《Python Cookbook》的作者David Beazley的课程PPT开源了,目标用户是希望从编写基础脚本过渡到编写更复杂程序的高级 Python 程序员,课程主题侧重于流行库和框架中使用的编程技术,主要目的是更好地理解 Python 语言本身,以便阅读他人的代码,并将新发现的知识应用到自己的项目中。内容组织的很棒,总共分为九个章节,我在阅读过程中顺便翻译整理下,用来查缺补漏了。翻译内容并非原版无对照翻译,有所增减,本篇是系列第四节。
感兴趣可前往原课件进行阅读 https://github.com/dabeaz-course/python-mastery/blob/main/PythonMastery.pdf
字典保存实例数据,每个实例都有自己的私有字典,如果创建了某个类的 100 个实例,则有 100 个保存数据的字典
字典保存类的成员
实例字典保存每个实例唯一的数据,而类字典保存所有实例共同共享的数据
__ class__ 属性引用回类
>>> s = Stock('GOOG', 100, 490.10)
>>> s.__dict__
{'name':'GOOG','shares':100,'price':490.10 }
>>> s.__class__
<class '__main__.Stock'>
>>>
修改对象的操作总是更新底层字典
>>> s = Stock('GOOG',100,490.10)
>>> s.__dict__
{'name':'GOOG', 'shares':100, 'price':490.10 }
>>> s.shares = 50
>>> s.date = '6/7/2007'
>>> s.__dict__
{ 'name':'GOOG', 'shares':50, 'price':490.10,
'date':'6/7/2007'}
>>> del s.shares
>>> s.__dict__
{ 'name':'GOOG', 'price':490.10, 'date':'6/7/2007'}
>>>
首先检查实例__dict__
,如果没有找到,则查看类的__dict__
父类在每个类中存储为元组,扩展了用于查找属性的搜索过程
class A(B,C):
...
>>> A.__bases__
(,)
>>>
MRO(Method Resolution Order)是指在面向对象编程中,确定类的方法调用顺序的算法。在Python中,MRO是通过C3线性化算法来实现的。C3线性化算法是一种基于拓扑排序的算法,用于解决多继承中方法调用的冲突问题,该算法保证了类的方法调用顺序满足一些重要的特性,例如保持局部顺序和首选父类等。
在Python中,类的继承是通过在类定义时指定基类来实现的。当一个类继承自多个基类时,Python会按照特定的顺序来解析方法调用。下面是一个示例,展示了MRO的工作原理:
class A:
def some_method(self):
print("A's method")
class B(A):
def some_method(self):
print("B's method")
class C(A):
def some_method(self):
print("C's method")
class D(B, C):
pass
d = D()
d.some_method()
在这个例子中,类D继承自类B和类C,而类B和类C都继承自类A。对于类D,其MRO的顺序可以通过以下方式获取:
print(D.__mro__)
输出结果为:
(, , , , )
从输出结果可以看出,方法调用的顺序是D -> B -> C -> A -> object。这意味着在类D中调用some_method()
方法时,首先会在类D中查找该方法,如果找不到,则按照MRO的顺序在类B、类C和类A中查找,直到找到该方法或者到达object类。
super()
函数实际上是通过方法解析顺序(MRO)查找父类的方法,并在父类的上下文中执行该方法。这样可以实现子类对父类方法的扩展和重写,而不会丢失父类方法的功能。
class A(Base):
def spam(self):
Base.spam(self)
class A(Base):
def spam(self):
super().spam()
看着篇吧 Python 描述符简介,PPT 内容组织的有点乱
每当访问类上的属性时,都会检查该属性以查看它是否是一个看起来像所谓的“描述符”的对象
描述符包含有关实例、类和值的信息
self 是描述符本身,instance 是它正在操作的对象。
类的每个主要特征都是使用描述符来实现的
__ slots __
描述符提供了在运行时将实例和类连接在一起的粘合剂
描述符通常是作为类的属性来定义的,它们实现了一些特殊的方法,如__get__
、__set__
和__delete__
。这些方法允许描述符拦截对属性的访问,并执行自定义的行为。
class Descriptor:
def __get__(self, instance, owner):
print("Getting the value")
return instance._value
def __set__(self, instance, value):
print("Setting the value")
instance._value = value
def __delete__(self, instance):
print("Deleting the value")
del instance._value
class MyClass:
attribute = Descriptor()
def __init__(self, value):
self._value = value
obj = MyClass(10)
print(obj.attribute) # Output: Getting the value 10
obj.attribute = 20 # Output: Setting the value
print(obj.attribute) # Output: Getting the value 20
del obj.attribute # Output: Deleting the value
__getattribute__()
__getattr__()
__ setattr__()
__ delattr__()
保存对对象的内部引用;属性访问被重定向到持有的对象
class Proxy:
def __init__(self,obj):
self._obj = obj
def __getattr__(self,name):
print('getattr:', name)
return getattr(self._obj, name)
有时用作继承的替代方式
class A:
def foo(self):
print('A.foo')
def bar(self):
print('A.bar')
class B:
def __init__(self):
self._a = A()
def bar(self):
print('B.bar')
self._a.bar()
def __getattr__(self, name):
return getattr(self._a, name)