调用类/静态方法并赋值给实例变量

2 投票
2 回答
1242 浏览
提问于 2025-04-29 03:39

我正在尝试在一个类里面创建一个类方法或静态方法。我需要这个叫做 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 个回答

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': ''})
    # ...
3

首先,简单来说:

在定义一个类的时候,你不能调用这个类的方法——即使是类方法和静态方法——至少不容易做到。

那么,你可以做什么呢?其实,这里你不需要类方法或静态方法。你需要的是一个普通的函数。像这样:

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

    class_attr = _func()

    del _func

在类定义完成后,_func会变成一个实例方法——但它是一个不能被调用的实例方法,因为它不接受self。所以我在前面加了一个下划线,并且还用del把它删除了,这样就不容易在后面意外调用它了……

但是在定义的时候,它是一个普通的函数,可以像普通函数那样被调用。


我应该提到,通常想这样做说明你的设计有点问题,你想写成类方法或静态方法的东西,实际上应该是一个基类的方法,或者是一个自由函数,或者是一个类构造函数,甚至可能是一个元类的方法。

正如David Sanders的回答所解释的,你想做的事情是很常见的,有一种习惯用法可以写成:作为TextField子类的类构造函数。


这怎么运作的呢?

显然,当你正在执行Spam类的定义时,Spam这个名字并不存在,所以你肯定不能调用Spam._func

但是为什么可以调用_func呢?你需要理解类定义是如何执行的。简单来说:Python会创建一个空的全局字典,把class定义里面的所有代码当作脚本来运行,然后再回到真正的全局环境,执行Spam = type('Spam', (object,), that_global_dict)。所以当我们执行class_attr = _func()时,我们是在那个临时的全局环境中,而_func就是那个环境里的一个函数,所以我们可以调用它。

那么,为什么我们不能用classmethodstaticmethod呢?

首先,你需要一个cls对象来调用classmethod,而我们没有这个对象。

其次,classmethodstaticmethod对象是不可调用的。函数对象可以直接被调用,它们也是可以用来构造绑定方法的描述符。而类方法和静态方法不可直接调用,它们只是描述符,可以用特殊的方式构造绑定方法(绑定到类或不绑定,而不是绑定到实例)。


那么,如果你想写一个既可以在类定义时使用,又可以作为静态方法使用的东西,最简单的方法是:

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

    class_attr = func()

    del _func

@staticmethod这样的装饰器实际上是做了_func = staticmethod(_func)。我们可以做同样的事情,但给结果一个不同的名字,这样我们就得到了一个静态方法,同时还保留了原始函数可以直接调用。

撰写回答