15.面向对象和super
面向对象和super()
类(Class): 具有相同的属性和方法的对象的集合,即定义对象的模板
对象(Object): 类的实例化对象,有自己的属性和方法。
类方法: 使用装饰器@classmethod ,传递类的属性和方法(不能传实例的属性和方法)
类属性: 类中的变量。类变量在整个实例化的对象中是公用的
实例方法: 传递对象的属性和方法
实例属性: 使用 self 调用
封装:对外部世界隐藏对象的工作细节
多态:对不同类的对象使用同样的操作
继承:即一个派生类(derived class)继承基类(base class)的字段和方法
class Person():
# #类属性
name="小明"
age=12
def __init__(self,id,email):
实例属性
self.id=id
self.email=email
实例方法
def run(self):
pass
xiaomi=Person(110,'110.com') # 对象实例化
xiaomi.colour='red' # 添加属性
print(Person.name) # 类引用
类对象支持两种操作:属性引用和实例化
class Circle(object): # 创建Circle类
def __init__(self, r): # 初始化一个属性r(不要忘记self参数,他是类下面所有方法必须的参数)
self.r = r # 表示给我们将要创建的实例赋予属性r赋值
self
和对象 指向了同一个内存地址,对对象的引用self
代表类的实例,而非类
实例属性用于区分不同的实例
类属性是每个实例的共有属性。
保留关键字对实例的操作
getattr(obj, name[, default]) : 访问对象的属性。
hasattr(obj,name) : 检查是否存在一个属性。
setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj, name) : 删除属性。
class Person():
def __init__(self, name,home):
self.name=name
self.home=home
print('我是Peson的__init__构造方法')
def address(self):
print("Name : ", self.name, ", address: ", self.home)
p1=Person("bei","BeiJing")
p1.address()
p1.age=18
p1.age=27
print(hasattr(p1, 'age')) # 如果存在 'age' 属性返回 True。
print(getattr(p1, 'age')) # 返回 'age' 属性的值
print(setattr(p1, 'age', 8)) # 添加属性 'age' 值为 8
print(delattr(p1, 'age')) # 删除属性 'age'
# 执行结果
我是Peson的__init__构造方法
Name : bei , address: BeiJing
True
27
None
None
hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。
getattr(emp1, 'age') # 返回 'age' 属性的值
setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
delattr(emp1, 'age') # 删除属性 'age'
内置属性类
__dict__
: 类的属性(包含一个字典,由类的数据属性组成)
__doc__
:类的文档字符串
__name__
: 类名
__module__
: 类定义所在的模块(类的全名是'main.className',如果类位于一个导入模块mymod中,那么className.module 等于 mymod)
__bases__
: 类的所有父类构成元素(包含了一个由所有父类组成的元组)
class Person():
def __init__(self, name,home):
self.name=name
self.home=home
print('我是Peson的__init__构造方法')
def address(self):
print("Name : ", self.name, ", address: ", self.home)
p1=Person("bei","BeiJing")
print ("Person.__doc__:", Person.__doc__)
print ("Person.__name__:", Person.__name__)
print ("Person.__module__:", Person.__module__)
print ("Person.__bases__:", Person.__bases__)
print ("Person.__dict__:", Person.__dict__)
# # ====================================================================
我是Peson的__init__构造方法
Person.__doc__: None
Person.__name__: Person
Person.__module__: __main__
Person.__bases__: (<class 'object'>,)
Person.__dict__: {'__module__': '__main__', '__init__': <function Person.__init__ at 0x000002619C7CD5E0>, 'address': <function Person.address at 0x000002619C8B3DC0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
私有属性和私有方法
__foo__
: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__()
之类的。
_foo
: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于
from module import *
__foo
: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问
私有属性包括 类属性和实例对象属性
私有方法包括 类方法和实例对象方法
双下划线
class Student():
name="zhangsan"
__age=12
def __init__(self):
__add="大红门"
pass
def __eat(self):
pass
pass
只能类的内部使用,不能在外部使用
1、不能被子类继承
2、不能实例调用
property
针对私有属性
property(get_day,set_day)
可以通过在类中定义__slots__变量来进行限定
# 限定Person对象只能绑定_name, _age和_gender属性
__slots__ = ('_name', '_age', '_gender')
super()
super() 是python 中调用父类(超类)的一种方法,在子类中可以通过super()方法来调用父类的方法。【超类: 是指 2层以上的继承关系,假如 C类继承B类,B类由继承A类,那么A类就是C类的超类】
通过super() 来调用父类的__init__ 构造方法
class Person():
def __init__(self, name):
print('我是Peson的__init__构造方法')
class Student(Person):
def __init__(self, name):
super(Student).__init__(name)
print('我是Student的__init__构造方法')
class Teacher(Student):
def __init__(self, name):
super(Teacher).__init__(name)
print('我是Teacher的__init__构造方法')
stu = Teacher(name="beike")
# 执行结果================================================================
我是Peson的__init__构造方法
我是Student的__init__构造方法
我是Teacher的__init__构造方法
通过supper() 来调用与子类同名的父类方法
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):
super(B, self).__init__()
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
1、super().add(m) 确实调用了父类 A 的 add 方法。
2、super().add(m) 调用父类方法 def add(self, m) 时, 此时父类中 self 并不是父类的实例而是子类的实例, 所以 b.add(2) 之后的结果是 5 而不是 4 。
多继承
针对 菱形继承
钻石继承还有一个问题是,比如若B和C中的m方法也同时调用了A中的m方法时:
class A:
def m(self):
print("m of A called")
class B(A):
def m(self):
print("m of B called")
A.m(self)
class C(A):
def m(self):
print("m of C called")
A.m(self)
class D(B,C):
def m(self):
print("m of D called")
B.m(self)
C.m(self)
# 此时我们调用d.m,A.m则会执行两次。
d=D()
d.m()
# 执行结果 ===============================================================
m of D called
m of B called
m of A called
m of C called
m of A called
在多继承中,会涉及到一个MRO(继承父类方法时的顺序表) 的调用排序问题。即严格按照MRO 顺序执行super方法
其实上面两个问题的根源都跟MRO有关,MRO(Method Resolution Order)也叫方法解析顺序,主要用于在多重继承时判断调的属性来自于哪个类,其使用了一种叫做C3的算法,其基本思想时在避免同一类被调用多次的前提下,使用广度优先和从左到右的原则去寻找需要的属性和方法。
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):
super(B, self).__init__()
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):
super(C, self).__init__()
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):
super(D, self).__init__()
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 0x000001DC8F4F9700> @D.add
self is <__main__.D object at 0x000001DC8F4F9700> @B.add
self is <__main__.D object at 0x000001DC8F4F9700> @C.add
self is <__main__.D object at 0x000001DC8F4F9700> @A.add
19
新式类继承顺序:D->B->C->A, 广度优先,从左到右。
事实上类中的_mro_属性(method resolution order)中定义了继承顺序,我们可以打印出来验证一下:
print(D.mro())
# 执行结果 ==========================================================================
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]