多态和属性自省(六)
一、面向对象三大特征:封装,继承,多态
多态:指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同子类的对象调用相同的方法,产生不同的执行结果,多态可以提高代码的灵活度
继承:在python中,一个类可以继承一个类,也可以继承多个类,被继承的类叫父类(或者叫基类,base class),继承的类叫子类
封装:将数据和方法放在一个类中就构成了封装
class Animal(object): def func(self): print('动物类的func方法') class Cat(Animal): '''猫类''' def func(self): print('这是猫类特性相关方法') class Dog(Animal): '''狗类''' def func(self): print('这是狗类相关方法') def func(ani_obj): ani_obj.func() if __name__ == '__main__': a1 = Animal() c1 = Cat() d1 = Dog() print(isinstance(a1, Animal)) print(isinstance(c1, Animal)) print(isinstance(d1, Animal)) func(a1) func(c1) func(d1)
注意:在python中的参数没有类型限制,所以多态在python中的提现不是很严谨,多态的概念是应用在在Java,c#这一类强类型语言中,而python崇尚鸭子类型。
二、鸭子类型
概念:它并不要求严格的继承体系,关注的不是对象类型本身,而是它如何使用的,一个对象只要‘看起来像鸭子,走路起来像鸭子’,那它就可以被看作是鸭子。
鸭子类型提现:
静态语言:对于静态语言(java,c#)来讲,上面传入的对象必须是base类型或它的子类,否则将无法调用func()方法。
动态语言:对于动态语言python来讲,上面传入的不一定是base类型,也可以是其他类型,只要内部实现一个func()方法就行,这就是鸭子类型的提现。
class Animal(object): def func(self): print('动物类的func方法') class Cat(Animal): '''猫类''' def func(self): print('这是猫类特性相关方法') class Dog(Animal): '''狗类''' def func(self): print('这是狗类相关方法') class Hero(object): def func(self): print('这是hero相关方法') def func(ani_obj): ani_obj.func() if __name__ == '__main__': a1 = Animal() c1 = Cat() d1 = Dog() h1 = Hero() print(isinstance(a1, Animal)) print(isinstance(c1, Animal)) print(isinstance(d1, Animal)) print(isinstance(h1, Animal)) func(a1) func(c1) func(d1) func(h1)
Hero不是Animal类型,但是可以调用func()方法,就是鸭子类型。
多态的意义:开放封闭原则
1、对于一个变量,我们只需知道它是base类型,无需确切地知道它的子类型,就可以放心的调用func()方法(调用方法只管地套用,不管细节)
2、当需要新增功能,只需新增一个base的子类实现func()方法,就可以再原来的基础上进行功能扩展,这就是注明的‘开放封闭’原则
3、对扩展开放:允许新增base子类
4、对修改封闭:不需要修改依赖base类型的func()等
三、数据和自省
私有属性:以单下划线或者双下划线开头的被称之为私有属性
私有属性定义:
单下划线开头:_attr
双下划线开头:__attr
class MyClass(object): attr = 100 #公有属性 _attr1 = 1000 #私有属性,在外部可以直接访问 __attr1 = 10000 #私有属性,在外部不可以直接访问,被改名了,所以在外部访问不了,但是_MyClas__attr1 t = MyClass() #查看该类所有的属性和方法 print(t.__dict__)
python私有属性并没有真正私有化,但可以用下划线得到伪私有,有一项大多数python代码都遵循的习惯:带有下划线,前缀的名称应视为非公开的API的一部分(无论是函数,方法还是数据成员),它被视为实现细节,如有更改恕不通知。
__dict__
类调用__dict__属性,返类属性和方法字典
实例调用__dict__属性,返回实例相关的属性和方法字典
class MyClass(object): attr = 100 #公有属性 _attr1 = 1000 #私有属性,在外部可以直接访问 __attr1 = 10000 #私有属性,在外部不可以直接访问,被改名了,所以在外部访问不了,但是_MyClas__attr1 print(MyClass._attr1) print(MyClass._MyClass__attr1) t = MyClass() #查看该类所有的属性和方法 print(t.__dict__)#实例相关属性和方法 print(MyClass.__dict__)#类相关属性和方法字典
__slots__:通过定义slots属性来限制实例对象属性,只能绑定slots指定的属性。不能添加slots之外的属性
class Hero(object): __slots__ = [] pass h = Hero() print(h.__dict__)
执行结果:报错,此时的__dict__没有创建,被slots覆盖了

自定义属性访问机制:
内置函数:
setattr:设置属性
getattr:获取属性值
delattr:删除属性值
class Hero(object): def __init__(self, name): self.name = name h = Hero('sinder') h.gender = 'bouns' setattr(h, 'age', 18) print(getattr(h, 'age')) del h.gender delattr(h, 'gender') print(h.__dict__)
__setattr__:
lass Hero(object): def __init__(self, name): self.name = name def __setattr__(self, key, value): '''给对象设置属性时会调用此方法''' print('正在设置属性key:{},value:{}'.format(key, value)) object.__setattr__(self, key, value) # 重写__setattr__,一定要去调用父类的__setattr__方法 h = Hero('sinder') setattr(h, 'age', 18)
执行结果:增加属性

__delattr__:
class Hero(object): def __init__(self, name): self.name = name def __delattr__(self, item): print(F'这个是item:{item}') object.__delattr__(self, item)
h = Hero('sinder')
setattr(h, 'age', 18)
print('删除前,实例属性:', h.__dict__)
delattr(h, 'age')
print('删除后,实例属性:', h.__dict__)
执行结果:

__

浙公网安备 33010602011771号