Скажем, у меня есть произвольный контейнер и запрос, есть ли в нем элемент, см. ниже.
D = {(1, 2): "whatever"}
if (2, 1) in D:
print( "Impossible" )
Что на самом деле происходит с базовым кодом? вызывается ли какая-либо конкретная функция-член, такая как find()?
Более того, могу ли я использовать собственный cmp/хеш? скажем, если я хотел бы сравнить только появление каждого числа в ключе кортежа, как показано в фрагменте кода, что я могу сделать, чтобы добиться этого?
D = {(1, 2, 1): "whatever"}
if (2, 1, 1) in D:
print( "As expected" ) # How to make it happen?
Официальный документ Py будет очень признателен. Я предполагаю, что это довольно фундаментальная информация, но нигде не могу найти официального вступления.
Невозможно напрямую настроить то, что делает любой метод любого встроенного типа. __contains__()
в этом плане ничего особенного. Например. нет возможности напрямую изменить то, что делает int.__add__()
. В CPython вам потребуется отредактировать исходный код C, реализующий этот метод, и перекомпилировать.
Понял, большое спасибо за ответ еще раз.
Вы хотите сказать, что хотели бы, чтобы (2,1,1) было эквивалентно (1,2,1)? Если да, реализуйте __contains__ и сравните в нем отсортированные значения.
Это определено в разделе «Справочник по языку» 6.10.2. Операции по проверке членства; в частности:
Все встроенные последовательности и типы наборов поддерживают это, а также словарь, для которого проверяется, имеет ли словарь заданный ключ. Для таких типов контейнеров, как список, кортеж, набор, замороженный набор, dict или Collections.deque, выражение
x in y
эквивалентноany(x is e or x == e for e in y)
.[…] Для пользовательских классов, определяющих метод
__contains__()
,x in y
возвращаетTrue
, еслиy.__contains__(x)
возвращает истинное значение, иFalse
в противном случае. […]
Под одеялом x in y
вызывает y.__contains__(x)
. Таким образом, поведение полностью зависит от того, как type(y)
реализует специальный __contains__
метод.
>>> class X:
... def __contains__(self, i):
... if i == 4:
... return True
... elif i < 0:
... return "hamburger"
... else:
... return False
...
>>> 3 in X()
False
>>> 4 in X()
True
>>> -4 in X()
True
Последнее может быть удивительным. Оно не возвращается "hamburger"
, но под покровом накладывается другой слой bool()
на то, что __contains__()
на самом деле возвращается.
>>> bool("hamburger")
True
Большое спасибо за быстрый ответ и помощь. Означает ли это, что невозможно настроить встроенный контейнер, а можно только наследовать или инкапсулировать его?