[英]Calling a method on a new instance of an object without assigning it to a variable
[英]Calling class/static method and assigning to an instance variable
我正在嘗試在一個類中創建一個類/靜態方法。 我需要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'未定義
首先,簡短的版本:
在定義該類的過程中,您不能調用類的方法(甚至是類方法和靜態方法),至少不容易。
所以,你能做什么呢? 好吧,實際上,您在這里不需要類方法或靜態方法。 您需要常規的舊功能。 像這樣:
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
是該環境中的一個函數,因此可以調用它。
那么,為什么我們不能使用classmethod
或staticmethod
做到這一點呢?
一方面,您需要一個cls
對象來調用classmethod
,但我們沒有一個。
另外, classmethod
和staticmethod
對象是不可調用的。 函數對象本身可以調用,它們也是可用於構造綁定方法的描述符 。 類和靜態方法是不可調用的,它們只是描述符,可用於以特殊方式構造綁定方法(綁定到類或什么都沒有,而不是實例)。
因此,如果您想編寫可用作類定義時間函數以及以后用作靜態方法的東西怎么辦? 最簡單的方法是:
class Spam(object):
def _func():
return 42
smeth = staticmethod(_func)
class_attr = func()
del _func
像@staticmethod
這樣的裝飾器@staticmethod
只是執行_func = staticmethod(_func)
。 我們可以做同樣的事情,但是給結果取一個不同的名字,現在我們有了一個靜態方法,同時仍然可以直接調用原始函數。
盡管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': ''})
# ...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.