一, 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
案例一:
- class People:
- def __init__(self, name, weight, height):
- self.name = name
- self.weight = weight
- self.height = height
- # 定义函数的原因 1:
- # 1, 从 bmi 的公式上看, bmi 应该是触发功能计算得到的
- # 2,bmi 是随着身高, 体重的变化而动态变化的, 不是一个固定的值
- # 说白了, 每次都是需要临时计算得到的
- # 但是 bmi 听起来更像是一个数据属性, 而非功能
- @property
- def bmi(self):
- return self.weight / (self.height ** 2)
- obj1 = People('egon', 70, 1.83)
- print(obj1.bmi())
- obj1.height=1.86
- print(obj1.bmi())
- print(obj1.bmi)
案例二:
- class People:
- def __init__(self, name):
- self.__name = name
- def get_name(self):
- return self.__name
- def set_name(self, val):
- if type(val) is not str:
- print('必须传入 str 类型')
- return
- self.__name = val
- def del_name(self):
- print('不让删除')
- # del self.__name
- name=property(get_name,set_name,del_name)
- obj1=People('egon')
- # print(obj1.get_name())
- # obj1.set_name('EGON')
- # print(obj1.get_name())
- # obj1.del_name()
- # 人正常的思维逻辑
- print(obj1.name) #
- # obj1.name=18
- # del obj1.name
案例三:
- class People:
- def __init__(self, name):
- self.__name = name
- @property
- def name(self): # obj1.name
- return self.__name
- @name.setter
- def name(self, val): # obj1.name='EGON'
- if type(val) is not str:
- print('必须传入 str 类型')
- return
- self.__name = val
- @name.deleter
- def name(self): # del obj1.name
- print('不让删除')
- # del self.__name
- obj1=People('egon')
- # 人正常的思维逻辑
- print(obj1.name) #
- # obj1.name=18
- # del obj1.name
二, 继承
1, 什么是继承
I: 继承是一种创建新类的方式, 新建的类可称为子类或派生类, 父类又可称为基类或超类, 子类会遗传父类的属性
II: 需要注意的是: python 支持多继承
在 Python 中, 新建的类可以继承一个或多个父类
- class Parent1(object):
- x=1111
- class Parent2(object):
- pass
- class Sub1(Parent1): # 单继承
- pass
- class Sub2(Parent1,Parent2): # 多继承
- pass
- print(Sub1.__bases__)
- print(Sub2.__bases__)
- print(Sub1.x)
ps1: 在 python2 中有经典类与新式类之分
新式类: 继承了 object 类的子类, 以及该子类的子类子子类...
经典: 没有继承 object 类的子类, 以及该子类的子类子子类...
ps2: 在 python3 中没有继承任何类, 那么会默认继承 object 类, 所以 python3 中所有的类都是新式类
- print(Parent1.__bases__)
- print(Parent2.__bases__)
III:python 的多继承
优点: 子类可以同时遗传多个父类的属性, 最大限度地重用代码
缺点:
1, 违背人的思维习惯: 继承表达的是一种什么 "是" 什么的关系
2, 代码可读性会变差
3, 不建议使用多继承, 有可能会引发可恶的菱形问题, 扩展性变差,
如果真的涉及到一个子类不可避免地要重用多个父类的属性, 应该使用 Mixins
2, 为何要用继承: 用来解决类与类之间代码冗余问题
3, 如何实现继承
示范 1: 类与类之间存在冗余问题
- class Student:
- school='OLDBOY'
- def __init__(self,name,age,sex):
- self.name=name
- self.age=age
- self.sex=sex
- def choose_course(self):
- print('学生 %s 正在选课' %self.name)
- class Teacher:
- school='OLDBOY'
- def __init__(self,name,age,sex,salary,level):
- self.name=name
- self.age=age
- self.sex=sex
- self.salary=salary
- self.level=level
- def score(self):
- print('老师 %s 正在给学生打分' %self.name)
示范 2: 基于继承解决类与类之间的冗余问题
- class OldboyPeople:
- school = 'OLDBOY'
- def __init__(self, name, age, sex):
- self.name = name
- self.age = age
- self.sex = sex
- class Student(OldboyPeople):
- def choose_course(self):
- print('学生 %s 正在选课' % self.name)
- # stu_obj = Student('lili', 18, 'female')
- # print(stu_obj.__dict__)
- # print(stu_obj.school)
- # stu_obj.choose_course()
- class Teacher(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 = level
- def score(self):
- print('老师 %s 正在给学生打分' % self.name)
- tea_obj=Teacher('egon',18,'male',3000,10)
- # print(tea_obj.__dict__)
- # print(tea_obj.school)
- tea_obj.score()
三, 属性查找
单继承背景下的属性查找
示范一:
- class Foo:
- def f1(self):
- print('Foo.f1')
- def f2(self):
- print('Foo.f2')
- self.f1() # obj.f1()
- class Bar(Foo):
- def f1(self):
- print('Bar.f1')
- obj=Bar()
- obj.f2()
- # Foo.f2
- # Foo.f1
示范二:
- class Foo:
- def f1(self):
- print('Foo.f1')
- def f2(self):
- print('Foo.f2')
- Foo.f1(self) # 调用当前类中的 f1
- class Bar(Foo):
- def f1(self):
- print('Bar.f1')
- obj=Bar()
- obj.f2()
- # Foo.f2
- # Foo.f1
示范三:
- class Foo:
- def __f1(self): # _Foo__f1
- print('Foo.f1')
- def f2(self):
- print('Foo.f2')
- self.__f1() # self._Foo__f1,# 调用当前类中的 f1
- class Bar(Foo):
- def __f1(self): # _Bar__f1
- print('Bar.f1')
- obj=Bar()
- obj.f2()
- # Foo.f2
- # Foo.f1
四, 多继承带来的菱形问题
1, 菱形问题介绍与 MRO
- class A(object):
- # def test(self):
- # print('from A')
- ? pass
- class B(A):
- def test(self):
- print('from B')
- pass
- class C(A):
- # def test(self):
- # print('from C')
- pass
- class D(C,B):
- # def test(self):
- # print('from D')
- pass
- print(D.mro()) # 类 D 以及类 D 的对象访问属性都是参照该类的 mro 列表
- # obj = D()
- # obj.test()
- # print(D.test)
- # print(C.mro()) # 类 C 以及类 C 的对象访问属性都是参照该类的 mro 列表
- # c=C()
- # c.test()
总结: 类相关的属性查找 (类名. 属性, 该类的对象. 属性), 都是参照该类的 mro
2, 如果多继承是非菱形继承, 经典类与新式的属性查找顺序一样:
都是一个分支一个分支地找下去, 然后最后找 object
- class E:
- # def test(self):
- # print('from E')
- ? pass
- class F:
- def test(self):
- print('from F')
- class B(E):
- # def test(self):
- # print('from B')
- pass
- class C(F):
- # def test(self):
- # print('from C')
- pass
- class D:
- def test(self):
- print('from D')
- class A(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
3, 如果多继承是菱形继承, 经典类与新式类的属性查找顺序不一样:
经典类: 深度优先, 会在检索第一条分支的时候就直接一条道走到黑, 即会检索大脑袋 (共同的父类)
新式类: 广度优先, 会在检索最后一条分支的时候检索大脑袋
- class G: # 在 python2 中, 未继承 object 的类及其子类, 都是经典类
- # def test(self):
- # print('from G')
- ? pass
- class E(G):
- # def test(self):
- # print('from E')
- pass
- class F(G):
- def test(self):
- print('from F')
- class B(E):
- # def test(self):
- # print('from B')
- pass
- class C(F):
- def test(self):
- print('from C')
- class D(G):
- def test(self):
- print('from D')
- class A(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 机制: 在多继承的背景下满足继承的什么 "是" 什么的关系
来源: http://www.bubuko.com/infodetail-3500176.html