封装
将属性私有化,定义公有set和get方法
- 方法一
class Person:
def __init__(self):
self.__name = '小明'
self.__age = 15
def setAge(self,age):
self.__age = age
def getAge(self):
print(self.__age)
def getName(self):
print(self.__name)
if __name__ == '__main__':
xiaoming = Person()
# 无法直接访问属性 __name,__age
xiaoming.getName()
# 更改小明的年龄
xiaoming.setAge(20)
xiaoming.getAge()
# 查看类的所有属性和方法
print(dir(xiaoming))
print(xiaoming.__dir__())
输出结果
小明
20
['_Person__age', '_Person__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getAge', 'getName', 'setAge']
['_Person__name', '_Person__age', '__module__', '__init__', 'setAge', 'getAge', 'getName', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
可以看出属性私有化的本质
:在对象的私有属性前添加_类名
(_Person__age,_Person__name)
- 方法二 :使用装饰器
class Student:
def __init__(self):
self.__name = '小红'
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name = name
if __name__ == '__main__':
xiaohong = Student()
# 不使用赋值= 默认调用getter方法
print(xiaohong.name)
# 使用赋值= 默认使用setter方法
xiaohong.name = '王涵'
print(xiaohong.name)
继承
在Python中,支持多继承。
- 示例一(单继承):
class Person:
def __init__(self,name):
self.name = name
class Student(A):
def __init__(self):
super(B, self).__init__("小明")
self.age = 15
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name,self.age)
if __name__ == '__main__':
xiaoming = Student()
print(xiaoming)
输出结果:
姓名:小明,年龄:15
python 多重继承的方法解析顺序
任何实现多重继承的语言都要处理潜在的命名冲突, 这种冲突由不相关的祖先类实现同名方法引起
- 示例二(多继承,使用较少):
class A:
def say(self):
print("A Hello:", self)
class B(A):
def eat(self):
print("B Eating:", self)
class C(A):
def eat(self):
print("C Eating:", self)
class D(B, C):
def say(self):
super().say()
print("D Hello:", self)
def dinner(self):
self.say()
super().say()
self.eat()
super().eat()
C.eat(self)
if __name__ == '__main__':
d = D()
d.eat()
#d.dinner()
这里B和C都实现了eat方法,
在 D 的实例上调用 d.eat() 方法的话, 运行的是哪个 eat 方法呢?
>>> d = D()
>>> d.eat()
B Eating: <__main__.D object at 0x7fb90c627f60>
>>> C.eat(d)
C Eating: <__main__.D object at 0x7fb90c627f60>
超类中的方法都可以直接调用, 此时要把实例作为显式参数传入
Python 能区分 d.eat() 调用的是哪个方法, 是因为 Python 会按照特定的顺序遍历继承图。 这个顺序叫方法解析顺序( Method Resolution Order, MRO)。 类都有一个名为 mro 的属性, 它的值是一个元组, 按照方法解析顺序列出各个超类, 从当前类一直向上, 直到object 类。 D 类的 mro 属性如下 :
# 输出元组
print(D.__mro__)
# 输出列表
print(D.mro())
输出:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
新式类、经典类
在Python 3.x中取消了经典类,默认都是新式类,并且不必显式的继承object,也就是说:
class Person(object):pass
class Person():pass
class Person:pass
三种写法并无区别,推荐第一种
但是在Python2.x中,默认都是经典类,只有显式继承了object才是新式类,即:
class Person(object):pass
新式类写法
class Person():pass
经典类写法
class Person:pass
经典类写法
他们最明显的区别在于继承搜索的顺序发生了改变,即
经典类多继承搜索顺序(深度优先):
先深入继承树左侧查找,然后再返回,开始查找右侧
新式类多继承搜索顺序(广度优先):
先在水平方向查找,然后再向上查找
多态
在python中没有严格的多态概念。总是伴随着继承使用的。若后续有学习,继续补充。