目录
一、封装方法
1.如何封装
给方法名字前加上双下划线
2.封装方法的好处:
1.提高安全性
2.隔离复杂度(将复杂的内容隔离到内部,外部只留下简单的接口,对于使用者 难度降低)
class ATM:
def __insert_card(self):
print("插入银行卡...")
def __input_pwd(self):
print("输入密码...")
def __select_money(self):
print("选择取款金额...")
def withdraw(self):
self.__insert_card()
self.__input_pwd()
self.__select_money()
print("取款成功!...")
atm = ATM()
atm.withdraw() #外部调用这个简单的接口,就能完成一系列复杂的操作
#即隔离了复杂度,若不用封装也可以使用功能,但过程不安全(不输入密码可以取钱)
二、封装的实现原理
私有属性只有在内部才能被转换,且这个转换过程只转换一次,后续无法再转换
1.私有的属性和方法名称 前自动加上了_类名 python就是通过这样的转换方式来实现封装
2.只有在类的内部的双下划线下才会被自动转换,并且这个转换过程只执行一次,在类定义完后 后续添加的双下划线开头的名称是不会自动转换的
3.父类中私有的的方法 子类中无法使用
之所以无法覆盖 是因为子类和父类中的私有方法 名称必然不相同 所以无法覆盖 子类的方法一定子类独有的 因为名称不同
class Person:
def __init__(self,name,sex,age,idcard):
self.name = name
self.sex = sex
self.__age = age
self.__idcard = idcard
def get_idcard(self):
return self.__idcard
def __test(self):
pass
p = Person("比尔盖茨","男",20,"2321315555123152")
p.__idcard = "XXXX" #只是在 p 中创建了一个 __idcard,无法转换成私有属性
print(p.__dict__) #{'name': '比尔盖茨', 'sex': '男', '_Person__age': 20, '_Person__idcard': '2321315555123152'}
print(p.get_idcard())
print(Person.__dict__)
#在父类中定义的私有方法 不能被子类覆盖
class A:
def f(self):
self.__f1() #_A__f1
def __f1(self):
print("A __f1")
class B(A):
def __f1(self):
print("B __f1") #_B__f1
def f2(self):
self.f()
b = B()
b.f2()
三、property装饰器
1.为什么用property
当一些属性的值 不是固定的而是通过计算得来的时候 我们必须为这个属性增加方法才能完成计算
但是一旦使用方法后 该属性的访问就变成了方法的调用 很明显与其他的属性访问方式不同,这样给使用者造成迷
惑,所有需要将这个方法伪装成普通属性 这就用到了Property
2.property的作用
property可以将方法伪装成属性 利用这个特点 我们也可以将其使用到封装中
之前没有这个装饰器我们需要为私有的属性 提供两个方法 但是这样一来访问私有属性的方式就发生了变化
这时就可以使用property来进行伪装 使得访问私有属性与访问普通属性的方式一致
另外 property还提供了 setter(用于修改属性的值)和 deleter(删除属性的值)
# BIM案例:
class Person:
def __init__(self,name,weight,height):
self.name = name
self.weight = weight
self.height = height
# self.bmi = weight/(height*height)
# def bmi(self):
# return self.weight / (self.height * self.height)
@property
def bmi(self):
return self.weight / (self.height * self.height)
p = Person("尔晴",50,1.5)
# print(p.bmi)
# p.weight = 90
# print(p.bmi)
# 现在 虽然可以实现需求 但是我们把一个属性变成了一个行为 这是不合理的
# print(p.bmi())
# p.weight = 90
# print(p.bmi())
# 使用property装饰器 可以将一个方法伪装成一个属性
print(p.bmi)
p.height += 0.2
print(p.bmi)
class Student:
def __init__(self,name,sex,idCard):
self.name = name
self.sex = sex
self.__idCard = idCard
def get_idCard(self):
return self.__idCard
def set_idCard(self,new_id):
self.__idCard = new_id
@property # 需要掌握
def idCard(self):
return self.__idCard
@idCard.setter #了解的
def idCard(self,new_id):
self.__idCard = new_id
@idCard.deleter # 了解的
def idCard(self):
print("身份证属性被删除了.....")
del self.__idCard
stu = Student("尔康","男","323254554554")
# print(stu.get_idCard())
# stu.set_idCard("xxxx")
print(stu.get_idCard()) # 使用装饰器前
print(stu.name) # 普通属性的访问
print(stu.idCard) # 使用装饰器后
stu.idCard = "aaaaaaa" # 使用装饰器后的修改操作
print(stu.idCard)
del stu.idCard
print(stu.__dict__)
print(Student.__dict__)
四、多态
1.什么是多态
不同对象 可以相应同一种方法,并作出不同的行为,产生不同的结果
即:不同对象,使用同一种方法,产生不同的结果
2.如何实现多态
让几个不同类拥有相同父类,这样一来他们就具备了相同的方法,每个子类的要覆盖父类的方法,从而每个类的对象行为都不同
3.多态的基本形式
#定义一个基类(父类)
#在基类中定义方法
#在各个子类中定义相同的方法名,实现方法不同,覆盖父类方法
#定义一个实现函数
#将对象放进去
class Animal:
def eat(self):
print("动物在吃东西...")
def sleep(self):
print("动物在睡觉...")
def drink(self):
print("动物需要水.....")
class Person(Animal):
def eat(self):
print("人吃粮食...")
class Pig(Animal):
def eat(self):
print("猪吃饲料...")
class Dog(Animal):
def eat(self):
print("狗吃骨头...")
person = Person()
pig = Pig()
dog = Dog()
person.eat()
pig.eat()
dog.eat()
#假设你学习了C1驾照 意味着 所有C1类的汽车都能开 因为每种C1汽车的驾驶方式相同
# 当使用了多态之后 对象的使用者不需要关系这个对象具体的实现,只需要知道该对象属于哪个基类,就能直接使用它
# 如此扩展性变高了
class Phone:
def call(self):
print("手机就能打电话..")
def send_msg(self):
print("手机能发短信..")
class WindowsPhone(Phone):
def call(self):
print("拨号打电话..")
def send_msg(self):
print("输入号码发短信..")
class IPhone(Phone):
def call(self):
print("拨号打电话..")
def send_msg(self):
print("输入号码发短信..")
# 可以定义一个方法接受一个手机为参数 无论是是类型的手机 都可以被使用
def CALL(phone):
phone.call()
wp = WindowsPhone()
ipx = IPhone()
CALL(wp)
CALL(ipx)
# 系统内置的方法有很多都体现了多态
print(len("abc"))
print(len([1,2,3,4,]))
print(len({"name":"123","sex":"man"}))
print("abc".__len__())
print([1,2,3,4,].__len__())
print({"name":"123","sex":"man"}.__len__())
print(len({1,23,4,5}))
五、多态之ABC模块
用于规范化子类,即子类必须有和父类相同的方法名
多态是多个类的对象拥有相同的的方法,但是我们没有从严格要求说必须提供这些方法,子类完全可以不用提供这些方法,现在要做的就是 严格要求 子类必须实现父类声明的方法
abc:abstract class 抽象类的缩写 抽象的意思是 不清晰 不具体 看不懂
使用ABC模块来限制子类的步骤
1.为类中指定元类为abc.ABCMeta
2.在相应的方法上加上abc.abstractmethod装饰器
ABC的基本模式:
import abc
#定义基类,在基类名后加括号,指定元类为abc.ABCMeta
#在相应的方法上加上装饰器 @abc.abcstractmetod 用以规范后面的子类
class Person(metaclass = abc.ABCMeta):
@abc.abcstractmethod
def eat(self):
pass
...
import abc
# abstract class 是抽象类的缩写 抽象的意思是 不清晰 不具体 看不懂
#使用ABC模块来限制子类 的步骤
#1.为类中指定元类为abc.ABCMeta
#2.在相应的方法上加上abc.abstractmethod装饰器
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def eat(self):
pass
@abc.abstractmethod
def drink(self):
pass
class Cat(Animal):
def eat(self):
print("猫爱吃鱼肉...")
def drink(self):
print("用舌头舔..")
class Dog(Animal):
def eat(self):
print("狗爱吃骨头...")
def drink(self):
print("用舌头舔..")
class Pig(Animal):
def eat(self):
print("猪 爱吃草...")
def drink(self):
print("用嘴吸的..")
p = Pig()
# p.eat()
c = Cat()
# c.eat()
# 多态的好处 完全不需要考虑得到的对象时声明类型 只要知道了其基类中的内容就能使用
def feeding(animal):
animal.eat()
animal.drink()
feeding(c)
feeding(p)
# 多态中的基类 相当于(协议 标准 规范) 要求子类必须满足这些标准
练习题:
import abc
# 电脑基类
class Computer(metaclass=abc.ABCMeta):
@abc.abstractmethod
def open(self):
pass
@abc.abstractmethod
def shutdown(self):
pass
#
class DesktopComputer(Computer):
def open(self):
print("台式机正在启动....")
def shutdown(self):
print("台式机正在关机....")
class Worker:
def working(self,pc):
# 先开机
pc.open()
print("工作中.....")
pc.shutdown()
w1 = Worker()
dp = DesktopComputer()
w1.working(dp)
# 增加了笔记本电脑
class BookComputer(Computer):
def open(self):
print("笔记本正在启动....")
def shutdown(self):
print("笔记本正在关机....")
bc = BookComputer()
w1.working(bc)
class PadComputer(Computer):
def open(self):
print("平板正在启动....")
def shutdown(self):
print("平板正在关机....")
bc = PadComputer()
w1.working(bc)
六、鸭子类型
1.什么是鸭子类型
python推崇简单的编程方式
鸭子类型:如果一个对象叫声像鸭子,走路也像鸭子,那就把它当成鸭子
即:对象的行为一样,就是同一类型。
2.鸭子类型的实现
就是自觉地将所有的类的方法名字都写成一样,就可以实现多态
class Duck:
def bark(self):
print("鸭子嘎嘎叫...")
def run(self):
print("摇摇晃晃走....")
class Chicken:
def bark(self):
print("鸡咯咯叫...")
def run(self):
print("摇摇晃晃走....")
def test(obj):
obj.bark()
obj.run()
duck = Duck()
c = Chicken()
test(duck)
test(c)
# 如果你足够自觉 你可以不使用abc模块 也不需要基类 自觉地将方法名字都写成一样 同样可以实现多态
# 这种方式称之为鸭子类型