面向对象的三大特征

面向对象的三大特征,第1张

面向对象三大特征之封装

封装是面向对象的核心特性
###将封装的属性进行隐藏
在属性名前加__前缀,就会实现实现一个对外隐藏属性
####特点

  1. 在类的外部无法直接访问隐藏属性; 知道了类名和属性名可以拼出名字_类名__属性名,然后就可以访问了;
    因此这种隐藏 *** 作并没有严格意义上的限制外部访问类的属性,只是一种语法意义上的变形 *** 作
  2. 这种隐藏对外部对内, __开头的属性在类的定义阶段统一发生变形;这种变形只在检查类体语法的时候发生
    class Foo:
    __x = 1 # _Foo__x
    def __f1(self):print(“在类的外部是无法访问到我的”) # _Foo__f1
    print(Foo.dict)
    ####隐藏数据属性
    #####为何隐藏
    为了不让外部使用者直接访问该属性
    #####如何使用
    在类内部定义接口,让使用者通过接口来访问隐藏属性,开发者可以在接口中定义任何逻辑
    class Person:
    def init(self, name, age, gender):
    self.__name = name
    self.__age = age
    self.__gender = gender定义接口访问隐藏属性 def get(self):
    print(“姓名: %s 年龄: %s 性别: %s” % (self.__name, self.__age, self.__gender))
    person1 = Person(“斯达舒”, 12, “female”)
    person1.get()
    ####隐藏函数属性
    #####为何隐藏
    目的是为了隔离复杂度,只在类内使用
    ###property
    将绑定给对象的方法伪造成一个数据属性
    ####案例1
    class Person:
    def init(self, name, height, weight):
    self.name = name
    self.height = height
    self.weight = weight
    @property
    def bmi(self):
    return self.weight / (self.height**2)
    person1 = Person(“漆仲勇”, 1.79, 75)
    print(person1.bmi)
    ####案例2
    class People:
    def init(self, name):
    self.__name = name
    @property
    def name(self):
    return self.__name
    @name.setter
    def name(self, val):
    if type(val) is not str:
    print(“必须传入字符串类型”)
    return
    self.__name = val
    @name.deleter
    def name(self):
    print(“不让删除”)
    people1 = People(“DJS”)
    print(people1.name)
    people1.name = “djs”
    print(people1.name)
    del people1.name
面向对象三大特征之继承
  1. 继承是一种创建新类的方式,新建的类可称为子类或派生类,父类可称为基类或超类,解决类与类之间代码冗余的问题
  2. python支持多继承,新建的类可以支持一个或多个父类
    优点:子类可以同时遗传多个父类的属性,极大限度大的重用代码
    缺点:降低代码的可读性和扩展性
  3. 新式类:继承了object类的子类,以及该子类的子类…
  4. 经典类:没有继承object类的子类,以及该子类的子类…
  5. 在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类
  6. 父类当中的属性会遗传给子类
    class Person1(object): # object类可有可无,当需要与python2兼容的时候可以有object类
    pass
    class Person2(object):
    pass
    单继承:
    class Male(Person1):
    pass
    多继承:
    class Female(Person1, Person2):
    pass
当出现代码冗余问题时,该如何解决

