2012-12-12 40 views
1

用例:用於類實例變量的對象方法鏈接的Python方法

我有一個接收實例變量(表單域)的表單對象。現在我想用方法鏈來驗證那些變量。任意方法的例子:

class Field(object): 

    def __init__(self, form, name): 
     self.form = form 
     self.name = name 

    def unspace(self): 
     setattr(self.form, self.name, getattr(self.form, self.name).replace(' ','')) 
     return self 

    def len_valid(self, length): 
     if len(getattr(self.form, self.name)) < length : 
      setattr(self.form, self.name + '_invalid', True) 
      self.form.valid = False 
     return self 

class Forms(object):                      

    def __init__(self): 
     self.valid = True 

    def validate(self, name): 
     return Field(self,name) 

f = Forms()   # create the form with some data 
f.a = 'J o Hn ' 
f.b = ' Too L o n g' 

f.validate('a').unspace().len_valid(2) 
f.validate('b').unspace().len_valid(5) 

RESULT : 
f.a : 'JoHn' 
f.a_invalid : True 
f.b : 'TooLong' 
f.valid : False 

這是在Form實例變量上創建方法鏈接的Pythonic方法。

+0

不是一個直接的答案,但是:這些東西必須是屬性(實例變量)而不是隻是'dict'的成員,所以你可以放下所有'setattr' /'getattr'東西並寫入簡單,直接的代碼? – abarnert

+0

你讓這種方式太複雜了。做@abarnert說什麼,只是把所有內容都寫成字典。 – katrielalex

回答

4

是的,沒有。

的Python的方式來鏈方法調用正好是你寫的:

f.validate('a').unspace().len_valid(2) 

但是Python的方式動態地訪問屬性是這樣做,除非你要。如果表單變量存儲在dict中而不是作爲對象的實例變量存儲,則所有內容都將更加簡單易讀。

即使你真的需要表單變量作爲f.a而不是f['a'](例如,因爲這是交互式shell的一部分,或者某些第三方API需要),所以寫入所有代碼實際上更容易圍繞dict,並使用您最喜歡的AttrDict類(來自PyPI或ActiveState)爲您的用戶/第三方API提供屬性式訪問。另外,如果你用一些方法進一步將Field對象改爲一個簡單的包裝值,而不是(實際上)對父對象和關鍵字的引用,那將更加簡單。另外,如果您像a_invalid那樣生成新的屬性,您可能想要總是生成它們,不僅僅當它們是真實的。否則,檢查a是否有效看起來是這樣的:

try: 
    avalid = not f.a_invalid 
except NameError: 
    avalid = True 

這是可怕的令人費解,但如果你的調用者想要避免這種情況,這樣做的唯一方法是這樣的:

avalid = not getattr(f, 'a_invalid', False) 

這似乎打敗了首先爲來電者僞造屬性的整個目的。

此外,請記住,您必須確保永遠不會有名稱以_invalid結尾的字段。既然你可以在Python中附加幾乎所有的新屬性,所以如果你真的想這樣做,爲什麼要用f.a_invalid而不是f.a.invalid

既然你在評論中問道,圍繞價值微不足道的包裝看起來是這樣的:

class Field(object): 

    def __init__(self, value): 
     self.value = value 
     self.valid = True 

    def unspace(self): 
     self.value = self.value.replace(' ', '') 
     return self 

    def len_valid(self, length): 
     if len(self.value) < length: 
      self.valid = False 
     return self 

而不是使每個字段的可達形式設置它的有效性,才使形式做到這一點:

class Form(object): 
    … 
    def valid(self): 
     return all(field.valid for field in self.fields) 

如果你真的需要作出規定:valid看起來像一個成員變量,而不是一個方法,只要使用@property

+1

或者您可以使用現有的表單驗證庫。 – Marcin

+0

@Marcin:表單驗證是表單wizzard的一部分。這就是爲什麼我沒有使用驗證庫。 – voscausa

+0

@abarnert。感謝您的好評。我使用帶有_invalid的名字作爲我的Jinja模板,因爲我可以輕鬆地將它們刪除。你能給我一個你的「平凡包裝」的例子嗎?順便說一句:我從字典切換到實例變量,使其更具可讀性。隨着你的建議像AttrDict我會再試一次。 – voscausa

相關問題