码迷,mamicode.com
首页 > 其他好文 > 详细

面向对象的三大属性

时间:2018-04-13 21:22:02      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:watch   根据   魔术方法   深度   2.x   closed   代码   tac   pen   

一:继承

1,面向对象中的继承表示的是类与类之间的关系(什么是什么的关系),在python3中,所有的类都会默认继承object类,继承了object类的所有类都是新式类,如果一个类没有继承任何父类,那么__bases__属性就会显示<class ‘object‘>。

2,继承可以分为单继承和多继承。

技术分享图片
# 单继承
class Parent:pass
class Son(Parent):pass   # 继承关系
# Son继承了Parent
print(Son.__bases__)  # 内置的属性
print(Parent.__bases__)  # 内置的属性


# 多继承
class Parent1:pass
class Parent2(Parent1):pass
class Parent3:pass
class Son(Parent2,Parent3):pass   # 继承关系
print(Parent2.__bases__)
print(Son.__bases__)
View Code

3,对象使用名字的顺序: 先找对象自己内存空间中的,再找对象自己类中的,再找父类中的。

技术分享图片
class Animal:
    role = Animal
    def __init__(self,name,hp,ad):
        self.name = name     # 对象属性 属性
        self.hp = hp         #血量
        self.ad = ad         #攻击力
    def eat(self):
        print(%s吃药回血了%self.name)

class Person(Animal):
    r = Person
    def attack(self,dog):   # 派生方法
        print("%s攻击了%s"%(self.name,dog.name))

    def eat2(self):
        print(执行了Person类的eat方法)
        self.money = 100
        self.money -= 10
        self.hp += 10

class Dog(Animal):
    def bite(self,person):  # 派生方法
        print("%s咬了%s" % (self.name, person.name))

# 继承中的init
alex = Person(alex,10,5)
print(Person.role)
print(alex.__dict__)
dog = Dog(teddy,100,20)
print(dog.__dict__)

# 继承中的派生方法
alex = Person(alex,10,5)
dog = Dog(teddy,100,20)
alex.attack(dog)
dog.bite(alex)

# 继承父类的方法:自己没有同名方法
alex = Person(alex,10,5)
dog = Dog(teddy,100,20)
alex.eat2()
alex.eat()
dog.eat()
View Code
技术分享图片
# class Animal:
#     def __init__(self,name,sex,kind):
#         self.name = name
#         self.sex = sex
#         self.kind = kind
#     def eat(self):
#         print(‘%s is eating‘%self.name)
#
#     def drink(self):
#         print(‘%s is drinking‘%self.name)
#
# class Cat(Animal):
#     def climb(self):
#         print(‘%s is climbing‘%self.name)
#
# class Dog(Animal):
#     def watch_door(self):
#         print(‘%s is watching door‘%self.name)

# 1.确认自己没有init方法
# 2.看看有没有父类
# 3.发现父类Animal有init
# 4.看着父类的init方法来传参数
#tom = Cat(‘tom‘,‘公‘,‘招财猫‘)   # 实例化对象
# tom.eat = ‘猫粮‘
# print(Cat.__dict__)   # Cat.__dict__ Cat类的命名空间中的所有名字
# print(tom.__dict__)   # tom.__dict__ 对象的命名空间中的所有名字
# tom.eat()   # 先找自己对象的内存空间 再找类的空间 再找父类的空间
# tom.climb()   # 先找自己的内存空间 再找类的空间
View Code

4,self.名字的时候,不要看self当前在哪个类里,要看这个self到底是谁的对象

技术分享图片
class Parent:
    def func(self):
        print(in parent func)
    def __init__(self):
        self.func()

class Son(Parent):
    def func(self):
        print(in son func)

s = Son()
View Code

 5,object 类

技术分享图片
class A:
#     ‘‘‘
#     这是一个类
#     ‘‘‘
    pass

a = A()
print(A.__dict__)  # 双下方法 魔术方法
# 创建一个空对象
# 调用init方法    —— 调用了么? 调用了
# 将初始化之后的对象返回调用处
View Code

6,在单继承中,如何给一个类的对象增加派生属性呢?

详见如下代码:

