2009-08-09 290 views
12

我有興趣聽到關於Python中類屬性的一些討論。例如,什麼是類屬性的良好用例?大多數情況下,我不能想出一個類屬性優於使用模塊級屬性的情況。如果這是真的,那麼爲什麼他們呢?Python類與模塊屬性

我與他們的問題是,它幾乎太容易錯誤地破壞類屬性值,然後你的「全局」值已經變成本地實例屬性。

歡迎你將如何處理以下情況發表意見:

  1. 由類和/或子類中使用的常數值。這可能包括「幻數」字典鍵或列表索引,永遠不會改變,但可能需要一次性初始化。
  2. 默認類屬性,在極少數情況下更新爲類的特殊實例。
  3. 全局數據結構用於表示在所有實例之間共享的類的內部狀態。
  4. 初始化大量默認屬性的類,不受構造函數參數的影響。

幾個相關文章:
Difference Between Class and Instance Attributes

+0

應該是社區維基 – SilentGhost 2009-08-09 09:18:32

回答

7

#4: 我從未使用類屬性初始化默認實例屬性(你通常放在__init__的那些)。例如:

class Obj(object): 
    def __init__(self): 
     self.users = 0 

永不:

class Obj(object): 
    users = 0 

爲什麼?因爲它是不一致的:它不會做你想要什麼,當你分配什麼,但一個不變的目標:

class Obj(object): 
    users = [] 

導致用戶列表將在所有對象,在這種情況下是不想要共享。將它們分成__init__中的類屬性和賦值是很困惑的,這取決於它們的類型,所以我總是把它們全部放在__init__中,無論如何我都會發現它們更清晰。


至於其餘的問題,我通常會把班級的具體數值放在課堂上。這並不是因爲全局變量是「邪惡的」 - 它們並不像某些語言那麼大,因爲它們仍然被作用於模塊,除非模塊本身太大 - 但如果外部代碼想要訪問它們,將所有相關的值放在一個地方很方便。例如,在module.py:

class Obj(object): 
    class Exception(Exception): pass 
    ... 

然後:

from module import Obj 

try: 
    o = Obj() 
    o.go() 
except o.Exception: 
    print "error" 
從允許子類更改值(它並不總是反正想),這意味着我沒有

除了費力地導入異常名稱以及使用Obj所需的其他一些東西。 「從模塊導入Obj,ObjException,...」很快就厭倦了。

2

類屬性經常被用來允許在子類中壓倒一切的默認值。例如,BaseHTTPRequestHandler具有類常量sys_version和server_version,後者默認爲"BaseHTTP/" + __version__。 SimpleHTTPRequestHandler覆蓋server_version到"SimpleHTTP/" + __version__

+0

但是,如果這有效或無效,類屬性的訪問方法將是一個因素。 Class屬性危險的另一個原因。 – cmcginty 2009-08-09 10:19:05

+0

什麼「訪問方法」? cls.version,self.version,getattr,都會給出正確的答案。 *在類中定義以允許覆蓋*與數據一樣適用於代碼 - 所以,凱西,爲什麼你認爲這對數據是危險的,但對代碼來說很好? – 2009-08-09 15:27:45

+0

通過在訪問屬性的方法中使用Class.value而不是self.value將防止發生重寫。有時這是所需的情況,其他時間則不是。 – cmcginty 2009-08-09 21:15:34

1

封裝是一個很好的原則:當一個屬性位於類內部時,它屬於全局範圍內的屬性,這爲讀取代碼的人提供了額外的信息。

在你的情況1-4中,我會盡可能避免使用全局變量,並且更喜歡使用允許從封裝中受益的類屬性。

3

什麼是一個很好的用例類屬性

案例0類方法都只是類屬性。這不僅僅是技術上的相似之處 - 您可以通過爲它們分配可調參數來在運行時訪問和修改類方法。

案例1.模塊可以很容易地定義幾個類。將關於class A的所有內容封裝爲A...以及將所有關於class B的內容封裝爲B...是合理的。例如,

# module xxx 
class X: 
    MAX_THREADS = 100 
    ... 

# main program 
from xxx import X 

if nthreads < X.MAX_THREADS: ... 

病例2此類擁有大量的可在一個實例進行修改默認屬性。這裏離開屬性成爲'全局默認'的功能是一個功能,而不是bug。

class NiceDiff: 
    """Formats time difference given in seconds into a form '15 minutes ago'.""" 

    magic = .249 
    pattern = 'in {0}', 'right now', '{0} ago' 

    divisions = 1 

    # there are more default attributes 

一個創建NiceDiff的情況下使用現有的或稍加修改的格式,但定位到不同的語言子類可用來實現一個根本不同的方式一些功能重新定義常量:

class Разница(NiceDiff): # NiceDiff localized to Russian 
    '''Из разницы во времени, типа -300, делает конкретно '5 минут назад'.''' 

    pattern = 'через {0}', 'прям щас', '{0} назад' 

你的情況

  • 常數 - 咋我把他們上課。說self.CONSTANT = ...是很奇怪的,所以我認爲沒有很大的危險來打破它們。
  • 默認屬性 - 混合,如上可能會上課,但也可能會去__init__取決於語義。
  • 全球數據結構---如果使用只有類,但也可以去模塊,在任何情況下必須是非常良好的文檔。