python装饰器 子类继承_property装饰器_继承

property装饰器

一:装饰器

装饰器是在不修改被装饰对象源代码以及调用方式的前提下为被装饰对象添加

#新功能的可调用对象#print(property)

property是一个装饰器,是用来绑定给对象的方法伪造成一个数据属性

二:案例

"""成人的BMI数值:

过轻:低于18.5

正常:18.5-23.9

过重:24-27

肥胖:28-32

非常肥胖, 高于32

体质指数(BMI)=体重(kg)÷身高^2(m)

EX:70kg÷(1.75×1.75)=22.86"""

#案例1:

classPeople:def __init__(self, name, weight, height):

self.name=name

self.weight=weight

self.height=height#定义函数的原因1:

#1、从bmi的公式上看,bmi应该是触发功能计算得到的

#2、bmi是随着身高、体重的变化而动态变化的,不是一个固定的值

#说白了,每次都是需要临时计算得到的

#但是bmi听起来更像是一个数据属性,而非功能

@propertydefbmi(self):return self.weight / (self.height ** 2)

obj1= People('egon', 90, 1.50)#print(obj1.bmi())

obj1.height= 1.60

#print(obj1.bmi())

print(obj1.bmi)#输出:

35.15624999999999egon#案例2:

classPeople:def __init__(self, name):

self.__name =name#@property

defget_name(self):return self.__name

defset_name(self, val):if type(val) is notstr:print('必须传入str类型')returnself.__name =valdefdel_name(self):print('不让删除')#def self.__name

name11=property(get_name, set_name, del_name)

obj1= People('egon')#print(obj1.get_name())

print(obj1.get_name())

obj1.set_name('xxq')print(obj1.get_name())

obj1.del_name()#输出:

egon

xxq

不让删除

egon#案例三:

classPeople:def __init__(self, name):

self.__name =name

@propertydef name(self): #obj1.name

return self.__name@name.setterdef name(self, val): #obj1.name='EGON'

if type(val) is notstr:print('必须传入str类型')returnself.__name =val

@name.deleterdef name(self): #del obj1.name

print('不让删除')#del self.__name

obj1= People('egon')#人正常的思维逻辑

print(obj1.name) #

#obj1.name=18#del obj1.name

#输出:

egon

继承

一:什么是继承

I:继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类,子类会遗传父类的属性

II:需要注意的是:python支持多继承

在Python中,新建的类可以继承一个或多个父类

classParent1(object):

x= 1111

classParent2(object):pass

class Sub1(Parent1): #单继承

pass

class Sub2(Parent1,Parent2): #多继承

pass

print(Sub1.__bases__) #(,)

print(Sub2.__bases__) #(, )

print(Sub1.x) #1111

ps1: 在Python2中有经典类与新式类之分

新式类:继承了object类的子类,以及该子类的子类子子类。。。

经典:没有继承object类的子类,以及该子类的子类子子类。。。

ps2:在Python3中没有继承任何类,那么会默认继承object类,所以Python3中所有的类都是新式类

print(Parent1.__bases__) #(,)

print(Parent2.__bases__) #(,)

III:Python的多继承

#优点:子类可以同时遗传多个父类的属性,最大限度地重用代码

#缺点:

#1、违背人的思维习惯:继承表达的是一种什么"是"什么的关系

#2、代码可读性会变差

#3、不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差,

#如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins

二:为何要用继承

用来解决类与类之间代码冗余问题

三:如何实现继承

示范1:类与类之间存在冗余问题

classStudent:

school='OLDBOY'

def __init__(self, name, age, sex):

self.name=name

self.age=age

self.sex=sexdefchoose_course(self):print('学生%s 正在选课' %self.name)classTeacher:

school='OLDBOY'

def __init__(self, name, age, sex, salary, level):

self.name=name

self.age=age

self.sex=sex

self.salary=salary

self.level=leveldefscore(self):print('老师 %s 正在给学生打分' % self.name)

示范2:基于继承解决类与类之间的冗余问题

classOldboyPeople:

school= 'OldBoy'

def __init__(self, name, age, sex):

self.name=name

self.age=age

self.sex=sexclassStudent(OldboyPeople):defchoose_course(self):print('学生%s 正在选课' %self.name)

stu_obj= Student('lili', 18, 'female')#print(stu_obj.__dict__) # {'name': 'lili', 'age': 18, 'sex': 'female'}#print(stu_obj.school) # OldBoy#stu_obj.choose_course() # 学生lili 正在选课

classTeacher(OldboyPeople):#老师的空对象,'egon',18,'male',3000,10

def __init__(self, name, age, sex, salary, level):#指名道姓地跟父类OldboyPeople去要__init__

OldboyPeople.__init__(self, name, age, sex)

self.salary=salary

self.level=leveldefscore(self):print('老师 %s 正在给学生打分' %self.name)

tea_obj= Teacher('egon', 18, 'male', 3000, 10)#print(tea_obj.__dict__) # {'name': 'egon', 'age': 18, 'sex': 'male', 'salary': 3000, 'level': 10}#print(tea_obj.school) # OldBoy

tea_obj.score()#老师 egon 正在给学生打分

单继承背景下的属性查找

示范1:

classFoo:deff1(self):print('Foo.f1')deff2(self):print('Foo.f2')

self.f1()#obj.f1()

