一、引言
这是我在学习 《Python Algorithms 2nd》第 32 页的时候看到的代码:
class Bunch(dict):
def __init__(self, *args, **kwargs):
super(Bunch, self).__init__(*args, **kwargs)
self.__dict__ = self
代码非常短小精悍,那么这是什么呢?
When prototyping or even finalizing data structures such as trees, it can be useful to have a flexible class that will allow you to specify arbitrary attributes in the constructor. In these cases, the Bunch pattern (named by Alex Martelli in the Python Cookbook) can come in handy.
根据 《Python Algorithms 2nd》作者的描述,The Bunch Pattern 是可以用来描述任意属性值的一个灵活的类,其命名来源于 《Python Cookbook》的作者 Alex Martelli。
那么,这个类究竟有什么神奇的功能呢?
1. 我们可以在构造函数中设置我们想要设置的任意数量的属性值
person = Bunch(name='wangying', age='23')
print(person)
print(person.name)
print(person['age'])
输出:
{‘name’: ‘wangying’, ‘age’: ‘23’}
‘wangying’
‘23’
可见,我们还可以使用 .
或者 []
运算符来访问对象的属性值(相当灵活方便!)。
2. 因为继承于 dict 类,我们拥有了 dict 类的所有方法,更加方便于我们的使用。
print(person.items())
print(person.keys())
print(person.values())
person.clear()
print(person)
输出:
dict_items([(‘name’, ‘wangying’), (‘age’, ‘23’)])
dict_keys([‘name’, ‘age’])
dict_values([‘wangying’, ‘23’])
{}
到这里,是不是感觉到 The Bunch pattern 太灵活强大了?!
接下来,让我们探索下,The Bunch pattern 拥有这些能力的原因何在。
二、探索
1. self.__dict__ = self
这句代码有什么深刻的含义?
当我第一眼看到了 self.__dict__ = self
这句代码的时候,想不出来这句代码究竟有什么含义,直到我们注释掉了这行代码,再执行以下的代码之后:
person = Bunch(name='wangying', age='23')
print(person.name)
这里开始报错:
Traceback (most recent call last):
File “”, line 1, in
AttributeError: ‘Bunch’ object has no attribute ‘name’
报错的含义是,Bunch 对象没有 name 属性,这是为什么呢?
通过查询资料,我发现了,原来 __dict__
中存储了类和对象的所有成员。这里,self.__dict__
操作的就是对象的成员,如果我们不将我们新加入的属性值加入到我们的对象成员记录 __dict__
中去,我们也就不能使用 .
运算符获取到该属性值;此时等式右边的 self
中存储了该对象接受到的所有属性值信息,因此这个等式相当于将当前所有构造传入的属性值信息存储到了 __dict__
中去,方便我们使用 Bunch 类创建的对象使用 .
运算符访问其属性值信息。
2. 任意属性值
这里简单提一下,初学者应该都有接触过,当一个函数接收 *args 和 **kwargs 的时候,也就意味着该函数能够接收任意数量任意类型的值。
三、总结
尽管看 《Python Algorithms 2nd》才看到第 32 页,我已经认定这个作者 Python 的深厚功力。
Magnus Lie Hetland 真乃大神也!