class Student:
school = “tins_hua”
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 = “tins_hua”
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)
解决方案
class TinsHuaPeople:
school = “tins_hua”
def init(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Student(TinsHuaPeople):
def choose_course(self):
print(“学生 %s 正在选课” % self.name)

student1 = Student(“李华”, 12, “男”)
student1.choose_course()
print(student1.school)
class Teacher(TinsHuaPeople):
def init(self, name, age, sex, salary, level):
TinsHuaPeople.init(self, name, age, sex)
self.salary = salary
self.level = level
def score(self):
print(“老师 %s 正在给学生打分” % self.name)
teacher1 = Teacher(“李华”, 22, “female”, 200000, 99)
print(teacher1.dict)
print(teacher1.school)

单继承背景下的属性查找

class Foo:
def f1(self):
print(“Foo.f1()”)
# 或者
def __f1(self):
print(“Foo.f1()”)
def f2(self):
print(“Foo.f2()”)
# self.f1()
# 调用当前类中的f1
Foo.f1()
# 调用当前类中的f1
self.__f1()

class Bar(Foo):
def f1(self):
print(“Bar.f1()”)
object1 = Bar()
object1.f2()
# 结果是: Foo.f2()
# Bar.f1()

继承的实现原理
  1. python多继承中的菱形问题(钻石问题)
    在python中,一个子类可以继承多个父类,但这可能会引发著名的菱形问题

          B          C
          
               D
D继承B和C, B和C继承于A; 如果A中有一个方法,B和C都重写了该方法,那么D继承的是那个版本的方法

# 菱形继承 class A(object): def test(self): print("from A") class B(A): def test(self): print("from B") class C(A): def test(self): print("from C") class D(B, C): pass obj = D() obj.test() # 结果是 from B

继承原理

对于开发者定义的每个类,python都会计算出一个方法解析顺序(MOR)列表,该MOR列表就是一个简单的所有基类的线性顺序表
print(D.mro())
[, , , , ]
类以及该类的对象访问属性都是参照该类的mro列表
python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性算法来实现的,它实际上就是合并所有父类的MRO列表。遵循以下三条准则:

  1. 子类会先于父类被检查
  2. 多个父类会根据他们在列表中的顺序倍被检查
  3. 如果对下一个类存在两个合法的选择,选择第一个父类
非菱形继承下,经典类与p新式类的属性查找顺序

如果多继承是非菱形继承,在新式类中python2与python3的属性查找顺序一样,都是一个分支一个分支的依次查找下去,最后查找object
class E:
def test(self):
print(“from E”)
class F:
def test(self):
print(“from F”)
class B(E):
def test(self):
print(“from B”)
class C(F):
def test(self):
print(“from C”)
class D:
def test(self):
print(“from D”)
class A(B, C, D):
def test(self):
print(“from A”)
pass
# 新式类
print(A.mro()) # [, , , , ,
# , ]

菱形继承下,经典类与新式类的属性查找顺序

在菱形继承下,那么经典类与新式类会有不同的MRO列表,分别对应属性的两种查找方式:广度优先和深度优先
当类是 经典类时,多继承情况下,在被查找的属性不存在时,会按照深度优先的方式查找下去(在检索第一条分支的时候就会检索公共父类)
class G:
def test(self):
print(“from G”)
class E(G):
def test(self):
print(“from E”)
class F(G):
def test(self):
print(“from F”)
class B(E):
def test(self):
print(“from B”)
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
查找顺序是:A -> B -> E -> G -> C -> F -> D
当类是 新式类时,多继承情况下,在被查找的属性不存在时,会按照广度优先的方式查找下去(在检索最后一条分支的时候查找公共父类)
class G(object):
def test(self):
print(“from G”)
class E(G):
def test(self):
print(“from E”)
class F(G):
def test(self):
print(“from F”)
class B(E):
def test(self):
print(“from B”)
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())
查找顺序是[, , , , , , , ]

多继承的正确打开方式:mixins机制
  1. 核心:在多继承背景下,尽可能地提升多继承的可读性
  2. 注意:使用Mixin类实现多重继承要非常小心
    (1)首先它必须表示某一种功能,而不是某个物品;python对于mixin类的命名一般以Mixin,able,ible为后缀
    (2)其次它必须责任单一,如果有多个功能,则写多个Mixin类
    (3)不依赖于子类的实现
    (4)如果子类没有继承这个Mixin类,也可以工作,只是缺少某个功能
    class Vehicle:
    pass
    class Flyable: # 子类混用某些功能的时候,在类名后加Mixin后缀,提示程序员这是一个混合的功能,不是子类的父类
    def fly(self):
    pass
    class CivilAircraft(Flyable, Vehicle):
    pass
    class Helicopter(Flyable, Vehicle):
    pass
    class Car(Vehicle):
    pass
