封装,顾名思义,就是将某些东西给封装起来,之后想要使用的时候再去调用。python
因此,在使用面向对象的封装特性时须要:① 将内容封装到某处 ② 调用时从某处取出来算法
封装分为两部分:函数
咱们先看广义上的封装:3d
将内容封装到某处code
class MyClass: def __init__(self, name, age): self.name = name self.age = age # 在实例化对象时,会自动执行__init__方法,将对象空间传递给self这个位置参数 obj = MyClass("oldniu", 20) # 将"oldniu" 和 20 分别封装到obj(self)的name和age属性中
从某处调用封装的内容对象
调用被封装的内容时,有两种方式:① 经过对象直接调用 ② 经过self间接调用blog
经过对象直接调用继承
class MyClass: def __init__(self, name, age): self.name = name self.age = age obj = MyClass("oldniu", 20) print(obj.name) # 经过obj对象直接调用里面的name属性 print(obj.age) # 经过obj对象直接调用里面的age属性
经过self间接调用ip
class MyClass: def __init__(self, name, age): self.name = name self.age = age def func(self): print(self.name) # 使用self间接调用obj对象中的name属性 print(self.age) # 使用self间接调用obj对象中的age属性 obj = MyClass("oldniu", 20) obj.func() # 对象执行方法时Python会默认将obj传给参数self
综上所述,对于面向对象广义上的封装来讲,其实就是使用初始化方法将内容封装到 对象 中,而后经过对象直接或者self间接获取被封装的内容。开发
咱们再看狭义上的封装
私有静态属性
class MyClass: __gender = "男" # 私有静态属性 def __init__(self, name, age): self.name = name self.age = age def get_gender(self): return self.__gender # 在类的内部能够访问私有静态属性 # print(MyClass.__gender) # 类名不能直接访问私有静态属性 obj = MyClass("oldniu", 20) # print(obj.__gneder) # 对象不能访问私有静态属性 print(obj.get_gender()) # 男
对于私有静态字段来讲,只能在本类中内部访问,类的外部,子类均不可访问。
tips:其实在类的外部能够经过使用_MyClass__gender访问私有静态属性,可是通常咱们不会去使用。
私有方法
class MyClass: def __init__(self, name, age): self.name = name self.age = age def __func(self): print("666666") def func(self): self.__func() 类内部访问静态方法 obj = MyClass("dogfa", 20) obj.func() # 私有方法和私有静态字段同样,只能在本类中内部访问,类的外部和子类均不课访问。
什么是继承?⼦类能够⾃动拥有⽗类中除了私有属性外的其余全部内容就是继承。
咱们先来看单继承
类名,对象执行父类方法
# 定义一个Animal父类 class Animal: type_name = "动物类" def __init__(self, name): self.name = name def eat(self): print("吃吃吃...") # 继承于Animal类 class Dog(Animal): pass # 类名调用父类的属性和方法 print(Dog.type_name) Dog.eat(111) # 对象调用父类的属性和方法 dog = Dog("二哈") # 调用父类的__init__方法实例化对象 print(dog.name) print(dog.type_name) dog.eat() print(dog.__dict__)
执行顺序
同时执行类及父类方法
方法一:
若是想执行父类的func方法,这个方法而且子类中夜用,那么就在子类的方法中写上:
父类.func(对象,其余参数)
class Animal: type_name = "动物类" def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender def eat(self): print("吃吃吃...") class Bird(Animal): def __init__(self, name, age, gender, wing): Animal.__init__(self, name, age, gender) # 执行了父类的__init__方法进行初始化 self.wing = wing # 给对象封装wing属性 obj = Bird("鹦鹉", 3, "雌", "翅膀") print(obj.__dict__) # {'name': '鹦鹉', 'age': 3, 'gender': '雌', 'wing': '翅膀'}
方法二:
利用super,super().func(参数)
class Animal: type_name = "动物类" def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender def eat(self): print("吃吃吃...") class Bird(Animal): def __init__(self, name, age, gender, wing): super().__init__(name, age, gender) # 使用super会自动将self传给父类 self.wing = wing # 给对象封装wing属性 obj = Bird("鹦鹉", 3, "雌", "翅膀") print(obj.__dict__) # {'name': '鹦鹉', 'age': 3, 'gender': '雌', 'wing': '翅膀'}
再来看看多继承
在多继承中要补充一点,在这里要注意类的种类。类能够分为经典类和新式类。
新式类:继承object类的类称为新式类。在Python3中默认都是继承object类,因此默认全部类都是新式类。
经典类:不继承object类的类称为经典类。在Python2中默认使用经典类,固然也能够本身手动继承object类来达到变成经典类的目的。
经典类的多继承
在Python的继承体系中, 咱们能够把类与类继承关系化成⼀个树形结构的图。
class A: pass class B(A): pass class C(A): pass class D(B, C): pass class E: pass class F(D, E): pass class G(F, D): pass class H: pass class Foo(H, G): pass
对付这种mro画图就能够:
继承关系图已经有了,那如何进⾏查找呢? 记住⼀个原则, 在经典类中采⽤的是深度优先遍历⽅案。 什么是深度优先,就是⼀条路走到头, 而后再回来, 继续找下⼀个。
类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C
新式类的继承
mro序列
MRO是一个有序列表L,在类被建立时就计算出来。
通用计算公式为:
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] ) (其中Child继承自Base1, Base2)
若是继承至一个基类:class B(A)
这时B的mro序列为
mro( B ) = mro( B(A) ) = [B] + merge( mro(A) + [A] ) = [B] + merge( [A] + [A] ) = [B,A]
若是继承至多个基类:class B(A1, A2, A3 …)
这时B的mro序列
mro(B) = mro( B(A1, A2, A3 …) ) = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] ) = ...
计算结果为列表,列表中至少有一个元素即类本身,如上述示例[A1,A2,A3]。merge操做是C3算法的核心。
表头和表位
表头:
列表的第一个元素
表尾:
列表中表头之外的元素集合(能够为空)
示例
列表:[A, B, C]
表头是A,表尾是B和C
列表之间的+操做
+操做:
[A] + [B] = [A, B]
(如下的计算中默认省略)
---------------------
merge操做示例:
如计算merge( [E,O], [C,E,F,O], [C] ) 有三个列表 : ① ② ③ 1 merge不为空,取出第一个列表列表①的表头E,进行判断 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,于是跳过当前当前列表 2 取出列表②的表头C,进行判断 C不在各个列表的集合中,于是将C拿出到merge外,并从全部表头删除 merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) 3 进行下一次新的merge操做 ...... ---------------------
计算mro(A)方式:
mro(A) = mro( A(B,C) ) 原式= [A] + merge( mro(B),mro(C),[B,C] ) mro(B) = mro( B(D,E) ) = [B] + merge( mro(D), mro(E), [D,E] ) # 多继承 = [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O] = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D = [B,D,E] + merge([O] , [O]) = [B,D,E,O] mro(C) = mro( C(E,F) ) = [C] + merge( mro(E), mro(F), [E,F] ) = [C] + merge( [E,O] , [F,O] , [E,F] ) = [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除 = [C,E,F] + merge([O] , [O]) = [C,E,F,O] 原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C]) = [A,B] + merge( [D,E,O], [C,E,F,O], [C]) = [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E = [A,B,D,C] + merge([E,O], [E,F,O]) = [A,B,D,C,E] + merge([O], [F,O]) # 跳过O = [A,B,D,C,E,F] + merge([O], [O]) = [A,B,D,C,E,F,O] ---------------------
多态:同一个对象,多种形态。
因为Python是弱类型语言, 在定义变量和传参的时候能够是任意形态的值,因此Python默认支持多态。
鸭子类型:你看起来像鸭子,那就是鸭子。
对相同的功能设定了相同的名字,这样方便开发,这两个方法就能够互成为鸭子类型。好比list、tuple、str都有index()方法,这就是互称为鸭子类型。