私有属性 / 方法
在实际开发中,一个对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到,这就叫 私有属性 / 私有方法。
在定义属性或方法时,在属性名或者方法名前增加 两个下划线,定义的就是私有属性或方法
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__)
新式类与旧式类
object
是 Python
为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir
函数查看。
以 object
为基类的类就是 新式类,否则即为 旧式类。
在新版本 Python 中,默认使用 object
作为所定义类的基类。
为了保证编写的代码能够同时在 旧版本 和 新版本的 Python 运行,在定义类时,建议统一继承自 object
:
class 类名(object):
pass