2010-02-21 77 views
4

我很想這樣定義我的Python類:Python類語法 - 這是一個好主意嗎?

class MyClass(object): 
    """my docstring""" 

    msg = None 
    a_variable = None 
    some_dict = {} 

    def __init__(self, msg): 
     self.msg = msg 

正在申報頂部的對象變量(味精,a_variable等),如Java好或壞或無動於衷?我知道這是不必要的,但仍然很有誘惑力。

+2

儘管這些屬性存儲在不同的位置是正確的,但是當這些值是不可變的,並且您通過self而不是class對象訪問它們時,它們並沒有什麼不同。對於可變對象(some_dict)來說,它確實有很大的不同。 – 2010-02-22 01:28:05

+0

對於不可變的「變量」(將msg和a_variable分配給None),我強烈建議您閱讀有關python的* names *:http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html #other-languages-have-variables 如果你認爲它是* tag * ** names **而不是* variables *,那麼它就沒有任何意義「初始化變量」。 「無」只是一個站在那裏的物體,除非你使用它,否則你不應該標記它。 – cregox 2010-04-14 17:39:20

回答

1

當你聲明一個類時,Python將解析它的代碼並將所有東西放在類的名字空間中;那麼這個類將被用作從它派生的所有對象的一種模板 - 但是任何對象都將擁有它自己的引用副本。
請注意,你總是有參考;因此,如果您可以更改引用的對象,則更改將反映到正在使用的所有位置。但是,成員數據的插槽對於每個實例都是唯一的,因此將其分配給新對象不會反映到其他任何正在使用的位置。

注意:Michael Foord在類實例化的工作方式上有very nice blog entry;如果你對這個話題感興趣,我建議你閱讀簡短。

無論如何,對於所有的實際用途,也有你的兩種方法之間的兩個主要區別:

  1. 名稱已可在一流水平,你可以使用它沒有實例化一個新的對象;這在聲明命名空間中的常量聽起來很整潔,但在很多情況下,模塊名稱可能已經很好。
  2. 該名稱是在課程級別添加的 - 這意味着您可能無法在單元測試期間輕鬆地嘲笑它,並且如果您有任何昂貴的操作,則可以在導入時立即得到它。

通常,審查代碼我看到在課堂上聲明的成員有點懷疑;對他們來說有很多很好的用例,但它們也很有可能是以前使用其他編程語言的一種習慣。

+1

「這個類將被用作從它派生的所有對象的一種模板 - 但任何對象都有它自己的數據副本」是不正確的。 – 2010-02-22 00:04:53

+0

-1:設置類似於OP的'msg','a_variable'和'some_dict'的類成員,然後在該類的所有對象之間共享,除非對象的構造函數複製並替換成員。你看到了哪些不同的地方? – 2010-02-22 00:58:48

+0

你是對的。我只關注會員插槽不共享的事實,但它提供參考的事實也應該是解釋的一部分。希望現在應該更清楚。 – 2010-02-22 14:45:23

8

在類定義中定義變量,使得變量可以在該類的每個實例之間訪問。在Java中,它是有點像使變量靜態。但是,下面顯示了一些主要區別。

class MyClass(object): 
    msg = "ABC" 

print MyClass.msg  #prints ABC 
a = MyClass() 
print a.msg   #prints ABC 
a.msg = "abc" 
print a.msg   #prints abc 
print MyClass.msg  #prints ABC 
print a.__class__.msg #prints ABC 

正如從上面的代碼看出,這是不太一樣的東西,如同時該變量可以經由self.msg訪問,當它被分配它沒有被分配給在類範圍中定義的變量的值。

通過您所做的方法來做這件事的一個缺點是,它可能會導致錯誤,因爲它會將隱藏狀態添加到類中。說某人從構造冷落self.msg = "ABC"(或更爲現實代碼被重構,只有定義之一是改變)

a = MyClass() 
print a.msg #prints ABC 

#somewhere else in the program 
MyClass.msg = "XYZ" 

#now the same bit of code leads to a different result, despite the expectation that it 
#leads to the same result. 
a = MyClass() 
print a.msg #prints XYZ 

遠越好,以避免在類級別定義味精,然後您避免的問題:

class MyClass(object): 
    pass 

print MyClass.msg #AttributeError: type object 'MyClass' has no attribute 'msg' 
4

小心。這兩個msg屬性實際上存儲在兩個不同的字典中。 其中一個遮掩了另一個,但該屬性仍在字典中佔據空間。所以它沒有被使用,但仍然佔用一些內存。

class MyClass(object):  
    msg = 'FeeFiFoFum' 
    def __init__(self, msg): 
     self.msg = msg 

m=MyClass('Hi Lucy') 

請注意,我們有'Hi Lucy'作爲值。該MyClass的的字典(通過m.__class__訪問)

print(m.__dict__) 
# {'msg': 'Hi Lucy'} 

公告仍然有FeeFiFoFum

print(m.__class__.__dict__) 
# {'__dict__': <attribute '__dict__' of 'MyClass' objects>, '__module__': '__main__', '__init__': <function __init__ at 0xb76ea1ec>, 'msg': 'FeeFiFoFum', 'some_dict': {}, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': 'my docstring', 'a_variable': None} 

其它的(也許更簡單)的方式來看到這一點:直接

print(m.msg) 
# Hi Lucy 
print(MyClass.msg) 
# FeeFiFoFum 
+0

在這種情況下,我不認爲「佔用一些內存」是一個值得注意的問題。如果您創建更多MyClass實例,則不會有更多「FeeFiFoFum」。只會有其中之一。記憶力不是一件大事。 – FogleBird 2010-02-22 14:44:39

+0

@FogleBird:我同意浪費的內存量是最小的,但爲什麼浪費內存當你不需要?無論如何,我提到內存問題主要是爲了證明類屬性和實例屬性是完全不同的東西。在類級別初始化屬性不會初始化實例屬性,因此OP的代碼沒有執行我認爲OP認爲它正在執行的操作。 – unutbu 2010-02-22 17:15:55

6

變量聲明裏面的類定義使它們類變量而不是實例變量。類變量與Java中的靜態變量有點類似,應該像MyClass.a_variable一樣使用。但它們也可以像self.a_variable一樣使用,這是一個問題,因爲天真的程序員可以將它們視爲實例變量。例如,您的「some_dict」變量將由MyClass的每個實例共享,因此如果您向其添加密鑰「k」,則任何實例都可以看到該密鑰。

如果您總是記得重新分配類變量,那麼與實例變量幾乎沒有區別。只有MyClass中的初始定義將保留。但無論如何,這不是一個好習慣,因爲如果不重新分配這些變量,可能會遇到麻煩!

最好寫的類,像這樣:

class MyClass(object): 
    """ 
    Some class 
    """ 

    def __init__(self, msg): 
     self.__msg = msg 
     self.__a_variable = None 
     self.__some_dict = {} 

使用兩個下劃線爲 「私有」 變量(pseudo-private!)是可選的。如果變量應該是公開的,只需保留它們的名字,而不用前綴__

+0

'__'前綴並沒有形成一個有意義的私有變量,只是做了一些名稱修改(如鏈接文檔中所述),最終導致類更加煩人,並且大部分時間都是測試子類。目前沒有太多好的Python代碼似乎使用它,更喜歡傳統的單引號下劃線來表示內部屬性。 – 2010-02-22 06:04:17

+0

@Mike Graham:我提到它是可選的。開發人員可以自行決定。 – AndiDog 2010-02-22 07:02:34

相關問題