20 面向对象三大特性

继承

是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,或者又可以称为基类或者超类,新建的类称为派生类或子类。
继承分为单继承和多继承

class A:    #父类(基类或者超类)
    pass
class B:	#父类
	pass
class A_son(A,B):     #子类(派生类)
    pass

一个类可以被多个类继承,且可以继承多个父类(仅仅在python中)。

print(A_son.__bases__)

__bases__可以查看父类。在Python3 中所有的类,都有父类,没有声明继承父类的类,都默认继承object类。

继承与抽象

继承是基于抽象的结果,通过编程语言去实现它,肯定是先经理抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧。通过抽象,才能得到类。

面试题

class Animal:
    def __init__(self):
        print('执行Animal.__init__')
        self.func()
    def eat(self):
        print('%s eating'%self.name)
    def drink(self):
        print('%s drinking'%self.name)
    def func(self):
        print('Animal.func')

class Dog(Animal):
    def guard(self):
        print('guarding')
    def func(self):
        print('Dog.func')
dog = Dog()

输出:
在这里插入图片描述
可以看到,当子类中有相应的方法的时候,会优先调用自己的方法。当自己没有这个方法的时候,会在父类中找,找到之后,调用父类中的方法。

派生
派生属性

父类中没有的属性,在子类中出现,叫做派生属性。

class Animal():
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp
class Dog(Animal):
    def __init__(self,name,aggr,hp,kind):
        Animal.__init__(self,name,aggr,hp)  #self也要传过来。
        self.kind = kind    #派生属性
    def bite(self,person):
        person.hp -= self.aggr

class Person(Animal):
    def __init__(self,name,aggr,hp,sex):
        Animal.__init__(self,name,aggr,hp)
        self.sex = sex  #派生属性
        self.money = 0  #派生属性
派生方法

父类中没有的方法,在子类中出现,叫做派生方法。

class Animal():
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp
class Dog(Animal):
    def __init__(self,name,aggr,hp,kind):
        Animal.__init__(self,name,aggr,hp)  #self也要传过来。
        self.kind = kind    #派生属性
    def bite(self,person):  #派生方法
        person.hp -= self.aggr

如果在子类中还要用到父类中的方法,需要单独调用父类的方法:

  • 父类名.方法名 需要自己传self参数,或者 super().方法名 不需要自己传self
