2012-05-01 31 views
15

Jestem całkiem nowy, Python i masz pytanie dotyczące następujących klas:Najlepsze praktyki przy definiowaniu zmiennych instancji

class Configuration: 
    def __init__(self): 
     parser = SafeConfigParser() 
     try: 
      if parser.read(CONFIG_FILE) is None: 
       raise IOError('Cannot open configuration file') 
     except IOError, error: 
      sys.exit(error) 
     else: 
      self.__parser = parser 
      self.fileName = CONFIG_FILE 

    def get_section(self): 
     p = self.__parser 
     result = [] 
     for s in p.sections(): 
      result.append('{0}'.format(s)) 
     return result 

    def get_info(self, config_section): 
     p = self.__parser 
     self.section = config_section 
     self.url = p.get(config_section, 'url') 
     self.imgexpr = p.get(config_section, 'imgexpr') 
     self.imgattr1 = p.get(config_section, 'imgattr1') 
     self.imgattr2 = p.get(config_section, 'imgattr2') 
     self.destination = p.get(config_section, 'destination') 
     self.createzip = p.get(config_section, 'createzip') 
     self.pagesnumber = p.get(config_section, 'pagesnumber') 

to jest ok, aby dodać więcej zmiennych instancji w innej funkcji, get_info w tym przykładzie, lub czy najlepiej jest definiować wszystkie zmienne instancji w konstruktorze? Czy nie może to prowadzić do kodu spaghetti, jeśli zdefiniuję nowe zmienne instancji w całym miejscu?

EDYCJA: Używam tego kodu za pomocą prostego skrobaka obrazu. Via get_section Zwracam wszystkie sekcje w pliku konfiguracyjnym, a następnie iteruję je, aby przejść do każdej witryny, z której zbieram obrazy. Dla każdej iteracji wykonuję połączenie z get_section, aby uzyskać ustawienia konfiguracyjne dla każdej sekcji w pliku konfiguracyjnym. Jeśli ktoś może wymyślić inne podejście, będzie dobrze! Dzięki!

+0

http://stackoverflow.com/questions/2964230/python-how-should-i-make-instance-variables-available –

+0

"Jaźń.__parser = None' powinno być ustawione na początku '__init __()'. Powód jest taki, że '__init __()' jest nazywany pierwszym mentodem * istniejącego * obiektu. Jeśli analizator składni nie odczyta pliku konfiguracyjnego i zgłosi wyjątek, wyjątek może zostać przechwycony w innym miejscu (program może nie zostać zakończony). Następnie obiekt klasy 'Configuration' nadal istnieje, a późniejsze' get_info() 'spowoduje, że instancja * AttributeError: Configuration nie ma atrybutu" __parser ". – pepr

+0

@pepr Czy powinienem przeczytać odpowiedź, że powinienem dodać 'self .__ parser = None' na początku' __init __. Py' lub czy sugerujesz przenieść inicjalizację parsera z '__init __. Py' do innej funkcji? – happygoat

Odpowiedz

11

pewno zadeklarować wszystkie zmienne instancji w __init__. Aby tego nie zrobić, zwiększa się złożoność i potencjalne niespodziewane skutki uboczne.

Aby zapewnić alternatywny punkt widzenia z David Hall w zakresie dostępu, jest to od Google Python style guide.

Access Control:

If an accessor function would be trivial you should use public variables instead of accessor functions to avoid the extra cost of function calls in Python. When more functionality is added you can use property to keep the syntax consistent

On the other hand, if access is more complex, or the cost of accessing the variable is significant, you should use function calls (following the Naming guidelines) such as get_foo() and set_foo(). If the past behavior allowed access through a property, do not bind the new accessor functions to the property. Any code still attempting to access the variable by the old method should break visibly so they are made aware of the change in complexity.

From PEP8

For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.

Note 1: Properties only work on new-style classes.

Note 2: Try to keep the functional behavior side-effect free, although side-effects such as caching are generally fine.

Note 3: Avoid using properties for computationally expensive operations; the attribute notation makes the caller believe that access is (relatively) cheap.

Python nie jest Java/C# i ma bardzo silne pomysłów, jak mogłyby wyglądać i powinno być napisane. Jeśli kodujesz pythona, ma to sens, aby wyglądał jak pyton. Inne osoby będą mogły łatwiej zrozumieć Twój kod, a także lepiej zrozumiesz inny kod Pythona.

+1

+1, ponieważ zgadzam się z filozofią "Wszyscy jesteśmy dorosłymi tutaj" w Pythonie. Moją główną wołowiną są zajęcia, w których musisz wiedzieć, aby wywołać określoną funkcję, aby wprowadzić klasę w prawidłowy stan. –

+0

@DavidHall W zeszłorocznym pycon "Stop writing classes" była naprawdę ciekawa rozmowa, oto wątek wiadomości hakerskich, który ma dobrą dyskusję na ten temat. Zarówno wątek, jak i wideo są warte przeczytania. http://news.ycombinator.com/item?id=3717715 –

+0

Pozdrawiam - będę wyglądać. Jak możesz prawdopodobnie powiedzieć, że jestem programistą C++/C#, który zna jakiegoś pytona, więc dyskusje takie jak ta są świetne do czytania. –

5

Byłbym faworyzował ustawianie wszystkich zmiennych instancji w konstruktorze nad funkcjami takimi jak get_info(), które są wymagane do wprowadzenia klasy w prawidłowy stan.

Z publicznymi zmiennymi instancji, które są tworzone tylko za pomocą wywołań metod, takich jak get_info(), tworzysz klasę, która jest nieco wykorzystywana w polu minowym.

Jeśli martwisz się, że masz określone wartości konfiguracyjne, które nie zawsze są potrzebne i są kosztowne do obliczenia (co prawdopodobnie jest powodem, dla którego masz get_info(), co pozwala na odroczone wykonanie), wtedy albo rozważałbym refaktoryzację tego podzbioru. config na drugą klasę lub wprowadzając properties lub funkcje, które zwracają wartości.

Właściwości lub funkcje stylu zachęcają użytkowników klasy do przejścia przez zdefiniowany interfejs i ulepszenia enkapsulacji .

Po utworzeniu enkapsulacji zmiennych instancji, dajesz sobie możliwość zrobienia czegoś więcej niż po prostu wyrzucenie wyjątku NameError - możesz ewentualnie zadzwonić pod numer get_info() lub wysłać niestandardowy wyjątek.


1. Nie można zapewnić 100% hermetyzacji z Python od prywatnych zmiennych instancji oznaczone czołowego podwójnego podkreślenia są tylko prywatne umownie

+0

Nie widzę korzyści dla właściwości nad publicznymi zmiennymi instancji. Możesz po prostu uczynić wszystko publiczną zmienną instancji, a jeśli później będziesz potrzebował wykonać coś innego niż tylko ustawienie/otrzymanie wartości, możesz zawsze przekonwertować ją na własność. – interjay

+0

Dobra uwaga - moim głównym problemem z publicznymi zmiennymi instancji jest tworzenie ich w funkcjach takich jak get_info sprawia, że ​​niepotrzebnie trudno używać klas. Ale ty i Andrew Barret przenieśliście mnie, aby edytować moją odpowiedź na dotyk, podkreślając konstruktorów. –