调用类/静态方法并分配给实例变量

时间:2014-10-22 22:21:31

标签: python django django-forms

我正在尝试在类中创建一个类/静态方法。我需要SignInForm来定义实例变量,因为它们是由Django的模板呈现的。如何从实例变量中调用类中的方法?我的目标是使用自定义小部件更新每个变量,以创建一致的样式。

class SignInForm(forms.Form):

    @classmethod
    def get_text_input_with_attributes():
        return forms.TextInput(attrs= {'class':'form-style'})

    first_name = forms.CharField(max_length=50,required=True)
    first_name.widget = SignInForm.get_text_input_with_attributes()
    last_name = forms.CharField(max_length=50,error_messages={'required': ''})
    last_name.widget = SignInForm.get_text_input_with_attributes()
    ....lots of other custom fields

错误:

  

名称'SignInForm'未定义

2 个答案:

答案 0 :(得分:3)

首先,简短版本:

在定义该类时,您无法调用类 - 甚至类方法和静态方法 - 的方法,至少不容易。

那么,可以你做什么?嗯,实际上,你不想在这里使用类方法一个静态方法。你想要一个普通的旧功能。像这样:

class Spam(object):
    def _func():
        return 42

    class_attr = _func()

    del _func

在定义类之后,_func将是一个实例方法 - 一个不可调用的实例方法,因为它不会采用self。 (这就是为什么我用下划线加上前缀,以及del它的原因,以便以后不小心打电话给它......)

被定义时,它是一个正常的函数,可以这样调用。


我应该提一下,通常情况下,想要这样做表明你的设计存在一些问题,你作为一种类方法或静态方法尝试编写的东西实际上应该是一种方法。基类,自由函数或类构造函数,甚至可能是元类方法。

正如David Sanders' answer所解释的那样,您尝试做的具体事情很常见,因此有一种惯用的方式来编写它:作为TextField子类的类构造函数


这是如何运作的?

显然,当您正在执行Spam类定义时,没有任何名为Spam的内容,因此您绝对无法调用Spam._func

但为什么可以致电_func?您必须了解如何执行类定义。过度简化:Python创建一个空的全局字典,运行class定义中的所有代码,就像它是一个脚本一样,然后它返回到真正的全局变量并运行Spam = type('Spam', (object,), that_global_dict)。因此,当我们执行class_attr = _func()时,我们会进入该临时全局环境,而_func是该环境中的函数,因此我们可以调用它。

那么,为什么我们无法使用classmethodstaticmethod执行此操作?

首先,您需要一个cls对象来呼叫classmethod,而我们没有。{/ p>

另一方面,classmethodstaticmethod个对象无法调用。函数对象可以自己调用,它们也可以用descriptors来构造绑定方法。类和静态方法不可调用,它们只是描述符,可用于以特殊方式构造绑定方法(绑定到类或任何内容,而不是绑定到实例)。


那么,如果您想编写可用作类定义时间函数的东西,以及稍后作为静态方法,该怎么办?最简单的方法是:

class Spam(object):
    def _func():
        return 42
    smeth = staticmethod(_func)

    class_attr = func()

    del _func

@staticmethod这样的装饰者实际上只是_func = staticmethod(_func)。我们可以做同样的事情,但给结果一个不同的名字,现在我们有一个静态方法,同时仍然有原始函数直接调用。

答案 1 :(得分:1)

虽然abernet的答案很好地解释了你为什么会收到这个错误,但用django做这个的惯用方法是这样的:

from django import forms


class SignInFormCharField(forms.CharField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('widget', forms.TextInput(attrs={'class': 'form-style'}))
        super(SignInFormCharField, self).__init__(*args, **kwargs)


class SignInForm(forms.Form):
    first_name = SignInFormCharField(max_length=50, required=True)
    last_name = SignInFormCharField(max_length=50, error_messages={'required': ''})
    # ...