首页 > 其他 > 详细

第四十二篇 面对对象进阶

时间:2019-06-23 11:06:09      阅读:76      评论:0      收藏:0      [点我收藏+]

面对对象进阶

* 补充(数据类装饰器:复制类中的数据属性)

@dataclass只能在python3.7版本中使用

from dataclasses import dataclass 

@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0


# p = Point(1.5, 2.5)
# print(p)  # produces "Point(x=1.5, y=2.5, z=0.0)"
from dataclasses import dataclass

@dataclass
class zhuangbei:
    price: int
    aggrev: int
    life_value: int

bc = zhuangbei(9,100,10)
class duolandun(zhuangbei):
    pass
class BlackCleaver(zhuangbei):
    pass
# print(bc)
f = BlackCleaver(0,100,10)
print(f)  
'''
BlackCleaver(price=0,aggrev=100,life_value=10)
'''


# https://www.cnblogs.com/apocelipes/p/10284346.html

一、类的继承

1.什么是继承

1.继承是一种新建类的方式。新建的类称为子类,被继承的类称为父类

2.继承的特性:子类会继承父类所有的属性

3.继承其本质就是类与类之间的一种关系

class F_c:
    attri = '继承'
    def __init__(self,name):
        self.name = name
    def func(self):
        print('from 父类')

class S_c(F_c):
    pass

son = S_c('son')
print(son.attri)  # 继承数据属性(可自行更改)
print(son.name)   # 继承父类的属性,即可以使用父类中的自定义属性
son.func()      # 继承父类的函数属性,即可以调用父类中的函数
'''
继承
son
from 父类
'''

2.为什么用继承

可以避免重复代码,即减少代码的冗余

3.对象的继承

1.python中支持一个类同时继承多个父类

class Parent1:
    pass

class Parent2:
    pass

class Child(Parent1, Parent2):
    pass

**2.使用__bases__方法可以获取对象所继承的类**

print(child.__bases__)  # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
# 是一个元组,所以我们可以通过for循环打印
for i in child.__bases__:
    print(i)

4.继承与抽象

1.继承描述的是子类与父类之间的关系,要找出它们的关系,必须先抽象再继承。抽象:抽取类似或者说比较像的部分

2.抽象主要的作用是划分类别(可以隔离关注点,降低复杂度)

3.抽象只是分析和设计过程的一个动作,或者说是一种技巧,通过抽象,我们可以得到类

  • 1.抽象过程

技术分享图片

  • 2.抽象结果

技术分享图片

5.继承的应用

class SchoolPeople:
    school = 'XXschool'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        
class Student(SchoolPeople):
    def choose_course(self):
        print(f'{self.name} is choose course')
    
class Teacher(SchoolPeople):
    def mark(self, stu_obj, score):
        print('{self.name} is mark')
        stu_obj.grade = score  # 对象本质上可以看作是一个字典,所以可以直接添加(对象是可以点出属性的)

stud = Student('king',26,'male')
print(stud.__dict__)
teac = Teacher('teacher',27,'male')
print(teac.__dict__)

stud.choose_course()
teac.mark(stud,100) 
print(stud.__dict__)
print(teac.__dict__)

'''
{'name': 'king', 'age': 26, 'gender': 'male'}
{'name': 'teacher', 'age': 27, 'gender': 'male'}
king is choose course
teacher is mark
{'name': 'king', 'age': 26, 'gender': 'male', 'grade': 100}
{'name': 'teacher', 'age': 27, 'gender': 'male'}
'''

6.对象查找属性的顺序

对象自己 ----> 对象的类 ----> 父类 ----> 父类(如果存在多个父类).... ----> 爷爷类

class Foo:
    
    def f1(self):
        print('f1 of Foo ')
        
    def f2(self):
        print('f2 of Foo ')
        self.f1()   # 这里的self指的是实例化对象(千万不要看作是f2)
        
class Bar(Foo):
    
    def f1(self):
        print('f1 of Bar')

obj = Bar()  # 实例化一个对象

obj.f2()  # 对象查找属性的路径:对象自己--》对象的类--》父类...
'''
所以 obj.f2() 的结果为:
f2 of Foo
f1 of Bar
'''

