Bar*_*eyn 6 python django django-models
这令我感到困惑,但我无法得到明确的答案.__new__在从DJango模型派生的类中使用该方法(或更准确地说,静态方法).
这是__new__应该如何理想使用(因为我们使用Django,我们可以假设正在使用python的2.x版本):
class A(object):
def __new__(self, *args, **kwargs):
print ("This is A's new function")
return super(A, self).__new__(self, *args, **kwargs)
def __init__(self):
print ("This is A's init function")
Run Code Online (Sandbox Code Playgroud)
从上面的类实例化对象按预期工作.现在,当在Django模型派生的类上尝试这样的事情时,会发生意外情况:
class Test(models.Model):
def __new__(self, *args, **kwargs):
return super(Test, self).__new__(self, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
从上面的类中实例化对象会导致此错误:
TypeError: unbound method __new__() must be called with Test instance as first argument (got ModelBase instance instead).
我无法理解为什么会发生这种情况(虽然我知道由于Django框架,一些类魔法正在幕后发生).
任何答案将不胜感激.
Ben*_*Ben 11
__new__不接收实例作为其第一个参数.怎么可能当(a)它是一个静态方法,如你所注意到的,以及(b)它的工作是创建一个实例并返回它!__new__传统上调用第一个参数cls,因为它是类.
这使得您引用的错误消息非常奇怪; 它通常是您在调用未绑定方法(即通过访问获得的内容ClassName.methodName)时获得的错误消息,而不是该类的实例作为self参数.但是,staticmethods(包括__new__)不会成为未绑定的方法,它们只是简单的函数,恰好是类的属性:
>>> class Foo(object):
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
def method(self):
pass
>>> class Bar(object):
pass
>>> Foo.method
<unbound method Foo.method>
>>> Foo.__new__
<function __new__ at 0x0000000002DB1C88>
>>> Foo.method(Bar())
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
Foo.method(Bar())
TypeError: unbound method method() must be called with Foo instance as first argument (got Bar instance instead)
>>> Foo.__new__(Bar)
<__main__.Bar object at 0x0000000002DB4F28>
Run Code Online (Sandbox Code Playgroud)
你可以从中看到,__new__永远不应该是一个未绑定的方法.此外(与普通方法不同)它并不关心你传递的内容是否一致; 我实际上设法Bar通过调用构建一个实例,Foo.__new__因为它和Bar.__new__最终以相同的方式实现(将所有实际工作推迟到object.__new__).
但是,这让我简单地看一下Django本身的源代码.Django的Model类有一个元类,ModelBase.这是非常复杂的,我没有弄清楚它在做什么,但我注意到了一些非常有趣的事情.
ModelBase.__new__(元类 __new__,它是在类块末尾创建类的函数)调用它的超级__new__ 而不传递类字典.它改为传递仅包含__module__属性集的字典.然后,在完成一大堆处理之后,它执行以下操作:
# Add all attributes to the class.
for obj_name, obj in attrs.items():
new_class.add_to_class(obj_name, obj)
Run Code Online (Sandbox Code Playgroud)
(attrs是包含您的类块中所有定义的字典,包括您的__new__函数; add_to_class是一个主要是元类的方法setattr).
我现在99%肯定问题就在这里,因为这__new__是一个奇怪的隐式静态方法.因此,与其他所有静态方法不同,您尚未将staticmethod装饰器应用于它.Python(在某种程度上)只是识别__new__方法并将其作为静态方法处理而不是普通方法[1].但我敢打赌,只有__new__在类块中定义时才会发生这种情况,而不是在使用时进行定义setattr.
因此,您的__new__(应该是静态方法但尚未由staticmethod装饰器处理)正在转换为普通实例方法.然后,当Python调用它传递类时 Test,按照正常的实例创建协议,它会抱怨它没有获取实例Test.
如果这一切都正确,那么:
__new__静态考虑不一致.@staticmethod你的__new__方法来完成这项工作,即使你不应该这样做.[1]我相信这是Python的一个历史怪癖,因为它__new__是在staticmethod装饰器之前引入的,但是__new__ 不能接受一个实例,因为没有实例可以调用它.
| 归档时间: |
|
| 查看次数: |
2126 次 |
| 最近记录: |