2015-05-27 20 views
12

Ich bin bewusst, eine benutzerdefinierte __repr__ oder __add__ Methode (und so weiter) zu erstellen, um das Verhalten von Operatoren und Funktionen zu ändern. Gibt es eine Methodenüberschreibung für len?Ist es möglich, das Verhalten von len() zu ändern?

Zum Beispiel:

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. 

Könnte dies für len, mit einer Liste getan werden? Normalerweise würde es so aussehen:

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

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

Was ist, wenn ich Sucharten aus der Zählung lassen möchte? Wie folgt aus:

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 

Gibt es eine Möglichkeit, dies zu tun aus einer list Unterklasse?

+3

Sie haben bereits gute Antworten, aber im Fall, dass Sie mehr über magische Methoden, um herauszufinden, I [A Guide to Python Magic Methoden] vorschlagen kann (http: // www. rafekettler.com/magicmethods.html);) – swenzel

+0

Dies wird sehr nützlich sein! Danke für das Teilen. @swenzel –

+0

Sie haben eine Liste Unterklasse, keine Liste Oberklasse. – wim

Antwort

19

Ja, implementieren die __len__ method:

def __len__(self): 
    return 42 

Demo:

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

Aus der Dokumentation:

aufgerufen, um die eingebaute Funktion len() zu implementieren. Sollte die Länge des Objekts zurückgeben, eine Ganzzahl >= 0. Auch ein Objekt, das keine __bool__() Methode definiert und deren __len__() Methode gibt Null zurück, wird in einem Booleschen Kontext als falsch angesehen.

Für Ihren speziellen Fall:

>>> 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

Würde 'sum (nicht isinstance (ob, Bar) für ob in self)' ein bisschen sauberer sein? – TigerhawkT3

+0

@ TigerhawkT3: an diesem Punkt müssen Sie erklären, dass Pythons boolescher Typ eine Unterklasse von int ist und dass 'True' einen ganzzahligen Wert von 1 und' False' einen Wert von 0 hat. Es ist nicht immer wert, etwas weniger Code zu haben wenn du das jedes Mal erklären musst. –

+0

Sehr wahr; So hatte ich es nicht gedacht. – TigerhawkT3

7

Ja, so wie Sie bereits entdeckt haben, dass Sie durch die Umsetzung des __repr__ magische Methode das Verhalten eines repr() Funktionsaufruf außer Kraft setzen können, können Sie das Verhalten angeben können aus eine len() Funktionsaufruf durch (was für eine Überraschung) die Umsetzung dann __len__ Magie:

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

ein Pedant würde man erwähnen, dass Sie ändern das Verhalten von len() nicht, Sie ändern das Verhalten Ihrer Klasse. len tut genau das gleiche, was es immer tut, was die Überprüfung eines __len__ Attributs auf dem Argument einschließt.

3

Sie können einfach eine __len__ Methode zu Ihrer Klasse hinzufügen.

class Test: 
    def __len__(self): 
     return 2 

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

Denken Sie daran: Python ist ein dynamisch und Duck Typed Sprache.

Wenn es wie etwas wirkt, das eine Länge haben könnte;

class MyCollection(object): 

    def __len__(self): 
     return 1234 

Beispiel:

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

wenn es nicht, wie es wirkt eine Länge;KABOOM!

class Foo(object): 

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

Beispiel:

>>> 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() 

Von Typing:

Python verwendet Ente eingeben und hat Objekte eingegeben, aber nicht typisierte Variable Namen. Type-Constraints werden bei der Kompilierung nicht überprüft. eher, Operationen an einem Objekt können fehlschlagen, was bedeutet, dass das angegebene Objekt nicht von einem geeigneten Typ ist. Obwohl Python dynamisch typisiert wird, ist er stark typisiert, verbietet Operationen, die nicht gut definiert sind (für Beispiel, Hinzufügen einer Zahl zu einer Zeichenfolge) anstatt stumm versuchen , um ihnen Sinn zu machen.

Beispiel:

>>> 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' 
Verwandte Themen