我在哪里、何时以及如何更改对象的__class__属性?

17 投票
4 回答
7435 浏览
提问于 2025-04-15 23:47

我想要能够做到:

>>> class a(str):
...     pass
...
>>> b = a()
>>> b.__class__ = str
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types

4 个回答

-1

只有用 class 关键字定义的类,才能用来给 __class__ 属性赋值:

>>> class C:
    pass

>>> class D:
    pass

>>> C().__class__ = D
>>>
6

Python 2没有统一的对象层次结构,也就是说,并不是所有东西都是从object派生出来的。属于这个层次结构的东西可以通过__class__来操作,但那些不属于这个层次的东西就不能这样修改(实际上也不能修改)。在Python 2中,这些被称为“类型”,而不是“类”,它们是用C语言硬编码的。类型的例子有str(字符串)、int(整数)、float(浮点数)、list(列表)、tuple(元组)等等。这意味着你不能像对待类那样使用这些类型,比如你不能改变一个类型实例的类,也不能添加、删除或修改类型的方法等等。下面的记录展示了像str这样的类型(硬编码的、非动态的C构造)和我称之为A和B的类(可变的、动态的Python构造)之间的行为差异:

>>> str
<type 'str'>
>>> class A:
...     pass
... 
>>> a = A()
>>> A
<class __main__.A at 0xb747f2cc>
>>> a
<__main__.A instance at 0xb747e74c>
>>> type(a)
<type 'instance'>
>>> type(A)
<type 'classobj'>
>>> type(str)
<type 'type'>
>>> type(type(a))
<type 'type'>
>>> type(type(A))
<type 'type'>
>>> A.foo = lambda self,x: x
>>> a.foo(10)
10
>>> A().foo(5)
5
>>> str.foo = lambda self,x: x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
>>> 'abc'.foo(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'foo'
>>> class B:
...     pass
... 
>>> a.__class__
<class __main__.A at 0xb747f2cc>
>>> a.__class__ = B
>>> a
<__main__.B instance at 0xb747e74c>
>>> 'abc'.__class__
<type 'str'>
>>> 'abc'.__class__ = B
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ must be set to new-style class, not 'classobj' object
>>> class B(object):
...     pass
... 
>>> 'abc'.__class__ = B
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types
7

我这样解决了这个问题:

>>> class C(str):
...     def __getattribute__(self, name):
...         if name == '__class__':
...             return str
...         else:
...             return super(C, self).__getattribute__(name)
...         
>>> c = C()
>>> c.__class__
<type 'str'>

撰写回答