首页 > python 实例化对象能够直接添加属性的意义是什么?

python 实例化对象能够直接添加属性的意义是什么?

定义了一个 Person 类,并且给予 name 和 age 两个属性,实例化一个对象 rbt, 直接给 rbt 赋予了一个 sport 属性,尽然没有发生错误,而且 sport 最终确实被作为了 rbt的一个属性,疑问:Person 类中并未定义 sport 属性,为什么rbt 可以直接获得该属性?
内置的类比如数、字符串等是无法添加属性的,python 是怎么做到这种有选择的动态添加属性的?
python 这种动态添加属性的设计有什么现实应用?



python允许动态添加对象的属性和方法(相关操作可以参考这里),类似的还有javascript等……这跟python的设计有关,如果你问的是python的底层如何允许动态添加类的属性和方法,那么我无能为力,只好在此抛砖引玉一下。


Python 中自定义类的实例是可以动态添加属性的,但是内置的类的实例则不可以:

>>> class A():pass
... 
>>> a = A()
>>> a.name = 'myclassA'
>>> lst = list()
>>> lst.name = 'mylst'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'name'

上例中,自定义类 A 的实例 a 可以动态添加 name 属性,但 list 的实例 lst 则不可以。事实上,自定义的类若想禁止动态添加属性,则需借助 __slots__ 属性,默认情况下,自定义类是没有该属性的,比如 A 类的属性:

>>> dir(A)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

我们为自定义类 B 手动添加 __slots__ 属性,并将其值设为空:

>>> class B():
...     __slots__ = {}
... 
>>> b = B()
>>> b.name = 'myclassB'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'B' object has no attribute 'name'

如上,此时 B 的实例 b 便无法像 a 一样动态添加 name 属性。
另外,对于具有 __slots__ 属性的类,该类和其实例都会缺失 __dict__ 属性,我们可以发现:实例 b 比实例 a 多了__slots__属性,而实例 a 要比实例 b 多了__dict__和 name 属性:

>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
>>> dir(b)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__']
>>> b.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'B' object has no attribute '__dict__'
>>> a.__dict__
{'name': 'myclassA'}
>>> b.__slots__
{}
>>> a.__slots__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__slots__'

此外,__slot__的值若为非空,则类的实例只能添加__slots__值中定义的属性,而不能添加其他属性:

>>> class C():
...     __slots__ = {'name'}
... 
>>> c = C()
>>> c.name = 'MyclassC'
>>> c.other = 'dobi'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'other'
>>> c.__slots__
{'name'}

如上,自定义类 C 的实例 c 只能添加 name 属性,而不能添加 other 属性;另外,即便可以添加 name 属性,C 类和 c 仍无 __dict__ 属性,不过类 C 类可以动态的添加'__dict__' 属性,但实例 c 不可以:

>>> c.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__dict__'
>>> C.__dict__
mappingproxy({'__doc__': None, '__module__': '__main__', 'name': <member 'name' of 'C' objects>, '__slots__': {'name'}})

因为 c 是基于 C 类创建,而 C 类则是基于其超类创建,而 C 类的超类默认是没有定义__slots__的。

【热门文章】
【热门文章】