2010-09-04 11 views
8

Czy pyton ma naśladować przeciążanie metod jak w statycznie napisanych językach? Mam przez to na myśli pisanie funkcji, która sprawdza typy jej argumentów i zachowuje się inaczej w oparciu o te typy.Czy to Pythonic naśladuje przeciążanie metody?

Oto przykład:

class EmployeeCollection(object): 
    @staticmethod 
    def find(value): 
     if isinstance(value, str): 
      #find employee by name and return 
     elif isinstance(value, int): 
      #find employee by employee number and return 
     else: 
      raise TypeError() 
+0

Chyba zapomniałeś aby dodać 'self' jako pierwszy parametr –

+0

Właściwie miało to być metodą statyczną. Zaktualizowałem to teraz. – hwiechers

Odpowiedz

13

Niezbyt pythonowy, wyjątkiem Być może w 2.6 lub lepsza, jeśli wszystkie kontrole polegają na nowych klas streszczenie bazowych, które są przewidziane w części dokładnie w celu ułatwienia takiego używania. Jeśli kiedykolwiek zdecydujesz się na wpisanie do klasy konkretnej, wtedy znasz powodujesz, że twój kod jest kruchy i ogranicza jego użycie.

Na przykład sprawdzenie, czy masz instancję numbers.Integral, nie jest takie złe - to nowe ABC istnieje w dużej części, aby ułatwić takie sprawdzanie. Sprawdzanie, czy masz instancję int, jest katastrofą, wykluczającą inne rodzaje liczb całkowitych, zupełnie bezcelowe: nigdy nie sprawdzaj konkretnych klas!

Struny są trudnym przypadkiem, ale klasa abstrakcyjna basestring (nie jedna z nowych rodzajów ABC) jest możliwa. Trochę zbyt restrykcyjne, ale jeśli używasz innych ABC, to może to być trochę skomplikowane, jeśli naprawdę musisz. Zdecydowanie niestr - dlaczego kiedykolwiek wykluczyć unicode?!

13

Niezupełnie, ponieważ można stracić możliwość korzystania z typów, które są nie-całkiem-że-ale-close-wystarczy. Utwórz zamiast tego dwie osobne metody (find_by_name() i find_by_number()).

+0

-1, teraz po prostu statycznie kodujesz typy w nazwy swoich metod - niezbyt dynamiczne! A co jeśli masz 5 różnych parametrów, które mogą być ciągiem lub liczbą? Czy tworzysz 32 różne metody? – Gabe

+3

Jeśli masz 5 argumentów, które mogą być ciągiem lub liczbą, to masz większe problemy z architekturą (i być może głębszy problem, którego nie może pomóc żadne forum tworzenia oprogramowania ...). –

+0

Powinieneś mieć różne nazwy metod, ponieważ implikacja z * sprawdzaniem * typu oznacza, że ​​* zachowujesz się inaczej * w zależności od wyniku tej kontroli. Jednak w pythonie wolimy robić rzeczy jawne; jeśli zachowanie jest inne, nazwy metod powinny być różne. Jedynym momentem, w którym rozważałbym łamanie tej reguły pod kątem pythonic byłoby sprawdzanie, czy argument 'jest Brak', aby wywołać rozsądne domyślne zachowanie. – SingleNegationElimination

2

Powiedziałbym, że tak, to jest "Pythonic" I istnieją przykłady, aby to potwierdzić (czego inne plakaty nie podały). Aby odpowiedzieć na to poprawnie, powinny istnieć przykłady!

Od rdzenia Pythona:

  • string.startswith() Akceptuje albo łańcuch lub krotki (strun).
  • string.endswith()

W pymongo:

  • find_one() przyjmuje albo obiektem dict do wyszukiwania, albo używać innego inny obiekt jako id.

Niestety nie wiem więcej, ale myślę, że istnieje WIELE przykładów metod, które zachowują się inaczej w zależności od podanych parametrów. To jest część piękna nie narzucania typów.

+1

-1 typechecking to __never__ pythonic. Sprawdź interfejsy, ale nie wpisz. zakres, w którym typechecking występuje w bibliotece standardowej, należy traktować jako niedociągnięcie, a nie jako przykład. – aaronasterling

+0

@Aaronasterling: Myślę, że "nigdy" jest trochę mocne. A może w metodach "__init__"? Na przykład możesz skonstruować 'bytearray' z innego' bytearray', liczbę całkowitą, liczbę całkowitą, widok 'memory_view', łańcuch znaków lub (tylko Python 3) obiekt' bytes'. Wszystko to od stosunkowo niedawno dodanego typu wbudowanego! –

+0

@Scott: Fakt, że musisz używać sprawdzania typu nie powoduje, że sprawdzanie typu jest już w Pythonie. –

1

Bardziej pythonic sposób na uzyskanie tego rodzaju funkcjonalności jest po prostu spróbuj i używać go w sposób preferowany (cokolwiek to może oznaczać) i jeśli argument nie obsługuje tego, spróbuj alternatywy.

Here'd dwa sposoby, aby to zrobić:

class EmployeeCollection(object): 
    def find(value): 
     try: 
      #find employee by name and return 
     catch: 
      try: 
       #find employee by employee number and return 
      catch: 
       raise TypeError() 

ale to swego rodzaju ohydne. oto jak zwykle to zrobić:

class EmployeeCollection(object): 
    def find(value): 
     if hasattr(value, 'join'): 
      #find employee by name and return 
     elif hasattr(value, '__div__'): 
      #find employee by employee number and return 
     else: 
      raise TypeError() 

W rzeczywistości, faktyczna atrybut bym sprawdzić zależy, co się dzieje w tych komentarzach, ja wolę sprawdzić atrybutu że rzeczywiście wykorzystać.

+0

Powiedziałbym, że twoje pierwsze podejście jest lepsze. – detly

+0

Przekaż argument do konstruktora typu, który Cię interesuje i wychwyć wyjątek. –

+0

Drugi przykład jest bardziej "pythonic", ponieważ sprawdza interfejs, a nie typ. Powiedziałbym więc, że to jest właściwa odpowiedź. Myślę, że niektóre dogmaty o "nigdy nie sprawdzają typu" są trochę głupie. – Amala

5

Nie, sprawdzanie typu nie jest Pythoniczne. Innym rozwiązaniem, jeśli nie lubisz wiele metod jest trzymać się jednej metody, ale korzystać z wielu parametrów:

def find(name=None, employee_number=None): 
    if sum(x != None for x in (name, employee_number)) != 1: 
     #raise exception - exactly one value should be passed in 
    if name is not None: 
     #find employee by name and return 
    if employee_number is not None: 
     #find employee by employee number and return 

Przy zastosowaniu zamiarem jest tak oczywiste, jak z wieloma metodami:

employee1 = x.find(name="John Smith") 
employee2 = x.find(employee_number=90210) 
Powiązane problemy