组合
在一个类中以另外一个类的对象作为数据属性,称为类的组合
1 class Role: 2 def __init__(self, name, hp, ad): 3 self.name = name 4 self.hp = hp 5 self.ad = ad 6 def attack(self): 7 pass 8 def wea(self,w): 9 self.w=w 10 11 class Weapon: 12 def __init__(self,name,ad): 13 self.name = name 14 self.ad = ad 15 def da(self,r1): 16 print("{}得到了{}".format(r1.name,self.name)) 17 r1=Role("亚瑟",1000,30) 18 w1=Weapon("大宝剑",50) 19 r1.wea(w1) 20 r1.w.da(r1)
组合的意义:
让类的对象与另一个类的对象产生关系,类与类产生关系。
继承
先抽象后继承
父类/超类/基类
子类/派生类
父类中所有的属性和方法都可以被子类使用
1 class Walkanimal: 2 def __init__(self,name): 3 self.name=name 4 def walk(self): 5 print("行走") 6 class Cat(Walkanimal): #Walkanimal的派生类 7 def catch_mouse(self): #派生方法 8 print("抓老鼠") 9 a=Cat("猫") 10 print(a.name) 11 a.walk()
当子类中有被调用的方法的时候,子类的对象直接选择子类中的方法,变量,父类中的方法不会被自动调用
如果我们既想执行子类的方法,也想执行父类的方法,那么要在子类中调用父类的方法
父类名.方法名()
super().方法名()
1 class A: 2 def func(self): 3 print("in A") 4 class B(A): 5 def func(self,): 6 print("in B") 7 A.func(self) 8 # b1=B() 9 # b1.func() # in B in A 10 11 12 class A: 13 def func(self): 14 print("in A") 15 class B(A): 16 def func(self,): 17 print("in B") 18 super().func() 19 b1=B() 20 b1.func() # in B in A 21 当用super时不用传入self
面试题
class Foo: def __init__(self): self.func() def func(self): print('in Foo') class Son(Foo): def func(self): print("in Son") s1=Son() #in Son class Foo: def __init__(self): self.func() def func(self): print('in Foo') class Son(Foo): pass s1=Son() #in Foo
当self去调用某个方法的时候,不要看self在哪个类里,要看self到底是谁
继承与重用:子类中可以用父类中的属性和方法
继承与派生:子类在父类的基础上又创建了自己需要的方法和属性
父类中有的属性和方法,子类没有 :子类对象直接调用就可以
父类中有,子类中也有:子类直接调用子类的
子类调用子类,同时调用父类 父类名.方法名()
1 class Foo: 2 country="china" 3 def func(self): 4 print(self.country) 5 class Son(Foo): 6 country="english" 7 s=Son() 8 s.func() #english
抽象类:抽象类是一个规范,它基本不会实现具体的功能,抽象类不能被实例化
from abc import ABCMeta,absttractmethod ,metaclass=ABCMeta
接口
多继承
新式类和经典类
python3中都是经典类
所有的新式类都有一个默认的父类:object
新式类搜索用的是广度优先算法,经典类用的是深度优先
新式类中采用mro和super
super不是单纯的找父类,而是遵循mro顺序
1 class A: 2 def func(self): 3 print("A") 4 class B(A): 5 def func(self): 6 super().func() 7 print("B") 8 class C(A): 9 def func(self): 10 super().func() 11 print("C") 12 class D(B,C): 13 def func(self): 14 super().func() 15 print("D") 16 d=D() 17 d.func() #ACBD
多态
一个类的多种形态,是通过继承实现
为什么要把多态单独列出来
1 class Animal: 2 pass 3 class Dog(Animal): 4 pass 5 class Cat(Animal): 6 pass
在java中,函数的参数需要注明数据类型,当有两个以上的参数的时候,就需要有一个父类来统一子类对象的数据类型
在python中,函数的参数不需要注明数据类型,所以不需要通过继承来统一子类的数据类型
在python中,都有一个默认的父类object,所以说python处处是多态
鸭子类型:不是通过继承来实现多态,而是通过模糊的概念来判断。print,len是通过模糊的概念来判断某个数据类型能不能作为函数的参数。
封装
广义上的封装:在实例化一个对象的时候,会产生一个空间来存储属性
只有这个类的对象可以使用定义在类的方法
狭义上的封装:隐藏类的属性和方法,仅提供接口
在类的外部不能使用私有变量
类的私有成员:
私有的静态属性,私有的对象属性,私有的方法
从变成规范的角度出发,我们不能在类的外部使用私有变量
1 class Goods: 2 __count=0.8 3 def __init__(self,price): 4 self.__price=price 5 def price(self): 6 return self.__price 7 g=Goods(10) 8 # print(g.__count) #报错,类的私有变量不能在外部使用 9 # print(g.__price) #报错 10 print(g.price()) #10
为什么要有私有变量?
1,我们不想让人看到这个值
2,我们不想让人修改这个值
3,修改这个值的时候有一些限制,保护数据的安全
4,有些方法和属性不希望子类继承
私有变量不能被子类继承
1 class Animal: 2 __name="animal" 3 class Dog(Animal): 4 pass 5 d=Dog() 6 print(d.__name) #报错
property 把方法伪装成属性
1 class Goods: 2 def __init__(self,name,price): 3 self.name=name 4 self.__price=price 5 @property 6 def price(self): 7 return self.__price 8 @price.setter 9 def price(self,new_price): 10 self.__price=new_price 11 return self.__price 12 a=Goods('apple',10) 13 print(a.price) #10 14 a.price=20 15 print(a.price) #20