技术分享图片
class Animal:
    def __init__(self,name,hp,ad):
        self.name = name     # 对象属性 属性
        self.hp = hp         #血量
        self.ad = ad         #攻击力
    def eat(self):
        print(eating in Animal)
        self.hp += 20

class Person(Animal):
    def __init__(self,name,hp,ad,sex):
        # Animal.__init__(self,name,hp,ad)
        #次为方法一
        # super(Person,self).__init__(name,hp,ad)
        #此为方法二
        super().__init__(name, hp, ad)
        #此为方法二简写(常用)
        # 在单继承中,super负责找到当前类所在的父类,在这个时候不需要再手动传self
        self.sex = sex      # 这个就是增加的派生属性
        self.money = 100
    def attack(self,dog):   # 派生方法
        print("%s攻击了%s"%(self.name,dog.name))
    def eat(self):                         # 重写
        super().eat()  # 在类内 使用 super()方法找父类的方法
        print(eating in Person)
        self.money -= 50

class Dog(Animal):
    def __init__(self,name,hp,ad,kind):
        Animal.__init__(self,name,hp,ad)
        self.kind = kind    # 派生属性
    def bite(self,person):  # 派生方法
        print("%s咬了%s" % (self.name, person.name))


alex = Person("zhangsan",100,10,"male")   # 实例化
#print(alex.__dict__)
# tg = Dog(‘到哥‘,100,50,‘藏獒‘)
# print(tg.__dict__)
# 父类有eat 子类没有
# alex.eat() # 找父类的
# 子类有eat 不管父类中有没有
# alex.eat() # 找子类的
# 当子类中有,但是我想要调父类的
# Animal.eat(alex)          #指名道姓
# super(Person,alex).eat()  # super(子类名,子类对象)方法   —— 一般不用
# 子类父类都有eat方法,我想执行父类的eat和子类的eat
#alex.eat()  # 执行子类的eat
View Code

7,多继承之钻石继承

对于多继承中的新式类,寻找名字的顺应该遵循广度优先。类名.mro() 可以查询广度优先的遍历顺序。

例如下面的程序:

技术分享图片
class A:
    def func(self):
        print(A)
class B(A):
    pass
    # def func(self):
    #     print(‘B‘)
class C(A):
    pass
    # def func(self):
    #     print(‘C‘)
class D(B):
    pass
    # def func(self):
    #     print(‘D‘)
class E(B,C):
    pass
    # def func(self):
    #     print(‘E‘)
class F(D,E):
    pass
    # def func(self):
    #     print(‘F‘)
f = F()
f.func()
print(F.mro())  # 查看广度优先的遍历顺序,其遍历顺序为 F-D-E-B-C-A
View Code

【附】:pyrhon3 中的新式类遵循的广度优先算法图示

技术分享图片

技术分享图片

技术分享图片

8,当遇到多继承和super时,应遵循以下的情况:

(1)找到这个对象对应的类。

(2)将这个类的所有父类都找到画成一个图

(3)根据图写出广度优先的顺序

(4)再看代码,看代码的时候要根据广度优先顺序图来找对应的super

例如以下程序:

技术分享图片
class A:
    def func(self):
        print(A)
class B(A):
    def func(self):
        super().func()
        print(B)
class C(A):
    def func(self):
        super().func()
        print(C)
class D(B,C):
    def func(self):
        super().func()
        print(D)
d = D()
d.func()     #结果为 A-C-B-D
View Code

该程序分析过程如下:

技术分享图片

【注】:supper(),在单继承中就是单纯的寻找父类,在多继承中就是根据子节点所在图的 mro 顺序找寻下一个类。

9,python 2中的经典类的多继承问题

【注】:经典类只在 python2 版本才存在,且必须不继承object。它在遍历的时候遵循深度优先算法,而且没有mro方法和super()方法。在python2 的版本中,必须手动继承object 类,才是新式类。它在遍历的时候遵循广度优先算法,在新式类中,有mro方法和super()方法,但是在2.X版本的解释器中,必须传参数(子类名,子类对象)。

【附】:python2 中的经典类中遵循的深度优先算法图示

技术分享图片

 

面向对象的三大属性

标签:watch   根据   魔术方法   深度   2.x   closed   代码   tac   pen   

原文地址:https://www.cnblogs.com/leiwei123/p/8809196.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!