私有属性
python中不存在真正意义上的私有属性,只是逻辑意义上的私有.
-
单下划线开头属性
定义属性和方法是私有的,不应该在类外进行访问,但是不代表无法访问.class A: def __init__(self): self._a = 11 a = A() print(a._a) a._a = 22 print(a._a) ==> 输出 11 22
正确的访问方式应该是:将私有属性隐藏起来,暴露其他属性
class A: def __init__(self): self._a = 11 @property def a(self): return self._a a = A() print(a.a) ==> 输出 11
-
双下划线开头属性
防止子类重写父类方法
__method方法/属性在python内部会被转化,因为两个_method不是一个方法,因此不会被重写.
==>
class A中 -> _A__method
class B中 -> _B__methodclass A(object): def __method(self): print("I'm a method in class A") def method_x(self): print("I'm another method in class A\n") def method(self): self.__method() # 注意:此处已经被定义为_A__method,因此class B调用的时候,其实调的是_A__method self.method_x() class B(A): def __method(self): print("I'm a method in class B") def method_x(self): print("I'm another method in class B\n") if __name__ == '__main__': a = A() a.method() b = B() b.method() print(A.__dict__) print(B.__dict__) ==> 输出 I'm a method in class A I'm another method in class A I'm a method in class A # 此处没有重写父类__method方法 I'm another method in class B {'_A__method': <function A.__method at 0x0000017F875DE048>, 'method_x': <function A.method_x at 0x0000017F875DE0D0>, 'method': <function A.method at 0x0000017F875DE158>} {'_B__method': <function B.__method at 0x0000017F875DE1E0>, 'method_x': <function B.method_x at 0x0000017F875DE268>}
-
开头结尾下划线
python内置方法
继承、封装、多态(接口、协议)
-
封装
封装行为具体实现,对外提供接口,减少了操作的复杂性.
体现在类实例化,每个实例都拥有不同的命名空间,都是不同的对象实体. -
继承
抽象共同的特征,继承父类,避免重复代码开发工作.
-
多态
一种事务有多种形态,比如 动物有猫、狗、猪
重写父类的方法,实现每个实例具有不同的行为,实现多态. — 具有类型依赖关系,比如animal类的行为,被person类调用肯定不行.鸭子类型:
动态语言特性:不依赖类型,取决于行为. 比如 看起来像,叫起来像鸭子的就是鸭子.
比如:序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系.
在比如:只要实现了__iter__和__next__方法的就是迭代器,不需要考虑继承父类实现. -
接口、协议
python中接口通过抽象基类实现,定义一系列的抽象方法,通过继承在子类中实现. 抽象基类保证了一致性.协议:协议是非正式的接口,不施加强制性约束.
python中有很多协议,比如迭代器协议. 得益于"鸭子类型." 多态的另一种很灵活的实现形式.python中使用isinstance来判断传入参数的类型是不提倡的,更pythonic的方法是直接使用传入的参数,通过try,except来处理传入参数不符合要求的情况.
property特性
如果我们直接把属性暴露出去,可能会被随意修改,不符合程序的数据类型,造成代码格式混乱.
通过property特性:
1.代码内部setter进行参数类型检测等工作.
2.简化调用,将函数调用简化为属性调用(不能传参)
class A:
def __init__(self):
self._a = 11
@property
def a(self):
return self._a
@a.setter
def a(self,value):
...
super
-
单继承
单继承中 super 主要用来调用父类方法
class A: def __init__(self): self.n = 2 def add(self, m): print('self is {0} @A.add'.format(self)) self.n += m class B(A): def __init__(self): self.n = 3 def add(self, m): print('self is {0} @B.add'.format(self)) super().add(m) self.n += 3 ==> b = B() b.add(2) print(b.n) 结果: self is <__main__.B object at 0x106c49b38> @B.add self is <__main__.B object at 0x106c49b38> @A.add 8
-
多重继承
python3中class.mro()即可查看方法解析顺序class A: def __init__(self): self.n = 2 def add(self, m): print('self is {0} @A.add'.format(self)) self.n += m class B(A): def __init__(self): self.n = 3 def add(self, m): print('self is {0} @B.add'.format(self)) super().add(m) self.n += 3 class C(A): def __init__(self): self.n = 4 def add(self, m): print('self is {0} @C.add'.format(self)) super().add(m) self.n += 4 class D(B, C): def __init__(self): self.n = 5 def add(self, m): print('self is {0} @D.add'.format(self)) super().add(m) self.n += 5 ==> 执行 d = D() d.add(2) print(d.n) 结果 self is <__main__.D object at 0x10ce10e48> @D.add self is <__main__.D object at 0x10ce10e48> @B.add self is <__main__.D object at 0x10ce10e48> @A.add 15
打包和解包
详看下面例子
class A:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def func1(**kwargs):
"""打包"""
"""**作用: 收集关键字参数传递给一个字典,并将这个字典赋值给变量kwargs"""
print(kwargs)
def func2(name,age,sex):
"""解包"""
"""**作用:将k/v形式字典解包,成单独的关键字参数"""
print(name, age, sex)
# class解包
dic = {'name':'kxc','age':25,'sex':'male'}
a = A(**dic)
print(a.__dict__) # {'name': 'kxc', 'age': 25, 'sex': 'male'}
# def解包
func2(**dic) # kxc 25 male
# def打包
func1(name='kxc',age=25,sex='female') # {'name': 'kxc', 'age': 25, 'sex': 'female'}
反射机制
字符串的事件驱动模型. 利用字符串去动态导入模块、函数、实例等.
hasattr() getattr() setattr() 三个函数实现