在 Python(2 和 3)中,我们可以将属性分配给函数:
>>> class A(object):
... def foo(self):
... """ This is obviously just an example """
... return "FOO{}!!".format(self.foo.bar)
... foo.bar = 123
...
>>> a = A()
>>> a.foo()
'FOO123!!'
这很酷。
但是为什么我们不能稍后更改 foo.bar
呢?例如,在构造函数中,像这样:
>>> class A(object):
... def __init__(self, *args, **kwargs):
... super(A, self).__init__(*args, **kwargs)
... print(self.foo.bar)
... self.foo.bar = 456 # KABOOM!
... def foo(self):
... """ This is obviously just an example """
... return "FOO{}!!".format(self.foo.bar)
... foo.bar = 123
...
>>> a = A()
123
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
AttributeError: 'instancemethod' object has no attribute 'bar'
Python 声称没有 bar
,即使它在前一行打印得很好。
如果我们尝试直接在类上更改它,则会发生同样的错误:
>>> A.foo.bar
123
>>> A.foo.bar = 345 # KABOOM!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'instancemethod' object has no attribute 'bar'
这里发生了什么,即为什么我们会看到这种行为?
有没有办法在创建类后设置函数的属性?
(我知道有多种选择,但我很想知道这里方法的属性,或者可能是更广泛的问题。)
动机:Django 利用了在方法上设置属性的可能性,例如:
class MyModelAdmin(ModelAdmin):
...
def custom_admin_column(self, obj):
return obj.something()
custom_admin_column.admin_order_field ='relation__field__span'
custom_admin_column.allow_tags = True
最佳答案
在类体内设置 foo.bar
是可行的,因为 foo
是实际的 foo
函数。但是,当您这样做时
self.foo.bar = 456
self.foo
不是那个函数。 self.foo
是一个实例方法对象,在您访问它时按需创建。由于多种原因,您无法为其设置属性:
- 如果这些属性存储在
foo
函数中,那么分配给a.foo.bar
会对b.foo.bar
产生意想不到的影响,这与对属性分配的所有常见预期相反。 - 如果这些属性存储在
self.foo
实例方法对象中,它们将不会在您下次访问self.foo
时显示,因为下次您将获得一个新的实例方法对象。 - 如果这些属性存储在
self.foo
实例方法对象上,并且您更改规则,使self.foo
始终是同一个对象,那么这会使 Python 中的每个对象大量膨胀以存储一堆您几乎不需要的实例方法对象。< - 如果这些属性存储在
self.__dict__
中,那么没有__dict__
的对象呢?此外,您需要想出某种名称修改规则,或将非字符串键存储在self.__dict__
中,这两者都有各自的问题。
如果你想在类定义完成后在 foo
函数上设置属性,你可以使用 A.__dict__['foo'].bar = 456
来实现。 (我已经使用 A.__dict__
来绕过 A.foo
是函数还是未绑定(bind)方法对象的问题,这取决于您的 Python 版本。如果 A
继承了 foo
,您将不得不处理该问题或访问它继承 foo
的类。)
关于python - 创建类后在方法上设置属性会引发 "' instancemethod' object has no attribute“但属性显然存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36749310/