2009-08-09 15 views
12

Interesuje mnie dyskusja na temat atrybutów klas w Pythonie. Na przykład, co jest dobrym przykładem użycia dla atrybutów klas? W przeważającej części nie mogę wymyślić przypadku, w którym atrybut klasy jest lepszy niż użycie atrybutu poziomu modułu. Jeśli to prawda, to po co je mieć?Python Class vs. Module Attributes

Problem z nimi związany polega na tym, że omyłkowe pomylenie wartości atrybutu klasy jest prawie zbyt łatwe, a następnie "globalna" wartość przekształciła się w atrybut instancji lokalnej.

Zapraszam do komentowania jak można obsługiwać następujące sytuacje:

  1. stałych używanych przez klasy i/lub podklasy. Może to obejmować klucze słownikowe lub indeksy "magicznej liczby", które nigdy się nie zmienią, ale możliwa jest potrzeba jednorazowej inicjalizacji.
  2. Domyślny atrybut klasy, który w rzadkich przypadkach był aktualizowany dla specjalnego wystąpienia klasy.
  3. Globalna struktura danych używana do reprezentowania wewnętrznego stanu klasy współużytkowanej między wszystkimi instancjami.
  4. Klasa, która inicjalizuje wiele domyślnych atrybutów, na które nie mają wpływu argumenty konstruktora.

Niektóre Podobne posty:
Difference Between Class and Instance Attributes

+0

powinna być wspólnota wiki – SilentGhost

Odpowiedz

7

# 4: I nigdy użycie klasy atrybutów zainicjować domyślne atrybuty instancji (te, które zazwyczaj umieszczone w __init__). Na przykład:

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

i nigdy:

class Obj(object): 
    users = 0 

Dlaczego? Ponieważ jest to niezgodne: nie robić to, co chcesz, kiedy przypisać niczego innego jak niezmiennego obiektu:

class Obj(object): 
    users = [] 

powoduje listy użytkowników, aby być współużytkowane przez wszystkich obiektów, które w tym przypadku nie jest potrzebne. Mylące jest dzielenie ich na atrybuty klas i przypisania w zależności od ich typu, dlatego zawsze umieszczam je wszystkie w __init__, które i tak uważam za jaśniejsze.


Co do reszty, generalnie nadaję klasie wartości w klasie.Nie chodzi o to, że globale są "złe" - nie są tak duże, jak w niektórych językach, ponieważ są one wciąż ograniczone do modułu, chyba że sam moduł jest zbyt duży - ale jeśli zewnętrzny kod chce mieć do nich dostęp, warto mieć wszystkie istotne wartości w jednym miejscu. Na przykład, w module.py:

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

, a następnie:

from module import Obj 

try: 
    o = Obj() 
    o.go() 
except o.Exception: 
    print "error" 

Oprócz pozwalając podklasy, aby zmienić wartość (co nie jest zawsze chciał tak), to znaczy, nie mam pracowicie importować nazwy wyjątków i kilka innych rzeczy potrzebnych do korzystania z Obja. "z modułu importu Obj, ObjException, ..." szybko staje się męczący.

2

atrybuty klasy są często używane w celu umożliwienia nadrzędne domyślne w podklasach. Na przykład BaseHTTPRequestHandler ma stałe klasy sys_version i server_version, z których ostatnia przyjmuje wartość "BaseHTTP/" + __version__. SimpleHTTPRequestHandler przesłania wersję serwera na "SimpleHTTP/" + __version__.

+0

Jednak metoda dostępu do atrybutu klasy byłaby czynnikiem, gdyby to działało, czy nie. Kolejny powód, dla którego atrybuty klas są niebezpieczne. – cmcginty

+0

Co "metoda dostępu"? cls.version, self.version, getattr, wszystkie dadzą właściwą odpowiedź. * Zdefiniuj w klasie, aby przesłonić * działa równie dobrze dla danych jak dla kodu - tak, Casey, dlaczego uważasz, że to niebezpieczne dla danych, ale dobrze dla kodu ?! –

+0

Użycie wartości Class.value zamiast self.value w metodzie dostępu do atrybutu uniemożliwi nadpisanie.Czasami jest to pożądany przypadek, innym razem nie. – cmcginty

1

Hermetyzacja to dobra zasada: jeśli atrybut znajduje się wewnątrz klasy, a nie w zasięgu globalnym, daje to dodatkowe informacje osobom czytającym kod.

W twoich sytuacjach 1-4 unikałbym tak dużo, jak tylko mogę, i wolałbym używać atrybutów klasowych, które pozwalają korzystać z enkapsulacji.

3

co jest dobrym przypadek użycia dla atrybutów klasy

Case 0. metody klasy są tylko atrybuty klasy. To nie tylko podobieństwo techniczne - możesz uzyskać dostęp do metod klasowych w czasie wykonywania, modyfikując je, przypisując do nich kalki.

Przypadek 1. Moduł może z łatwością zdefiniować kilka klas. Rozsądnie jest zamknąć wszystko, co dotyczy: class A w A... i wszystko o class B w . Na przykład,

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

# main program 
from xxx import X 

if nthreads < X.MAX_THREADS: ... 

Przypadek 2. Ta klasa ma wiele atrybutów domyślnych, które mogą być modyfikowane w instancji. Tutaj możliwość pozostawienia atrybutu jako "globalnej wartości domyślnej" jest funkcją, a nie błędem.

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 

Jeden tworzy instancję NiceDiff wykorzystać istniejące lub nieznacznie zmodyfikowany formatowanie, ale lokalizator na inny język podklas klasy do wdrożenia niektórych funkcji w zupełnie inny sposób i przedefiniować stałe:

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

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

Twoje przypadki:

  • stałe - wy s, postawiłem je na lekcje. Dziwne jest powiedzenie self.CONSTANT = ..., więc nie widzę dużego ryzyka, aby je przekręcić.
  • Domyślny atrybut - mieszany, jak wyżej, może przejść do klasy, ale może również przejść do __init__ w zależności od semantyki.
  • Globalna struktura danych --- przechodzi do klasy, jeśli jest używana przez klasę tylko, ale może również przejść do modułu, w każdym przypadku musi być bardzo dobrze napisana.