二、类的派生

1.派生

派生:子类中定义新的属性的过程叫做派生。子类在使用派生的属性时,始终以自己的派生属性为准

2.派生方法

方法一:指名道姓访问某一个类中的函数,与继承无关(子类自己定义属性)

class SchoolPeople:
    school = 'XXschool'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        
class Teacher(SchoolPeople):
    def __init__(self,name,age,gender,level):
        SchoolPeople.__init__(self,name,age,gender)
        self.level = level
    def mark(self, stu_obj, score):
        print('{self.name} is mark')

teac = Teacher('king',26,'male',2)
print(teac.__dict__)
# {'name': 'king', 'age': 26, 'gender': 'male', 'level': 2}

方法二:

1.严格以继承属性来查找关系(可以参考菱形继承问题)

**2.利用super().__init__方法进行派生子类的新属性**

3.super()会得到一个特殊的对象,该对象就是专门用来访问分类中的属性的(按照继承关系来查找属性)

4.python2中的语法:super(自己的类名,self)。python3中的语法:super()

class SchoolPeople:
    school = 'XXschool'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        
class Teacher(SchoolPeople):
    def __init__(self,name,age,gender,level):
        super().__init__(self,name,age,gender)
        # python2语法:
        # super(Teacher,self).__init__(self,name,age,gender)
        self.level = level
        
    def mark(self, stu_obj, score):
        print('{self.name} is mark')

teac = Teacher('king',26,'male',2)
print(teac.__dict__) # {'name': 'king', 'age': 26, 'gender': 'male', 'level': 2}

三、类的组合

1.什么是组合

在一个类中以另外一个类的对象作为数据属性

2.为什么用组合

组合可以解决类与类之间代码冗余的问题

3.如何使用组合

class SchoolPeople:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    def login(self):
        print(f'{self.name}登陆')

class Student(SchoolPeople):
    def __init__(self, id, name, age, gender):
        self.id = id
        super(Student, self).__init__(name, age, gender)  # python2 语法
    def choose(self, course):
        print(f'{self.name}选择了{course.name}课程')

king = Student(1, 'king', 26, 'male')

class Teacher(SchoolPeople):
    def __init__(self, name, age, gender, level):
        super().__init__(name, age, gender)  # python3 语法
        self.level = level
    def scored(self, student, course, score):
        print(f'老师{self.name}给学生{student.name}的{course.name}课程打了{score}分')

nick = Teacher('nick',20,'male',1)
class Course:
    def __init__(self, name, price):
        self.name = name
        self.price = price

python = Course('python', 8888)

# 类的组合:将另一个类的对象当作这个类的数据属性
class Admin(SchoolPeople, Course):
    # 组合的应用
    def creat_course(self, name, price):
        res = Course(name, price)   # 通过类中的方法调用其他的类(生成一个实例对象)
        print(f'{self.name}创建了课程{res.name}')
        return res    # 返回被调用类运行的结果,这个结果就是一个实例对象

egon = Admin('egon', 20, 'male')
python = egon.creat_course('python', 20000)  # 相当于在类内部调用另一个类,同样可以实例化对象
print(python.price)

四、菱形继承问题

1.类的分类

1.1 新式类

1.继承了object的类以及该类的子类的类,都是新式类

2.python3中所有的类都是新式类

1.2 经典类

1.没有继承object的类以及该类的子类,都是经典类

2.只有python2中有经典类

2.菱形继承问题

1.1经典类:深度优先

技术分享图片

1.2新式类:广度优先

技术分享图片

3. C3算法与mro()方法

3.1 对于python中定义的每个类,python会计算出一个方法解析顺序列表(MRO),这个MRO列表就是一个简单的所有基类的线性顺序列表

3.2 通过mro()方法,我们可以得到新式类的寻找属性顺序

class A:
    pass

class B(A):
    pass

class C(A):
    pass
    
class D(A):
    pass
    
class E(D):
    pass
    
class F(C):
    pass
 
class G(B,E,F):
    pass

