2015-05-27 13 views
12

Jestem świadomy tworzenia niestandardowej metody __repr__ lub __add__ (i tak dalej), aby zmodyfikować zachowanie operatorów i funkcji. Czy istnieje nadpisanie metody dla len?Czy można zmodyfikować zachowanie len()?

Na przykład:

class Foo: 
    def __repr__(self): 
     return "A wild Foo Class in its natural habitat." 

foo = Foo() 

print(foo)   # A wild Foo Class in its natural habitat. 
print(repr(foo)) # A wild Foo Class in its natural habitat. 

można to zrobić za len z listy? Normalnie wyglądałoby to tak:

foo = [] 
print(len(foo)) # 0 

foo = [1, 2, 3] 
print(len(foo)) # 3 

Co zrobić, jeśli chcę pozostawić typy wyszukiwania poza policzeniem? Tak:

class Bar(list): 
    pass 

foo = [Bar(), 1, ''] 
print(len(foo)) # 3 

count = 0 
for item in foo: 
    if not isinstance(item, Bar): 
     count += 1 

print(count)  # 2 

Czy istnieje sposób to zrobić z poziomu list podklasy?

+3

Masz już dobre odpowiedzi, ale w przypadku, gdy chcesz dowiedzieć się więcej o magicznych sposobach mogę zasugerować [Przewodnik Pythona Magicznych Metod] (http: // www. rafekettler.com/magicmethods.html);) – swenzel

+0

To przyda się całkiem sporo! Dziękuję za udostępnienie. @ swenzel –

+0

Masz podklasę listy, a nie nadklasę listy. – wim

Odpowiedz

19

Tak, wdrożenie __len__ method:

def __len__(self): 
    return 42 

Demo:

>>> class Foo(object): 
...  def __len__(self): 
...   return 42 
... 
>>> len(Foo()) 
42 

Z dokumentacji:

Powołani do wdrożenia wbudowaną funkcję len(). Powinna zwrócić długość obiektu, liczbę całkowitą >= 0. Ponadto obiekt, który nie definiuje metody __bool__() i którego metoda __len__() zwraca zero, jest uważany za fałszywy w kontekście Boolean.

dla konkretnego przypadku:

>>> class Bar(list): 
...  def __len__(self): 
...   return sum(1 for ob in self if not isinstance(ob, Bar)) 
... 
>>> len(Bar([1, 2, 3])) 
3 
>>> len(Bar([1, 2, 3, Bar()])) 
3 
+0

Czy "suma (nie isinstance (ob, Bar) dla ob w siebie)" być nieco czystsze? – TigerhawkT3

+0

@ TigerhawkT3: w którym momencie musisz wyjaśnić, że typ boolowski Pythona jest podklasą int i że 'True' ma wartość całkowitą 1, a' False' wartość 0. Nie zawsze warto mieć trochę mniej kodu kiedy musisz to wyjaśniać za każdym razem. –

+0

Bardzo prawdziwe; Nie myślałem o tym w ten sposób. – TigerhawkT3

7

Tak, tak jak już odkrył, że można zmienić zachowanie połączenia repr() funkcji poprzez wdrożenie magiczną metodę __repr__ można określić zachowanie z wezwanie len() funkcja wdrażając (niespodzianka), a następnie __len__ magia:

>>> class Thing: 
...  def __len__(self): 
...   return 123 
...  
>>> len(Thing()) 
123 

pedant może wspomnieć, że nie modyfikujesz zachowania len(), modyfikujesz zachowanie swojej klasy. len po prostu robi to samo, co zawsze, co obejmuje sprawdzanie atrybutu __len__.

3

Możesz po prostu dodać do swojej klasy metodę __len__.

class Test: 
    def __len__(self): 
     return 2 

a=Test() 
len(a) # --> 2 
5

Pamiętaj: Python jest dynamicznie i Duck Typed język.

Jeśli działa jak coś, co może mieć długość;

class MyCollection(object): 

    def __len__(self): 
     return 1234 

przykład:

>>> obj = MyCollection() 
>>> len(obj) 
1234 

jeżeli nie zachowują się jak to ma długość;KABOOM!

class Foo(object): 

    def __repr___(self): 
     return "<Foo>" 

Przykład:

>>> try: 
...  obj = Foo() 
...  len(obj) 
... except: 
...  raise 
... 
Traceback (most recent call last): 
    File "<stdin>", line 3, in <module> 
TypeError: object of type 'Foo' has no len() 

Od Typing:

Python używa kaczka wpisywanie i obiekty wpisane ale bez typu zmiennych nazwy. Ograniczenia typu nie są sprawdzane podczas kompilacji; raczej operacje na obiekcie mogą się nie udać, co oznacza, że ​​dany obiekt nie jest odpowiedniego typu. Pomimo tego, że jest napisane dynamicznie, Python jest mocno napisany, zabraniając operacji, które nie są dobrze zdefiniowane (na przykład, dodając liczbę do ciągu znaków), a nie w milczeniu próbując uzyskać ich sens z .

Przykład:

>>> x = 1234 
>>> s = "1234" 
>>> x + s 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'int' and 'str' 
Powiązane problemy