文章目录
- 一、封装方法
- 二、封装的实现原理
- 三、property装饰器
- 四、多态
- 五、多态之ABC模块
- 六、鸭子类型
一、封装方法
- 如何封装方法:给方法名字前面加上双下划线
- 封装方法的好处:
- 提高安全性
- 隔离复杂度(将复杂的内容隔离到内部,外部只留下简单的接口,对于使用者而言,降低难度)
class A:
def __f1(self):
print("f1 run")
def run_f1(self):
self.__f1()
a = A()
a.run_f1()
# ATM的取款功能
#1.插入银行卡 2.输入密码 3.选择取款金额 4.取款
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()
二、封装的实现原理
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
print("aaaaaaaaaa")
p = Person("比尔盖茨","男",20,"322323232332332")
p.__idCard = 'xxxxxxx'
print(p.get_idCard())
print(p.__dict__) #{'name': '比尔盖茨', 'sex': '男', '_Person__age': 20, '_Person__idCard': '322323232332332', '__idCard': 'xxxxxxx'}
print(Person.__dict__)
p.__xxxxxxxxxxxx = 1
print(p.__dict__) #{'name': '比尔盖茨', 'sex': '男', '_Person__age': 20, '_Person__idCard': '322323232332332', '__idCard': 'xxxxxxx', '__xxxxxxxxxxxx': 1}
#通过__dict__ 可以发现
#1.私有的属性和方法名称前自动加上了_类名,python就是通过这样的转换方式来实现封装
#2.只有在类的内部的双下划线才会被自动转换,并且这个转换过程只执行一次
#3.父类中私有的方法,子类中无法使用
子类无法覆盖父类的私有方法:
class A:
def f(self):
self.__f1() #_A__f1
def __f1(self):
print("A __f1")
class B(A):
def __f1(self): # _B__f1
print("B __f1")
def f2(self):
self.f()
b = B()
b.f2()
#之所以无法覆盖是因为子类和父类中的私有方法名称不相同,所以无法覆盖,子类的方法一定子类独有的,因为名称不同
三、property装饰器
- 当一些属性的值,不是固定的而是通过计算得来的时候,我们必须为这个属性增加方法才能完成计算。但是一旦使用方法后,该属性的访问就变成了方法的调用,很明显与其他的属性访问方式不同,这样给使用者造成迷惑
- property可以将方法伪装成属性,利用这个特点我们也可以将其使用到封装中,之前没有这个装饰器我们需要为私有的属性 提供两个方法,但是这样一来方访问私有属性时的方式就发生了变化
这时候就可以使用property来进行伪装,使得访问私有属性与访问普通属性的方式一致 - 另外property还提供了setter(用于修改属性的值)和deleter(删除属性的值)
BIM案例:
class Person:
def __init__(self,name,weight,height):
self.name = name
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / (self.height * self.height)
p = Person("尔晴",50,1.5)
print(p.bmi)
p.height += 0.2
print(p.bmi)
#22.22222222222222
#17.301038062283737
练习:
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())
#使用装饰器后,普通属性的访问
print(stu.idCard)
#使用装饰器后,普通属性的修改操作
stu.idCard = "aaaaaaa"
print(stu.idCard)
#使用装饰器后,普通属性的删除操作
del stu.idCard
print(stu.__dict__) #{'name': '尔康', 'sex': '男', '_Student__idCard': 'aaaaaaa'}
print(Student.__dict__)
四、多态
- 什么是多态:生活中具备多种形态的事物 水(水蒸气、冰、液体水)一种事物具备多种形态或状态 就称之为多态。
官方解释:不同对象,可以使用同一方法,并作出不同的行为,产生不同的结果 - 如何实现多态:让几个不同类拥有相同父类,这样一来他们就具备了相同的方法,每个子类要覆盖父类的方法,从而每个类的对象行为都不同
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()
#人吃粮食...
#猪吃饲料...
#狗吃骨头...
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__())
五、多态之ABC模块
- 多态是多个类的对象拥有相同的方法,但是我们没有从严格要求说必须提供这些方法,子类完全可以不提供这些方法。在要做的就是严格要求子类必须实现父类声明的方法
- 多态的好处:完全不需要考虑得到的对象时声明类型,只要知道了其基类中的内容就能使用
- 使用ABC模块来限制字类的步骤:
- 为类中指定元类为abc.ABCMeta
- 在相应的方法上加上abc.abstractmethod装饰器
#abstract class 是抽象类的缩写
import abc
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("用舌头舔..")
cat = Cat()
dog = Dog()
#多态的好处:完全不需要考虑得到的对象时声明类型,只要知道了其基类中的内容就能使用
def feeding(animal):
animal.eat()
animal.drink()
feeding(cat)
feeding(dog)
#猫爱吃鱼肉...
#用舌头舔..
#狗爱吃骨头...
#用舌头舔..
练习:
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("平板正在关机....")
pc = PadComputer()
w1.working(pc)
六、鸭子类型
- python推崇简单的编程方式,鸭子类型:如果一个对象叫声像鸭子,走路也像鸭子,那就把它当成鸭子。
对应到代码中就是:只要你的行为一样,那就把你当成同一个类型来看待
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()
chicken = Chicken()
test(duck)
test(chicken)
#鸭子嘎嘎叫...
#摇摇晃晃走....
#鸡咯咯叫...
#摇摇晃晃走....
题:
"""
三个基础的宠物类 -- Cat类,Dog类,Pig类
属性:name(名字)、type(品种)
name、type均为私有属性(对内可见,对外不可见)
type属性为成员属性(由构造器__init__方法赋初值)
但type对外又是可读可写(利用property装饰器实现)
name属性初始化操作由父类完成(子类利用super()来实现)
方法:eat(self)
均拥有eat的方法(父级继承)
但实现体分别可以体现出 "吃猫粮"、"吃狗粮"、"吃猪粮"不同点(不同的实现)''==
一个宠物的父类 -- Pet类
属性:name(名字)
name为私有属性(对内可见,对外不可见)
name属性为成员属性(由构造器__init__方法赋初值)
但name对外又是可读可写(利用property装饰器实现)
方法:eat(self)
拥有eat的方法(没有方法的实现体,利用abc模块实现)
一个主人类 -- Master类
属性:name(名字)、pet(宠物)
name、pet均为私有成员属性(具体操作同上面属性的操作)
方法:feed(self)
拥有feed方法(方法只有self一个参数,没有多余的参数)
feed方法实现要求
-- "某某"主人准备好宠物粮食
-- "某某品种"的"某某宠物"来进食
-- 吃...(调用宠物自身的eat方法)
注:""括起来的某某都是要被替换为具体的数据的
创建三个宠物主人,分别养的是不同的三种宠物
三个主人进行喂食的时候,对应养的宠物就会完成进食
其他细节自由补充
"""
import abc
class Pet(metaclass=abc.ABCMeta):
def __init__(self,name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self,new_name):
self.__name = new_name
@abc.abstractmethod
def eat(self):
pass
class Cat(Pet):
def __init__(self,name,type):
# self.name = name
super().__init__(name) # 这是在调用父类的init方法
super().name = name # 这是在调用父类的name(new_name)
self.__type = type
@property
def type(self):
return self.__type
@type.setter
def type(self,new_type):
self.__type = new_type
def eat(self):
print("吃猫粮....")
class Pig(Pet):
def __init__(self,name,type):
# self.name = name
super().__init__(name)
self.__type = type
@property
def type(self):
return self.__type
@type.setter
def type(self,new_type):
self.__type = new_type
def eat(self):
print("吃猪粮....")
class Master:
def __init__(self,name,pet):
self.__name = name
self.__pet = pet
@property
def name(self):
return self.__name
@name.setter
def name(self,new_name):
self.__name = new_name
@property
def pet(self):
return self.__pet
@pet.setter
def pet(self, new_pet):
self.__name = new_pet
def feed(self):
print("""
-- "%s"主人准备好宠物粮食
-- "%s"的"%s"来进食
""" % (self.name,self.pet.type,self.pet.name))
self.__pet.eat()
pet = Pig("猪无能","猪")
m = Master("张三",pet)
m.feed()