print(G.mro())
'''
[<class '__main__.G'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.D'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
'''

for i in G.mro():
    print(i)
'''
<class '__main__.G'>
<class '__main__.B'>
<class '__main__.E'>
<class '__main__.D'>
<class '__main__.F'>
<class '__main__.C'>
<class '__main__.A'>
<class 'object'>
'''   

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

  1. 子类会先于父类被检查
  2. 多个父类会根据它们在列表中的顺序被检查
  3. 如果对下一个类存在两个合法的选择,选择第一个父类

五、类的多态与多态性

1.多态:多种状态,只要大家能继承同一种东西A,这些东西就是A的多态
2.水:液态/固态/气态
3.动物:人/狗/猫

import abc

class Animal(metaclass=abc.ABCMeta):  # 不推荐使用
    def __init__(self, height, weight):
        self.height = height
        self.weight = weight

    @abc.abstractmethod
    def sleep(self):
        print('我在睡觉')
    
    @abc.abstractmethod
    def speak(self):
        print(self, '开始叫了')
    
    @abc.abstractmethod
    def eat(self):
        print(self, '开始吃了')


class People(Animal):
    def speak(self):
        print('开始叫了')

    def eat(self):
        print(self, '开始吃了')


class Dog(Animal):
    def speak(self):
        print('开始叫了')
    def eat(self):
        print(self, '开始吃了')


class Cow(Animal):
    def speak(self):
        print('开始叫了')
    def eat(self):
        print(self, '开始吃了')



class Foo(Animal):
    def speak(self):
        pass


f  = Foo(1,1)
f.sleep()



peo = People(180, 140)
dog = Dog(50, 100)
cow = Cow(100, 200)

# peo.speak()
# dog.speak()
# cow.speak()
# sheep.speak()
# mao.speak()

# peo.eat()
# dog.eat()

4.总结

4.1 鸭子类型:长得像鸭子,叫声也像鸭子,就是鸭子,(只要有speak和eat这两个方法,那他就是动物类)

4.2 对于我们这个例子:==你只要有speak方法/有eat方法,我无论你怎么定义这个类,你就是动物==的一种形态,你这样才能用动物的方法,否则无法使用动物的方法

5.多态性的好处(涉及到接口)

  1. 增加了程序的灵活性:以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
  2. 增加了程序额可扩展性:通过继承Animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
class Cat(Animal):  # 属于动物的另外一种形态:猫
    def talk(self):
        print('say miao')


def func(animal):  # 对于使用者来说,自己的代码根本无需改动
    animal.talk()


cat1 = Cat()  # 实例出一只猫
func(cat1)  # 甚至连调用方式也无需改变,就能调用猫的talk功能

Python本身就是多态,根本就不支持多态

class Animal():
    def eat(self):
        print('eat')

class People(Animal):
    def eat(self):
        print('人吃')
class Dog(Animal):
    def eat(self):
        print('??吃')
class Pig(Animal):
    def eat(self):
        print('??吃')
    def sleep(self):
        print('??睡')
class F(Animal):
    def eat(self):
        print('f吃')
f = F()

peo = People()
pig = Pig()
dog = Dog()

# 多态性
peo.eat()
pig.eat()
dog.eat()
f.eat()

class Cat(Animal):
    def eat(self):
        print('???吃')
cat = Cat()
cat.eat()

# 100种动物
print('*'*50)
# 多态性的使用,提供接口的概念
def func(obj):
    obj.eat()
    obj.run()
    obj.walk()
    obj.sleep()

func(cat)
# cat.eat()
# cat.walk()
# cat.run()
# cat.sleep()
func(dog)
# dog.eat()
# dog.walk()
# dog.run()
# dog.sleep()
func(peo)

取钱,插卡-》输入密码-》输入金额-》取到钱了

(插卡-》输入密码-》输入金额-》取到钱了)--》取钱函数

鸭子类型:只要长得像??,叫的像??,游泳也想??,你就是??

参考链接:http://www.cnblogs.com/nickchen121/

第四十二篇 面对对象进阶

原文:https://www.cnblogs.com/itboy-newking/p/11072034.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!