026--静态属性、类方法、静态方法、组合、继承
一、静态属性
class Room: tag=1 def __init__(self,name,owner,width,length,heigh): self.name=name self.owner=owner self.width=width self.length=length self.heigh=heigh @property def cal_area(self): # print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length)) return self.width * self.length
r1=Room('厕所','alex',100,100,100000)
print(r1.cal_area)
要点:@property + return 把公共函数变成数据属性,实例调用的调用的时候去掉小括号,像调用普通属性一样调用它。
二、类方法
class Room: tag=1 def __init__(self,name,owner,width,length,heigh): self.name=name self.owner=owner self.width=width self.length=length self.heigh=heigh @classmethod def tell_info(cls,x): print(cls) print('-->',cls.tag,x) r1=Room('厕所','alex',100,100,100000) Room.tell_info(10) #输出: <class '__main__.Room'> --> 1 10
要点:@classmethod 和 cls 专门供类使用的方法,类调用的时候不用传实例,也可以被实例调用(不建议这么做,本来就是划给类的方法,你还去调用它,四不是四傻)
三、静态方法
是一种普通函数,位于类定义的命名空间中,不会对任何实例类型进行操作,python为我们内置了函数staticmethod来把类中的函数定义成静态方法。
应用场景:编写类时需要采用很多不同的方式来创建实例,而我们只有一个__init__函数,此时静态方法就派上用场了。
class Room: tag=1 def __init__(self,name,owner,width,length,heigh): self.name=name self.owner=owner self.width=width self.length=length self.heigh=heigh @staticmethod def wash_body(a,b,c): print('%s %s %s正在洗澡' %(a,b,c)) Room.wash_body('alex','yuanhao','wupeiqi') print(Room.__dict__) r1=Room('厕所','alex',100,100,100000) print(r1.__dict__) r1.wash_body('alex','yuanhao','wupeiqi') #输出: alex yuanhao wupeiqi正在洗澡 { 'wash_body': <staticmethod object at 0x000000000261B438>, ..... } {'name': '厕所', 'owner': 'alex', 'width': 100, 'length': 100, 'heigh': 100000} alex yuanhao wupeiqi正在洗澡
class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day @staticmethod def now(): #用Date.now()的形式去产生实例,该实例用的是当前时间 t=time.localtime() #获取结构化的时间格式 return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回 @staticmethod def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间 t=time.localtime(time.time()+86400) return Date(t.tm_year,t.tm_mon,t.tm_mday) a=Date('1987',11,27) #自己定义时间 b=Date.now() #采用当前时间 c=Date.tomorrow() #采用明天的时间 print(a.year,a.month,a.day) print(b.year,b.month,b.day) print(c.year,c.month,c.day)
要点:@staticmethod 只是名义上归属类管理,不能调用类变量、实例变量,只是类的工具包。
四、组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合。
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系。
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。
class Trunk: pass class Head: pass class Person: def __init__(self,id_num,name): self.id_num=id_num self.name=name self.trunk=Trunk() self.head=Head() p1=Person('111111','alex') print(p1.name) print(p1.id_num) print(p1.__dict__) #输出: alex 111111 {'id_num': '111111', 'name': 'alex', 'trunk': <__main__.Trunk object at 0x000000000290B358>, 'head': <__main__.Head object at 0x000000000290B390>}
class School: def __init__(self,name,addr): self.name=name self.addr=addr def zhao_sheng(self): print('%s 正在招生' %self.name) class Course: def __init__(self,name,price,period,school): self.name=name self.price=price self.period=period self.school=school s1=School('oldboy','北京') s2=School('oldboy','南京') s3=School('oldboy','东京') c1=Course('linux',10,'1h','oldboy 北京') c2=Course('linux',10,'1h',s1)
要点:把s1当做参数传进去,可以不写死。
五、继承
继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类。
class Grandfather: pass class Father(Grandfather): #单继承 Father是派生类,grandfather 是基类 pass class son(Father,Grandfather): #多继承 pass
继承使用产生的场景:如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时我们不可能从头开始写一个类B,这就用到了类的继承的概念。通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用。
除了继承与派生的概念还有一个概念是需要提出的那就是:组合。组合就是指在一个类中以另外一个类的对象作为数据属性,成为类的组合。
组合与继承两者到底什么的关系?1.继承的方式:通过继承建立了派生类与基类的关系,两者之间是“是”的关系。当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师 2.组合的方式:用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程(当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好)
class School: def __init__(self,name,addr): self.name=name self.addr=addr def zhao_sheng(self): print('%s 正在招生' %self.name) class Course: def __init__(self,name,price,period,school): self.name=name self.price=price self.period=period self.school=school s1=School('北大','北京') c1=Course('linux',10,'1h',s1) print(c1.name) #linux print(c1.school) # <__main__.School object at 0x02182330> print(c1.school.name) # 北大 print(c1.school.addr) # 北京
在这个例子中呢,创建了两个类,一个是学校类一个是课程类。需要将课程类与学校类进行相关联的时候,继承在这里是不合适的,那我们采用组合的方式来对这两个类进行关联,这样就在实例化一门课程的时候把学校的信息进行关联。
子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
class Dad: '这个是爸爸类' money=10 def __init__(self,name): print('爸爸') self.name=name def hit_son(self): print('%s 正在打儿子' %self.name) class Son(Dad): money = 1000000000009 def __init__(self,name,age): self.name=name self.age=age def hit_son(self): print('来自儿子类')
接口继承(抽象类):
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 。
import abc class All_file(metaclass=abc.ABCMeta): @abc.abstractmethod def read(self): pass @abc.abstractmethod def write(self): pass class Disk(All_file): def read(self): print('disk read') def write(self): print('disk write') class Cdrom(All_file): def read(self): print('cdrom read') def write(self): print('cdrom write') class Mem(All_file): def read(self): print('mem read') def write(self): print('mem write') m1=Mem() m1.read() m1.write()
父类规定子类中必须实现的方法,但父类不实现(基类接口进行规范化子类)。
顺序继承:
class A: # def test(self): # print('A') pass class B(A): # def test(self): # print('B') pass class C(A): def test(self): print('C') # pass class D(B): # def test(self): # print('D') pass class E(C): def test(self): print('E') # pass class F(D,E): # def test(self): # print('F') pass f1=F() f1.test() #经典类:F->D->B->A-->E--> print(F.__mro__) #F-->D->B-->E--->C--->A新式类 #输出: E (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
继承的顺序:A为父类
新式类找的顺序:
在子类中调用父类的方法super():
class Vehicle1: Country='China' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print('开动啦') print('开动啦') class Subway(Vehicle1): def __init__(self,name,speed,load,power,line): # Vehicle.__init__(self,name,speed,load,power) super().__init__(name,speed,load,power) #super(__class__,self).__init__(name,speed,load,power) self.line=line def show_info(self): print(self.name,self.speed,self.load,self.power,self.line) def run(self): # Vehicle.run(self) super().run() print('%s %s 线,开动啦' %(self.name,self.line)) line13=Subway('北京地铁','10km/s',1000000000,'电',13) line13.show_info() line13.run() print(line13.__class__)
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)。
学习资料来源:海峰老师