2010-01-29 18 views
112

Powiel możliwe:
What is a clean, pythonic way to have multiple constructors in Python?Wiele konstruktorów w python?

Czy nie jest możliwe zdefiniowanie wielu konstruktorów w Pythonie, z różnych podpisów? Jeśli nie, jaki jest ogólny sposób obejścia tego?

Na przykład, powiedzmy, że chciał zdefiniować klasę City

chciałbym móc powiedzieć someCity = City() lub someCity = City("Berlin"), gdzie pierwszy właśnie daje wartość domyślną nazwę, a druga definiuje go.

+2

każ mi myśleć o tym mowa - http://stackoverflow.com/questions/682504/what-is-a-clean-pythonic-way-to-have-multiple -konstruktorów-w-pythonach – Gant

+0

Najlepsze: [Jak przeciążyć metodę '__init__' opartą na typie argumentu?] (https://stackoverflow.com/questions/141545/how-to-overload-init-method-based-on- argument-type) –

Odpowiedz

143

W przeciwieństwie do Java, nie można definiować wielu konstruktorów. Można jednak zdefiniować wartość domyślną, jeśli nie została przekazana.

def __init__(self, city="Berlin"): 
    self.city = city 
2

Najprostszym sposobem jest poprzez argumentów kluczowych:

class City(): 
    def __init__(self, city=None): 
    pass 

someCity = City(city="Berlin") 

Jest to dość podstawowe rzeczy, może spojrzeć na the python docs?

+0

literówki w komentarzach; również, nie o to pytał - pytał o włączanie typów, po prostu dawał zły przykład. – pavpanchekha

+1

@pavpanchekha: dokładnie o to pytano. z wyjątkiem oczywiście braku "self". – SilentGhost

+5

@Jack, twój przykład tak naprawdę nie przechowuje 'miasta' gdziekolwiek, więc dla początkującego może to być dość myląca odpowiedź. –

2

Na przykład dałeś, wartości domyślne zastosowanie:

class City: 
    def __init__(self, name="Default City Name"): 
     ... 
    ... 

W ogóle, masz dwie opcje:

1) Czy if - elif bloki oparte na typ:

def __init__(self, name): 
    if isinstance(name, str): 
     ... 
    elif isinstance(name, City): 
     ... 
    ... 

2) Używaj kaczych liter --- to znaczy zakładaj, że użytkownik twojej klasy jest na tyle inteligentny, że używa go poprawnie. Zazwyczaj jest to preferowana opcja.

+0

@Ghost Wartości domyślne .... um ... Myślę, że to wszystko. Punkt wzięty. Dlaczego ja to głosowałem? Ah, głos jest za stary, żeby się teraz zmienić. –

140

Jeśli podpisy różnią się jedynie liczby argumentów wykorzystaniem domyślnych argumentów jest właściwy sposób to zrobić. Jeśli chcesz móc przekazywać różne argumenty w postaci , spróbuję uniknąć podejścia opartego na isinstance wspomnianego w innej odpowiedzi, zamiast używać argumentów słów kluczowych. Jeśli użycie argumentów tylko słów kluczowych staje się nieporęczne, możesz połączyć je z metodami klasy (kod bzrlib lubi to podejście). To jest po prostu głupi przykład, ale mam nadzieję, że masz pomysł:

class C(object): 

    def __init__(self, fd): 
     # Assume fd is a file-like object. 
     self.fd = fd 

    @classmethod 
    def fromfilename(cls, name): 
     return cls(open(name, 'rb')) 

# Now you can do: 
c = C(fd) 
# or: 
c = C.fromfilename('a filename') 

uwaga Wszystkie te classmethods jeszcze przejść przez ten sam __init__, ale przy użyciu classmethods może być znacznie wygodniejsze niż konieczności pamiętania co kombinacje argumentów kluczowych do pracy __init__.

Najlepiej unikać, ponieważ pisanie kaczych pysków sprawia, że ​​trudno jest określić, jaki obiekt został faktycznie przekazany. Na przykład: jeśli chcesz wziąć nazwę pliku lub obiektu podobnego do pliku, nie możesz użyć isinstance(arg, file), ponieważ istnieje jest wiele obiektów podobnych do plików, które nie mają podklasy file (jak te zwrócone z urllib lub StringIO, lub ...). Zazwyczaj lepszym rozwiązaniem jest, aby osoba dzwoniąca wyraźnie informowała cię, jaki rodzaj obiektu miał na myśli, używając różnych argumentów słów kluczowych.

+0

Jak mówisz, jest to świetne podejście, jeśli musisz przekazywać różnego rodzaju argumenty. W takich przypadkach używam bardzo prostego '__init__' i tworzę więcej niż jedną metodę klasy dla każdego przypadku. – zekel

2

Jack M.ma rację, zrób to w ten sposób:

>>> class City: 
...  def __init__(self, city=None): 
...   self.city = city 
...  def __repr__(self): 
...   if self.city: return self.city 
...   return '' 
... 
>>> c = City('Berlin') 
>>> print c 
Berlin 
>>> c = City() 
>>> print c 

>>> 
Powiązane problemy