2013-02-11 500 views
1

我被告知在類作用域中聲明動態屬性不是'Python方式',但我不明白爲什麼。 有人可以向我解釋這個或指出我在一些文件,爲什麼這是一件壞事?老實說,我認爲這是一個很好的做法,如果有任何自我記錄代碼。Python和類屬性聲明

實施例:

class ClassA(object): 
    user_data = {} 

    def set_user(self): 
     self.user_data['username'] = 'fred' 

我可以看到不使用這個唯一的原因是,屬性是靜態的(並且因此可能會誤導)..

+0

您應該訪問self.user_data或ClassA.user_data – jimifiki 2013-02-11 15:46:56

+2

這與pythonic沒有關係。這是與'user_data'在類的所有實例之間共享的事實。這是一個班級屬性。而且大多數開發人員都希望它是一個實例屬性,導致奇怪的行爲(對他們而言)。 – 2013-02-11 15:48:10

+0

固定..對不起是一個錯字 – Lee 2013-02-11 15:48:11

回答

1

隨着碼如圖所示,user_data ISN」 t 動態屬性(它不是在類實例上「動態地」創建的)。這是一個類屬性,這更像是我相信的其他一些語言中的「靜態」屬性。這意味着它是在類被讀取和初始化時在類上聲明的屬性。這具有所有能夠通過self.whatever訪問同一對象的實例的副作用/好處。

換句話說:

class Foo(object): 
    whatever = {} 
    def __init__(self): 
     print self.whatever is Foo.whatever 

將始終打印True

class Bar(object): 
    whatever = {} 
    def __init__(self): 
     self.whatever = {} 
     print self.whatever is Bar.whatever 

隨着Foo,如果我添加的項目:當然,你可以通過添加不同的whatever屬性的實例改變這種行爲foo_instance.whatever['foo'] = 'bar',然後foo_instance2會看到變化爲好,而不會是與Bar的情況。

0

下面是使用類和實例成員的例子:

class Test(object): 
    instances = {} 

    def __init__(self, name): 

     self.instance = self 
     self.instances[name] = self 

    # rest of class 

a = Test('alfred') 
b = Test('banana') 

# use a to get a 
print a.instance 

>>> 
<__main__.Test object at 0x0000000002BEBC50> 

# get all instances of the Test class 
print Test.instances 

>>> 
{'banana': <__main__.Test object at 0x0000000002BEBDA0>, 'alfred': <__main__.Test object at 0x0000000002BEBC50>} 

由於這些只是例子,它們並不反映任何具體的,只是可以做什麼。

在某些情況下聲明一個類成員是有用的,如上面所述,如果你想能夠記錄和控制某個類的所有類型。但是你應該總是明白你在做什麼,並且不要認爲instance對於每個實例都是本地的。

至於'最佳實踐'和'最pythonic方式'的問題。這就是,意見。有些東西會被某些人所詬病,而不會被其他人所詬病。只要符合由你所屬的任何工作人員施加的規定和標準,你就應該以一種讓你感覺舒適的方式寫作,這對你很有用。

3

在評論中,你說,「那麼每個實例都會有不同的可變user_data。」不,它不會。 ClassA的每個實例都將共享相同的user_data字典:

>>> class ClassA(object): 
...  user_data = {} 
...  def set_user(self, name): 
...   self.user_data['name'] = name 
... 
>>> a1 = ClassA() 
>>> a1.set_user('fred') 
>>> a1.user_data 
{'name': 'fred'} 
>>> 
>>> a2 = ClassA() 
>>> a2.user_data 
{'name': 'fred'} 
>>> a2.set_user('barney') 
>>> a2.user_data 
{'name': 'barney'} 
>>> 
>>> a1.user_data 
{'name': 'barney'} 
>>> 
>>> a1.user_data is a2.user_data 
True 

這不是一個Pythonic是不是問題。這是編寫代碼的行爲,如你所願。

+0

感謝您的幫助..我已經標記了另一個答案作爲正確的答案,因爲它可以幫助更多的人..但是,謝謝:)你讓我意識到錯誤。 – Lee 2013-02-11 16:29:06

0

要清楚,類屬性可能與您預期的不同。

實施例:

class Example(object): 
    class_data={} 
    def __init__(self,val): 
     self.val=val 
    def __repr__(self): 
     return str(self.val) 

>>> Example.class_data['one']=1 # assign value to the empty dict in class Example 
>>> e1,e2=Example(1), Example(2) # INSTANCES-self.val different for each instance 
>>> print e1,e2,e1.class_data,e2.class_data 
1 2 {'one': 1} {'one': 1} 
     ^^^^^  ^^^^^   # SAME class_data in two different instances 

注意實施例的每個實例具有class_data的相同的可變副本。它不受保護,因爲靜態類變量可能在Java或C++中。

事實上,你可以更改,添加或刪除在任何時候將這些類屬性:

>>> Example.class_data='old dict is gone gone gone...' 
>>> print e1,e2,e1.class_data,e2.class_data 
1 2 old dict is gone gone gone... old dict is gone gone gone... 

您可能會看到這樣的代碼:

class Example(object): 
    class_constants=('fee','fie','foe') 
    # ... 

隨着虛假的安慰,這是像個常數(另一種語言),因爲這樣:

>>> e1=Example(1) 
>>> e1.class_constants[4]='fum' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'tuple' object does not support item assignment  

但是,這是一個虛假的安慰因爲... E中的一段代碼總是可以做到這一點:

>>> Example.class_constants=('another','tuple','of','constants') 

,一些有類屬性的問題在於他們沒有做什麼期望 - 因爲它是一個常數。它們不是常量。類屬性更改類的所有現有和將來實例的數據。有時有用,但可能會令人困惑。

真的,如果class屬性是可變的,那沒有關係。如您所見 - 您可以隨時更改屬性。