classBar(Foo):deff1(self):print('Bar.f1')

obj=Bar()

obj.f2()#预料的结果#Foo.f2#Foo.f1

#实际的结果#Foo.f2#Bar.f1

示范2:

classFoo:deff1(self):print('Foo.f1')deff2(self):print('Foo.f2')

Foo.f1(self)#调用当前类中的f1

classBar(Foo):deff1(self):print('Bar.f1')

obj=Bar()

obj.f2()#输出:#Foo.f2#Foo.f1

示范3:

classFoo:def __f1(self): #_Foo__f1

print('Foo.f1')deff2(self):print('Foo.f2')

self.__f1() #self._Foo__f1,# 调用当前类中的f1

classBar(Foo):def __f1(self): #_Bar__f1

print('Bar.f1')

obj=Bar()

obj.f2()#Foo.f2#Foo.f1

多继承带来的菱形问题

一:菱形问题

大多数面向对象语言都不支持多继承,而在Python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的 Diamond problem菱形问题(或称钻石问题,有时候也被称为“死亡钻石”),菱形其实就是对下面这种继承结构的形象比喻。

classA(object):deftest(self):print('from A')pass

classB(A):deftest(self):print('from B')pass

classC(A):deftest(self):print('from C')pass

classD(C, B):#def test(self):

#print('from D')

pass

#print(D.mro()) # 类D以及类D的对象访问属性都是参照该类的mro列表#输出:[, , , , ]

obj=D()

obj.test()#from C

print(D.test) #

print(C.mro()) #类C以及类C的对象访问属性都是参照该类的mro列表#输出:[, , ]

c=C()

c.test()#from C

总结:类相关的属性查找(类名.属性,该类的对象.属性),都是参照该类的mro

python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。 而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1.子类会先于父类被检查

2.多个父类会根据它们在列表中的顺序被检查

3.如果对下一个类存在两个合法的选择,选择第一个父类

二:如果多继承是非菱形继承,经典类与新式的属性查找顺序一样:

都是一个分支一个分支地找下去,然后最后找object

classE:#def test(self):

#print('from E')

pass

classF:deftest(self):print('from F')classB(E):#def test(self):

#print('from B')

pass

classC(F):#def test(self):

#print('from C')

pass

classD:deftest(self):print('from D')classA(B, C, D):#def test(self):

#print('from A')

pass

#新式类#print(A.mro()) # A->B->E->C->F->D->object

obj=A()

obj.test()#结果为:from F

三:如果多继承是菱形继承,经典类与新式类的属性查找顺序不一样:

经典类:深度优先,会在检索第一条分支的时候就直接一条道走到黑,即会检索大脑袋(共同的父类)

新式类:广度优先,会在检索最后一条分支的时候检索大脑袋

class G: #在python2中,未继承object的类及其子类,都是经典类

#def test(self):

#print('from G')

pass

classE(G):#def test(self):

#print('from E')

pass

classF(G):deftest(self):print('from F')classB(E):#def test(self):

#print('from B')

pass

classC(F):deftest(self):print('from C')classD(G):deftest(self):print('from D')classA(B, C, D):#def test(self):

#print('from A')

pass

#新式类#print(A.mro()) # A->B->E->C->F->D->G->object

#经典类:A->B->E->G->C->F->D

obj =A()

obj.test()#

四:总结:

多继承到底要不用???

要用,但是规避几点问题

1.继承结构尽量不要过于复杂

2.推荐使用mixins机制:在多继承的背景下满足继承的什么"是"什么的关系

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中,继承父类的`__init__()`方法有两种常用的方式。第一种方式是使用`super().__init__()`来继承父类的`__init__()`方法,同时也可以使用`super()`继承其他方法。这种方式适用于单继承和多继承的情况。 第二种方式是使用`父类.父类方法(self, 参数)`的方式来继承父类的`__init__()`方法。这种方式在多继承的情况下会有明显的差异[2]。在多继承的情况下,使用`super(子类, self).__init__()`会按照方法解析顺序(MRO)调用父类的方法,而使用`父类.父类方法(self, 参数)`会按照定义顺序依次调用父类的方法。 举个例子来说明。假设有以下类的继承关系: ```python class A: def __init__(self): print("[开始 访问A") print("[结束 访问A") class B(A): def __init__(self): print("[开始 访问B") A.__init__(self) print("[结束 访问B") class C(A): def __init__(self): print("[开始 访问C") A.__init__(self) print("[结束 访问C") class D(A): def __init__(self): print("[开始 访问D") A.__init__(self) print("[结束 访问D") class E(B, C, D): def __init__(self): print("[开始 访问E") B.__init__(self) C.__init__(self) D.__init__(self) print("[结束 访问E") # 实例化类E e = E() ``` 使用第一种方式`super(子类, self).__init__()`,输出结果为: ``` 访问E 访问B 访问C 访问D 访问A 访问A 访问D 访问C 访问B 访问E ``` 而使用第二种方式`父类.父类方法(self, 参数)`,输出结果为: ``` 访问E 访问B 访问C 访问D 访问A 访问A 访问D 访问C 访问B 访问E ``` 可以看出,使用第一种方式时,方法的调用顺序按照MRO从左到右的顺序进行;而使用第二种方式时,方法的调用顺序按照定义顺序从左到右依次进行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值