2017-06-27 9 views
0

So in Python 3 kann ich object().__eq__ verwenden. Ich verwende es derzeit als eine mappable Funktion, die lambda x: x is object() entspricht.Python 2 vs Python 3 doppelte Unterstreichungsmethoden

Ich benutze es als Sentinel (als None hätte eine andere Bedeutung als kein Argument).

>>> import sys 
>>> print(sys.version) 
3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] 
>>> object.__eq__ 
<slot wrapper '__eq__' of 'object' objects> 
>>> object().__eq__ 
<method-wrapper '__eq__' of object object at 0x000002CC4E569120> 

Aber in Python 2, das nicht funktioniert:

>>> import sys 
>>> print sys.version 
2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:53:40) [MSC v.1500 64 bit (AMD64)] 
>>> object.__eq__ 
<method-wrapper '__eq__' of type object at 0x0000000054AA35C0> 
>>> object().__eq__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'object' object has no attribute '__eq__' 
>>> dir(object) 
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] 

Warum nicht existiert diese Funktion? Und wie kann ich es emulieren (performant mit Python 2 Kompatibilität)

$ python3 -m timeit "sentinel = object(); tests = [sentinel] * 100 + [None] * 100" "list(filter(sentinel.__eq__, tests))" 
100000 loops, best of 3: 8.8 usec per loop 
$ python3 -m timeit "sentinel = object(); tests = [sentinel] * 100 + [None] * 100; exec('def is_sentinel(x): return sentinel is x', locals(), globals())" "list(filter(is_sentinel, tests))" 
10000 loops, best of 3: 29.1 usec per loop 
+0

Das ist genau der Grund, warum Sie '__dunder__' Methoden wie diese nicht verwenden sollten. Verwenden Sie 'Import-Operator; operator.eq' –

+0

Oder verwenden Sie eigentlich 'Lambda-Ding: Ding ist Sentinel'; Gleichheit ist nicht notwendigerweise Identität. – jonrsharpe

+0

@jonrsharpe Ich benutze buchstäblich 's = object()'. Dafür denke ich, dass Gleichheit als Identität definiert ist. – Artyer

Antwort

3

Wenn Sie eine Funktion wollen Gleichheit gegen einen festen Gegenstand zu testen, ist das

from functools import partial 
from operator import eq 

equals_thing = partial(eq, thing) # instead of thing.__eq__ 

Das von thing.__eq__ etwas anders verhalten wird, weil es auch das andere Argument einen Schuss gibt, um den Vergleich zur Verfügung zu stellen, und es wird NotImplemented nicht zurückgeben.

Falls Sie einen Identitätstest wollen, egal was, verwenden operator.is_ statt operator.eq:

from operator import is_ 

is_thing = partial(is_, thing) 

Wenn Sie tatsächlich das Python 3 Verhalten eines rohen __eq__ Anruf, NotImplemented und alle wollten, dann je nach Typ , müssen Sie es möglicherweise manuell neu implementieren. Für object, würde das sein

lambda x: True if x is thing else NotImplemented 

In Python 2 nicht jedes Objekt definiert ein __eq__, und in der Tat, definiert nicht jedes Objekt, jede Art von Gleichheit Vergleich zu allen, auch den alten Stil __cmp__ . Der Identitätsvergleichs-Fallback für == findet außerhalb der Objektmethode statt.

+0

Ich wusste nicht über 'operator.is_'. Vielen Dank! Ich werde das akzeptieren, wenn es mich lässt. – Artyer

Verwandte Themen