class Animal:
    def __init__(self, name, aggr, hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

    def eat(self):
        print('吃东西')
        self.hp += 100


class Dog(Animal):
    def __init__(self, name, aggr, hp, kind):
        super().__init__(name, aggr, hp)  # 只在新式类中有,python3中所有类都是新式类
        self.kind = kind  # 派生属性

    def eat(self):
        print('大黄吃粑粑')


huang = Dog('大黄', 200, 500, 'tugou')
print(huang.name)
huang.eat()
super(Dog, jin).eat() #不仅可以在方法中调用,还可以在函数外调用。方法是super(父类,实例化名称).方法()

输出:
在这里插入图片描述

class A:
    def func(self):
        print('A')
class B:
    def func(self):
        print('B')
class C:
    def func(self):
        print('C')
class D(A,B,C):
    pass
    # def func(self):
        # print('D')
        # pass
d = D()
d.func()

输出:
在这里插入图片描述
当多继承的时候,如果子类中没有该方法,就从离他最近的父类中找,就如上述代码中的A
下面是更复杂的一种:

class A:
    def func(self):
        print('A')
class B(A):
    # def func(self):
    #     print('B')
    pass
class C:
    def func(self):
        print('C')
    # pass
class D(C):
    # def func(self):
    #     print('D')
    pass
class E(B,D):
    # def func(self):
    #     print('E')
    pass

e = E()
e.func()

输出:
在这里插入图片描述

class A:
    def func(self):
        print('A')
class B(A):
    # def func(self):
    #     print('B')
    pass
class C(A):
    # def func(self):
    #     print('C')
    pass
class D(B):
    # def func(self):
    #     print('D')
    pass
class E(C):
    # def func(self):
    #     print('E')
    pass
class F(D,E):
    # def func(self):
    #     print('F')
    pass

F = F()
F.func()

继承顺序:


在这里插入图片描述

print(类名.mro())方法可以把继承顺序显示出来。

所以,在新式类中的继承顺序为“广度优先”。
Python2.7中,新式类和经典类共存,新式类要继承object类。
Python3 中,只有新式类,默认继承object
经典类中,进行深度优先
在新式类中,进行广度优先。
经典类和新式类,,mro()方法只有新式类中才有,super()只在Python3中使用。

super

super()的本质不是单纯的找父类,而是根据调用者的节点位置的广度优先顺序来。

class A(object):
    def func(self):
        print('A')
class B(A):
    def func(self):
        super().func()
        print('B')
    # pass
class C(A):
    def func(self):
        super().func()
        print('C')
    # pass
class D(B):
    def func(self):
        super().func()
        print('D')
    # pass
class E(C):
    def func(self):
        super().func()
        print('E')
    # pass
class F(D,E):
    def func(self):
        super().func()
        print('F')
    # pass

F = F()
F.func()

输出:
在这里插入图片描述

多态

一类事物有多种状态。做一件事情根据实际情况开设计实际的方法。
Python天生支持多态。
在其他语言中,我们需要通过如下的代码实现多态。(下面的例子在别的语言中可能出错,没有按规范写)

class Payment:
	pass;
class Alipay(Payment):
	def pay(self,money):
		print('已经用支付宝支付了%s元' % money)
class Applepay():
	def pay(self,money):
		print('已经用applepay支付了%s元' % money)
def pay(Payment pay_obj,int money):
	pay_obj.pay(money)
pay()

然而在Python代码中,我们可以直接通过如下代码:

class Alipay():
    def pay(self, money):
        print('已经用alipay支付了%s元' % money)


class Applepay():
    def pay(self, money):
        print('已经用applepay支付了%s元' % money)


def pay(pay_obj, money):  # 统一支付入口  归一化设计
    pay_obj.pay(money)


ap = Applepay()
ali = Alipay()
pay(ap, 13)
pay(ali, 13)

Python语言不崇尚根据继承所得来的相似。例如ListTuple这两个类型的数据,两者的很多方法是一样的,但不是通过继承的方式来约束其相似的方法,而是自己实现自己的代码。
这种实现方法的方式称为“鸭子类型”。那么也就是说,如果两个类刚好相似,并不是一个父类的子类的兄弟关系,那么就是鸭子类型。这种编程方式的优点是松耦合,每个相似的类之间都没有影响。

封装

广义上面向对象的封装:代码的保护,面向对象的思想本身就是一种封装,之让用实例化的对象来操作类中属性或者方法。
狭义上面向对象的封装:将属性和方法都藏起来,不让你看见。

class Person:
    def __init__(self,name,passwd):
        self.name = name
        self.__passwd = passwd   # 私有属性

    def get_pwd(self):
        return self.__passwd

alex = Person('zhangsan','1234')
print(alex.get_pwd())
print(alex.__passwd)

输出:
在这里插入图片描述
私有属性不可以通过实例化名称.属性的方式得到值。

带有私有属性、方法的代码:

class Person:
    __key = 123  # 私有静态属性
    def __init__(self,name,passwd):
        self.name = name
        self.__passwd = passwd   # 私有属性

    def __get_pwd(self):         # 私有方法
        return self.__passwd   #只要在类的内部使用私有属性,就会自动的带上_类名

    def login(self):          # 正常的方法调用私有的方法
        self.__get_pwd()

alex = Person('zhangsan','1234')
print(alex._Person__passwd)   # _类名__属性名
print(alex.get_pwd())

输出:
在这里插入图片描述
当定义了私有属性的时候,可以通过_类名__属性名的方式调用私有属性,但不赞成这样去使用。私有方法的调用跟私有属性的规则相似,不能通过实例化名称.方法的方式得到值。

类中定义方法和属性的时候,在前面加上__(双下划线),会变成私有的方法或者属性。

所有的私有方法或属性,都不能再类的外部使用,且只能在类的内部声明。如果在外部声明一个私有类,则可以在外部使用,即在外部声明的类似与私有属性相似的属性,不是私有属性。

class Person:
    __key = 123  # 私有静态属性
    def __init__(self,name,passwd):
        self.name = name
        self.__passwd = passwd   # 私有属性

    def __get_pwd(self):         # 私有方法
        return self.__passwd   #只要在类的内部使用私有属性,就会自动的带上_类名

    def login(self):          # 正常的方法调用私有的方法
        self.__get_pwd()

alex = Person('zhangsan','1234')
alex.__weight = 130
print(alex.__weight)

输出:
在这里插入图片描述
在上述代码中说定义的alex.__weight = 130并不是一个私有属性。

在Python类中声明的属性,相比于其他语言声明的属性访问限制如下表。Python中没有protect类型的数据。

python其他
self.属性public
self.__属性private

访问修饰符public、private、protect、default范围:

同一个类中同一个包不同包的子类不同包且非子类
private
protect
public

private:一般称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
protect:介于public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、属性以及方法只能被类本身的方法     及子类访问,即使子类在不同的包中也可以访问。
public:访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值