在子类派生的新方法中使用父类的功能
  1. 指名道姓调用某一个类下的函数,不依赖于继承
    class TinsHuaPeople:
    school = “tins_hua”
    def init(self, name, age, sex):
    self.name = name
    self.age = age
    self.sex = sex
    class Teacher(TinsHuaPeople):
    def init(self, name, age, sex, salary, level):
    TinsHuaPeople.init(self, name, age, sex)
    self.salary = salary
    self.level = level
    def score(self):
    print(“老师 %s 正在给学生打分” % self.name)
    teacher1 = Teacher(“李华”, 22, “female”, 200000, 99)
    print(teacher1.dict)
    print(teacher1.school)
  2. supper调用父类提供给自己的方法,严格依赖于继承
    调用super()函数会得到一个特殊的对象,该对象会参照发起属性查找的那个类的mro列表,去查找要找的属性
    class TinsHuaPeople:
    school = “tins_hua”
    def init(self, name, age, sex):
    self.name = name
    self.age = age
    self.sex = sex
    class Teacher(TinsHuaPeople):
    def init(self, name, age, sex, salary, level):
    super().init(name, age, sex) # 调用的是方法,自动传参,不需要传入self参数
    self.salary = salary
    self.level = level
    def score(self):
    print(“老师 %s 正在给学生打分” % self.name)
    teacher1 = Teacher(“李华”, 22, “female”, 200000, 99)
    print(teacher1.dict)
    print(teacher1.school)
    super案例
    class A:
    def test(self):
    print(“from A”)
    super().test()
    class B:
    def test(self):
    print(“from B”)
    class C(A, B):
    pass
    obj = C()
    obj.test()
    # print(C.mro()) # [, , , ]
组合的概念

在一个类中以另外一个类的对象作为数据属性,称为类的组合。组合与继承都是用来解决代码的复用问题,不同的是,继承是一种的关系
比如教师是人,学生是人,当类之间有很多相同的属性时,应该用继承;
而组合是一种的关系,比如学生有姓名,班级,当类之间有显著不同,并且较小的类是较大类所需的组件时,应该使用组合

多态与鸭子类型
  1. 多态指的是同一种事物有多种形态
    # 动物的多种形态
    class Animal:
    pass
    class Monkey(Animal):
    pass
    class Pig(Animal):
    pass
    class People(Animal):
    pass
  2. 多态会带来什么样的特性
    多态性指的是可以在不考虑对象具体类型的情况下而直接使用对象
    class Animal:
    def say(self):
    print("动物基本的发声频率 “, end=” ")
    class Monkey(Animal):
    def say(self):
    super().say()
    print(“猴子的发声频率”)
    class Pig(Animal):
    def say(self):
    super().say()
    print(“猪的发声频率”)
    class People(Animal):
    def say(self):
    super().say()
    print(“人的发声频率”)
    obj1 = Monkey()
    obj2 = Pig()
    obj3 = People()
    # obj1.say() 结果:动物基本的发声频率 猴子的发声频率
    # obj2.say() 结果:动物基本的发声频率 猪的发声频率
    # obj3.say() 结果:动物基本的发声频率 人的发声频率
  3. 父类同一了所有子类的方法
    定义统一的接口,接收传入的动物对象
    def animal_say(animal):
    animal.say()
    animal_say(obj1)
    animal_say(obj2)
    animal_say(obj3)
    # 动物基本的发声频率 猴子的发声频率
    # 动物基本的发声频率 猪的发声频率
    # 动物基本的发声频率 人的发声频率
  4. python推崇的鸭子类型:不采用父类继承的方式实现多态,而是使多个类中有相似的方法,从而不考虑对象的类型而直接使用对象
    class Cpu:
    def read(self):
    print(“cpu read”)
    def write(self):
    print(“cpu write”)
    class Mem:
    def read(self):
    print(“mem read”)
    def write(self):
    print(“mem write”)
    class Txt:
    def read(self):
    print(“txt read”)
    def write(self):
    print(“txt write”)
    obj1 = Cpu()
    obj2 = Mem()
    obj3 = Txt()

obj1.read()
obj1.write()

obj2.read()
obj2.write()

obj3.read()
obj3.write()
结果:
cpu read
cpu write
mem read
mem write
txt read
txt write
5. 总结
综上可知,多态性的本质在于不同的类中定义有相同的方法名,这样就可以不考虑类而统一用一种方式去使用对象

	print("mem read")
def write(self):
	print("mem write")

class Txt:
def read(self):
print(“txt read”)
def write(self):
print(“txt write”)
obj1 = Cpu()
obj2 = Mem()
obj3 = Txt()

obj1.read()
obj1.write()

obj2.read()
obj2.write()

obj3.read()
obj3.write()
结果:
cpu read
cpu write
mem read
mem write
txt read
txt write
5. 总结
综上可知,多态性的本质在于不同的类中定义有相同的方法名,这样就可以不考虑类而统一用一种方式去使用对象

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/741553.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存