私有属性 / 方法

在实际开发中,一个对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到,这就叫 私有属性 / 私有方法

在定义属性或方法时,在属性名或者方法名前增加 两个下划线,定义的就是私有属性或方法

class Women:

    def __init__(self, name):

        self.name = name
        # 不要问女生的年龄
        self.__age = 18

    def __secret(self):
        print("我的年龄是 %d" % self.__age)

    def secret(self):
        print("我的年龄是 %d" % self.__age)

xiaofang = Women("小芳")

# print(xiaofang.__age)
# xiaofang.__secret()
xiaofang.secret()

AttributeError: 'Women' object has no attribute '__age'
AttributeError: 'Women' object has no attribute '__secret'
我的年龄是 18

实际上,是因为在 属性 / 方法名 前面增加了两个下划线 __,使得 Python 解释器进行了特殊处理,才会无法访问私有属性 / 方法。
所以只要知道 Python 解释器是怎样处理的,就可以访问私有属性 / 方法:

print(xiaofang._Women__age)

18


单继承

面向对象三大特性:封装继承多态

  • 封装 根据职责将属性和方法封装到一个抽象的类中
  • 继承 可以实现代码的重用
  • 多态 是指不同的对象调用相同的方法,将产生不同的结果

单继承

class Animal:
    def eat(self):
        print("吃")

    def drink(self):
        print("喝")

    def run(self):
        print("跑")

    def sleep(self):
        print("睡")

不使用继承定义 Dog 类:

class Dog:
    def eat(self):
        print("吃")

    def drink(self):
        print("喝")

    def run(self):
        print("跑")

    def sleep(self):
        print("睡")

    def bark(self):
        print("汪汪叫")

这种方式弊端很多,比如

  • 代码重复,冗余
  • 比如 Animal 中的 eat 方法修改时,Dog 中的 eat 方法也要修改,很麻烦

使用继承定义 Dog 类,子类(派生类) 拥有 父类(基类) 的所有属性和方法:

class 类名(父类名)
    
    pass
class Animal:
    def eat(self):
        print("吃")

    def drink(self):
        print("喝")

    def run(self):
        print("跑")

    def sleep(self):
        print("睡")


class Dog(Animal):

    def bark(self):
        print("汪汪叫")

继承的传递性C 类从 B 类继承,B 类又从 A 类继承,那么 C 类就具有 B 类和 A 类的所有属性和方法

方法的重写

当父类的方法不能满足子类需求时,可以对方法进行 重写,有两种方式:

  • 覆盖
  • 扩展

覆盖

在子类中定义一个与父类同名的方法即可。

class Dog(Animal):

    def bark(self):
        print("汪汪叫")


class XiaoTianQuan(Dog):

    def fly(self):
        print("哮天犬会飞")

    def bark(self):
        print("叫得像神狗")

重写之后,在运行时,会调用子类中重写的方法,而不会调用父类的方法,

扩展

super 是 Python 中一个特殊的 ,在子类中常用 super().父类方法 来调用父类方法。

class Dog(Animal):

    def bark(self):
        print("汪汪叫")


class XiaoTianQuan(Dog):

    def fly(self):
        print("哮天犬会飞")

    def bark(self):
        print("叫得像神狗")
        super().bark()
        print("%$##@#&@$")


xtq = XiaoTianQuan()
xtq.bark()

输出:

叫得像神狗
汪汪叫
%$##@#&@$

也可以使用 Dog.bark(self) 调用父类方法。

子类对象不能在自己的方法内部 直接 访问父类的私有属性 / 方法,但仍可以通过父类的公有方法 间接 访问到其 私有属性 / 方法。


多继承

一个子类可以拥有多个父类,具有所有父类的属性和方法。

class 子类名(父类名1, 父类名2...)
    pass
class A:

    def test(self):
        print("A 的方法")


class B:

    def demo(self):
        print("B 的方法")


class C(A, B):

    pass


c = C()
c.test()
c.demo()

应尽量避免不同的父类中出现同名的方法。

MRO
__MRO__ 是类的一个内置属性。MRO 即 Method Resolution Order,直译就是方法解决顺序,主要用于在多继承时判断方法 / 属性的调用路径。

print(C.__mro__)

新式类与旧式类

objectPython 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看。

object 为基类的类就是 新式类,否则即为 旧式类

在新版本 Python 中,默认使用 object 作为所定义类的基类。

为了保证编写的代码能够同时在 旧版本 和 新版本的 Python 运行,在定义类时,建议统一继承自 object:

class 类名(object):
    pass