Klasy mogą implementować pewne operacje, które możemy następnie wywoływać
przy użyciu specjalnej składni (np. używając operatorów arytmetycznych,
odwołania do indeksu lub wykrojenia). Do ich definicji używa się metod
o specjalnych nazwach. Mechanizm ten jest stosowanym w Pythonie podejściem do przeciążania
operatorów, które pozwala definiować zachowanie klas w odniesieniu
do operatorów języka. Na przykład, jeśli klasa definiuje metodę o nazwie
__getitem__(), a x jest instancją tej klasy, wówczas
zamiast x[i] możemy użyć x.__getitem__(i)
Poza zaznaczonymi przypadkami, próba wykonania operacji przy braku
odpowiedniej metody spowoduje wystąpienie wyjątku.
Przy tworzeniu implementacji klasy emulującej typ wbudowany, należy ją ograniczyć do zakresu, który ma sens w odniesieniu do modelowanych obiektów. Na przykład, do niektórych sekwencji dobrze pasuje pobieranie pojedynczych elementów, lecz pobieranie wykrojeń może już nie mieć sensu (jako przykład może służyć interfejs NodeList w standardzie W3C DOM).
x.__del__() -- instrukcja del zmniejsza tylko licznik
odwołań do obiektu o jeden, zaś metoda __del__() jest wywoływana
po osiągnięciu przez ten licznik wartości zero.
W pewnych sytuacjach licznik może nigdy nie osiągnąć wartości zero.
Do typowych należą: cykliczne odwołania pomiędzy obiektami (np. lista z
dwukierunkowymi dowiązaniami lub struktura drzewiasta z odwołaniami do ojca i
potomków); odwołanie do obiektu w ramce stosu funkcji, która wyłapała
wyjątek (ramkę utrzymuje przy życiu stan stosu, zapisany w
sys.exc_traceback); odwołanie do obiektu w ramce stosu, w której
wystąpił nieobsłużony wyjątek podczas pracy interaktywnej (ramkę utrzymuje
przy życiu stan stosu zapisany w sys.last_traceback).
Pierwszej sytuacji można uniknąć tylko poprzez jawne przerwanie cykli,
pozostałych zaś, poprzez zapisanie None w sys.exc_traceback lub
sys.last_traceback.
Cykliczne odwołania pomiędzy nieużywanymi obiektami są wykrywane, jeśli
aktywny jest opcjonalny wykrywacz cykli (domyślnie jest on aktywny), jednak
tworzące je obiekty mogą być usunięte tylko, jeśli nie są w ich ramach
używane metody __del__() na poziomie Pythona.
Aby uzyskać więcej informacji na temat sposobu obsługi metody
__del__() przez wykrywacz cykli (oraz na temat wartości
garbage), zajrzyj do dokumentacji
modułu gc.
sys.stderr.
Dodatkowo, jeśli metoda __del__() została wywołana jako odpowiedź
na usunięcie modułu (np. przy zakończeniu pracy programu), inne obiekty
globalne, do których chce się odwoływać __del__() mogą już być
usunięte. Z tego powodu metody __del__() powinny wykonywać
absolutne minimum operacji, wymaganych do zachowania zewnętrznych niezmienników.
Poczynając od wersji 1.5, Python gwarantuje, że globalne obiekty modułu, których nazwy rozpoczynają się
pojedynczym podkreśleniem, są usuwane przed wszystkimi innymi; jeśli nie istnieją
inne odwołania do nich, może to pomóc w zagwarantowaniu, że zaimportowane moduły
są nadal dostępne w chwili wywołania metody __del__().
Metoda ta jest zwykle używana podczas debugowania, ważne więc, aby reprezentacja zawierała pełnię informacji o obiekcie i aby była jednoznaczna.
x<y wywołuje x.__lt__(y),
x<=y wywołuje x.__le__(y),
x==y wywołuje x.__eq__(y),
x!=y oraz x<>y wywołują
x.__ne__(y),
x>y wywołuje x.__gt__(y),
x>=y wywołuje x.__ge__(y).
Metody te mogą zwracać dowolne wartości, lecz jeśli operator porównania
zostanie użyty w kontekście logicznym, zwracana wartość powinna dać się
zinterpretować jako wartość logiczna, w przeciwnym bowiem wypadku wystąpi
wyjątek TypeError.
Zgodnie z konwencją False jest używane w znaczeniu fałszu, zaś True
- w znaczeniu prawdy.
Pomiędzy operatorami porównań nie występują żadne zależności mające charakter
ogólny. Prawdziwość porównania x==y nie musi pociągać za
sobą nieprawdziwości porównania x!=y. Analogicznie, przy
definiowaniu metody __eq__ należy również zdefiniować __ne__, tak
aby operatory zachowywały się w oczekiwany sposób.
Nie istnieją osobne wersje powyższych metod z argumentami zamienionymi miejscami (używanymi, jeśli lewy argument nie obsługuje operacji, natomiast prawy ją obsługuje); jednak metody __lt__() i __gt__() stanowią wzajemnie swoje odwrócenie, podobnie jest z metodami __le__() i __ge__() oraz __eq__() i __ne__().
Argumenty porównań szczegółowych nie są nigdy uzgadniane. Jeśli
metoda porównania szczegółowego nie implementuje operacji dla podanej
pary argumentów, może wygenerować wyjątek NotImplemented.
self < inny, funkcja powinna zwrócić
całkowitą liczbę ujemną, jeśli self == inny - zero, jeśli zaś
self > inny - całkowitą liczbę dodatnią.
Jeśli klasa nie definiuje operacji __cmp__(), __eq__(), ani
__ne__(), jej instancje są porównywane według tożsamości
("adresów") obiektów.
Ważne uwagi na temat tworzenia obiektów, które obsługują własne operacje
porównań i mogą być używane jako klucze w słownikach, odnajdziesz w opisie
metody __hash__().
(Uwaga: ograniczenie, polegające na tym, że wyjątki nie są propagowane
przez metodę __cmp__() zostało zniesione w Pythonie 1.5.)
bool(); powinna zwrócić False lub True, ew.
ich liczbowe odpowiedniki, 0 lub 1.
Jeśli metoda ta nie jest zdefiniowana, wywoływana
jest metoda __len__(). Jeśli klasa nie definiuje i tej metody,
przyjmuje się, że wartością logiczną wszystkich jej instancji jest prawda.
Poprzez zdefiniowanie opisanych poniżej metod możliwa jest zmiana
semantyki dostępu do atrybutów (użycia, przypisania lub usunięcia
x.nazwa dla instancji klas).
self. Parametr nazwa zawiera nazwę atrybutu.
Metoda powinna zwrócić wartość atrybutu lub wygenerować wyjątek
AttributeError.
Zwróćmy uwagę, że jeśli atrybut zostanie odnaleziony w zwykły sposób, metoda __getattr__() nie będzie wywołana. (Występuje tu celowa asymetria pomiędzy __getattr__() a __setattr__().) Jest tak zarówno ze względu na wydajność, jak i dlatego, że w przeciwnym wypadku __setattr__() nie mogłaby w żaden sposób uzyskać dostępu do innych atrybutów instancji. W przypadku zmiennych instancji można zasymulować pełną kontrolę, nie wstawiając do słownika atrybutów instancji żadnych wartości (wstawiając je natomiast wewnątrz innego obiektu). Sposób przejęcia całkowitej kontroli nad dostępem do atrybutów instancji przy klasach w nowym stylu opisano w dalszej części, dotyczącej metody __getattribute__().
Aby dokonać przypisania do atrybutu instancji wewnątrz tej metody, nie należy używać zwykłej instrukcji przypisania ("self.nazwa = wartość"), gdyż spowodowałoby to rekurencyjne wywołanie tej samej metody. Zamiast tego należy bezpośrednio wstawić wartość do słownika atrybutów instancji, np. "self.__dict__[nazwa] = wartość". W przypadku klas w nowym stylu, zamiast bezpośredniego odwoływania się do słownika atrybutów należy wywołać metodę klasy bazowej o tej samej nazwie, np. "obiekt.__setattr__(self, nazwa, wartość)".
Opisane poniżej metody występują wyłącznie w obiektach w nowym stylu.
Poniższe metody mają zastosowanie tylko w przypadkach, gdy instancja
klasy zawierającej metodę (tzw. klasa deskryptora) pojawia się
w słowniku innej klasy w nowym stylu, znanej jako klasa właściciela.
W przedstawionych przykładach określenie "atrybut" odnosi się do
atrybutu, którego nazwa jest kluczem własności w słowniku __dict__
klasy właściciela.
None, jeśli
dostęp do atrybutu występuje poprzez klasę właściciel.
Wynikiem działania metody powinna być (wyliczona) wartość atrybutu
lub wygenerowanie wyjątku AttributeError.
W ogólnym przypadku deskryptor jest atrybutem obiektu definiującym "zachowanie dowiązania", tj. takim, do którego dostęp jest kontrolowany przez metody deskryptora o nazwach: __get__(), __set__() i __delete__(). Jeśli obiekt implementuje którąkolwiek z tych metod, wówczas określa się go mianem deskryptora.
Domyślnym zachowaniem przy dostępie do atrybutu jest jego pobranie, ustawienie lub
usunięcie ze słownika powiązanego z obiektem. Na przykład zapis a.x powoduje
uruchomienie łańcucha poszukiwań, rozpoczynającego się od a.__dict__['x'], po
którym następuje type(a).__dict__['x'] oraz ciąg analogicznych odwołań
dla wszystkich klas bazowych klasy type(a) z pominięciem metaklas.
Jeśli jednak odnaleziona wartość jest obiektem definiującym jedną z metod deskryptora, domyślne zachowanie może zostać zastąpione wywołaniem odpowiedniej metody. Miejsce w łańcuchu poszukiwań, w którym używane są deskryptory, zależy od tego, które metody deskryptora zostały zdefiniowane i w jaki sposób są wywoływane. Należy przy tym podkreślić, że deskryptory są używane tylko przy obiektach lub klasach w nowym stylu (będących pochodnymi klasy object() lub type()).
Punktem wyjścia dla użycia deskryptora jest dowiązanie, a.x.
Sposób, w jaki ustalane są argumenty, zależy od tego, czym jest a:
x.__get__(a).
a.x jest przekształcany na wywołanie:
type(a).__dict__['x'].__get__(a, type(a)).
A.x
jest przekształcany na wywołanie: A.__dict__['x'].__get__(None, A).
a jest instancją klasy super,
wówczas dowiązanie super(B, obiekt).m() powoduje wyszukanie wśród wartości
obj.__class__.__mro__ klasy bazowej A bezpośrednio poprzedzającej
B, a następnie wywołanie deskryptora przy użyciu wyrażenia:
A.__dict__['m'].__get__(obiekt, A).
W przypadku dowiązania do instancji priorytet użycia deskryptorów, w stosunku do innych metod dostępu do atrybutu, zależy od tego, jakie implementuje on metody. Deskryptory opisujące dane definiują metody __get__() oraz __set__(). Deskryptory nie opisujące danych definiują wyłącznie metodę __get__(). Deskryptory opisujące dane biorą zawsze górę nad ponowną definicją atrybutu w słowniku instancji. Z drugiej strony, deskryptory nie opisujące danych mogą zostać nadpisane przez instancje.
Metody Pythona (łącznie ze zdefiniowanymi przy użyciu staticmethod() lub classmethod()) są implementowane jako deskryptory nie opisujące danych. W związku z tym instancje mogą przedefiniowywać i nadpisywać metody, co pozwala różnicować zachowanie poszczególnych instancji tej samej klasy.
Funkcja property() jest zaimplementowana przy użyciu deskryptora opisującego dane, w związku z czym instancje nie mogą modyfikować jej zachowania.
Domyślnie z każdą instancją klasy w starym jak i w nowym stylu związany jest słownik przechowujący jej atrybuty. Powoduje to niegospodarne wykorzystanie pamięci w przypadku obiektów mających niewielką ilość zmiennych poziomu instancji, szczególnie dolegliwe przy tworzeniu dużej liczby instancji.
Domyślne zachowanie można zmienić poprzez ustawienie atrybutu wewnątrz definicji klasy w nowym stylu. Przypisanie atrybutowi __slots__ sekwencji nazw zmiennych poziomu instancji powoduje przydzielenie w każdej instancji ilości miejsca dokładnie odpowiadającej liczbie zmiennych. Oszczędność miejsca polega na uniknięciu tworzenia słownika __dict__ dla każdej instancji.
Uwagi na temat użycia atrybutu __slots__
'__dict__'.
Zmieniono w wersji 2.3:
W poprzedniej wersji Pythona dodanie do sekwencji __slots__
atrybutu '__dict__' nie umożliwiało przypisywania nowych atrybutów, które
nie zostały jawnie wymienione wśród nazw zmiennych poziomu instancji.
'__weakref__'.
Zmieniono w wersji 2.3:
W poprzedniej wersji Pythona dodanie do sekwencji __slots__
atrybutu '__weakref__' nie umożliwiało obsługi słabych odwołań.
Domyślnie klasy w nowym stylu są tworzone przy użyciu funkcji type().
Definicja klasy jest umieszczana w odrębnej przestrzeni nazw, zaś do nazwy klasy
dowiązywany jest wynik wywołania type(nazwa, bazowe, słownik).
Jeśli na etapie odczytywania definicji klasy, zdefiniowana jest zmienna __metaclass__, to zamiast funkcji type() zostanie wywołana wartość tej zmiennej. Pozwala to na tworzenie klas lub funkcji monitorujących lub zmieniających proces tworzenia klas. Do możliwych zmian należą:
nazwa, bazowe oraz słownik.
Obiekt wywoływany jest w zastępstwie wbudowanej funkcji type()
na etapie tworzenia klasy.
Dodano w wersji 2.2.
Właściwa metaklasa jest wybierana zgodnie z poniższymi regułami ustalającymi priorytety postępowania:
dict['__metaclass__'], w roli metaklasy
używana jest jej wartość.
Potencjalne obszary zastosowań metaklas są nieograniczone. Wykorzystane już pomysły obejmują rejestrowanie zdarzeń w dzienniku, sprawdzanie interfejsu, automatyczne delegowanie, automatyczne tworzenie właściwości, klasy pośredniczące, szkielety, jak też automatyczne synchronizowanie/blokowanie zasobów.
x(arg1, arg2, ...) jest odpowiednikiem
x.__call__(arg1, arg2, ...).
Poniższe metody mogą być zdefiniowane w celu zaemulowania obiektów
kontenerowych. Kontenery są zwykle sekwencjami (np. listy czy krotki) lub
odwzorowaniami (np. słowniki) lecz obiekty mogą również reprezentować
również inne kontenery.
Pierwszy zbiór metod jest używany do
emulowania albo sekwencji albo odwzorowań; różnica polega na tym, że w
przypadku sekwencji dopuszczalnymi kluczami powinny być wartości całkowite
k, takie, że 0 <= k < N, gdzie N jest
długością sekwencji, lub też obiekty wykrojenia, definiujące zakresy
elementów (w celu zachowania zgodności wstecz można również zdefiniować
metodę __getslice__() (patrz niżej), obsługującą proste wykrojenia,
bez obsługi wykrojeń złożonych). W przypadku odwzorowań zaleca się również
udostępnianie metod keys(), values(), items(),
has_key(), get(), clear(), setdefault(),
iterkeys(), itervalues(), iteritems(),
pop(), popitem(), copy() oraz
update() z zachowaniem semantyki zbliżonej do tej, która obowiązuje
przy standardowych obiektach słownikowych Pythona. Moduł UserDict
oferuje klasę DictMixin, pomocną przy tworzeniu tych metod w oparciu
o zaimplementowany zestaw metod bazowych: __getitem__(), __setitem__(),
__delitem__() oraz keys().
Podobnie, sekwencje
zmienne powinny udostępniać metody append(), count(),
index(), extend(), insert(), pop(), remove(),
reverse() oraz sort(), o działaniu zbliżonym do
standardowych obiektów listowych Pythona. Ponadto, typy sekwencyjne powinny
implementować operacje dodawania (w znaczeniu doklejenia) oraz mnożenia
(w znaczeniu powtórzenia) poprzez definicje opisanych poniżej metod
__add__(), __radd__(), __iadd__(),
__mul__(), __rmul__() oraz __imul__().
Nie należy jednak w takich przypadkach definiować __coerce__(), ani
innych metod, odpowiadających wyłącznie operatorom liczbowym.
Zaleca się, aby metodę __contains__() implementowały zarówno
odwzorowania, jak i sekwencje, co pozwala na efektywne użycie operatora
in. W przypadku odwzorowań in powinien być odpowiednikiem
metody has_key(). Przy sekwencjach powinien on powodować
przeszukanie kolejnych jej wartości. Zaleca się ponadto, aby zarówno
odwzorowania, jak i sekwencje implementowały metodę __iter__(), pozwalającą
na efektywne przebieganie (iterowanie) przez elementy kontenera. Przy odzworowaniach
metoda __iter__() powinna być równoważnikiem metody iterkeys().
Przy sekwencjach powinna ona przebiegać przez kolejne elementy sekwencji.
self[klucz].
W przypadku typów sekwencyjnych powinny być akceptowane klucze
całkowitoliczbowe oraz obiekty wykrojenia. Zwróćmy uwagę, że specjalna interpretacja indeksów ujemnych (jeśli
klasa ma emulować typ sekwencyjny) należy do samej metody
__getitem__().
Jeśli klucz jest niewłaściwego typu, może zostać wygenerowany wyjątek
TypeError; jeśli wartość nie należy do zbioru dopuszczalnych
indeksów sekwencji (po specjalnej interpretacji wartości ujemnych),
powinien zostać wygenerowany wyjątek IndexError.
Notka:
Działanie instrukcji for zależy od faktu, że
przy niedopuszczalnych indeksach zostanie wygenerowany wyjątek
IndexError, gdyż w ten sposób wykrywany jest koniec sekwencji.
self[wartość].
Odnoszą się do niej te same uwagi, co do __getitem__().
Metoda powinna być implementowana tylko w odniesieniu do obiektów
odwzorowawczych, które pozwalają na podmienianie wartości przypisanych
kluczom ew. na dodawanie nowych kluczy oraz przy sekwencjach, których
elementy można podmieniać. Przy niepoprawnych wartościach klucza powinny być
generowane te same wyjątki, co w przypadku metody __getitem__().
self[klucz].
Odnoszą się do niej te same uwagi, co do __getitem__().
Metoda powinna być implementowana tylko w odniesieniu do obiektów
odwzorowawczych, które pozwalają na usuwanie kluczy oraz przy
sekwencjach, których elementy można usuwać. Przy niepoprawnych
wartościach klucza powinny być generowane te same wyjątki, co w
przypadku metody __getitem__().
Do zaimplementowania tej metody potrzebne są również obiekty iteratorów, które powinny zwracać same siebie. Aby uzyskać więcej informacji na temat obiektów iteratorów, zajrzyj do sekcji "Typy iteratorów" w pozycji Podręcznik programisty Pythona - opis biblioteki standardowej.
Operatory sprawdzania przynależności (in oraz not in) są normalnie implementowane jako iteracja przez elementy sekwencji. Obiekty kontenerowe mogą jednak dostarczać bardziej efektywnych implementacji, definiując poniższą specjalną metodę, która nie wymaga jednocześnie, aby obiekt był sekwencją.
Poniższe opcjonalne metody mogą zostać zdefiniowane celem dokładniejszej emulacji obiektów sekwencyjnych. W przypadku sekwencji niezmiennych należy zdefiniować co najwyżej metodę __getslice__(); przy sekwencjach zmiennych można zdefiniować wszystkie trzy metody.
Wywoływana przy obliczaniu wyrażenia self[i:j].
Zwracany obiekt powinien być tego samego typu, co self.
Brakujące i lub j zastępowane jest odpowiednio przez zero
i sys.maxint.
Jeśli w wykrojeniu zostaną użyte indeksy ujemne, do odpowiednich indeksów
jest dodawana długość sekwencji. Jeśli instancja nie implementuje metody
__len__(), generowany jest wyjątek AttributeError.
Nie daje się żadnych gwarancji, że indeksy po dokonaniu korekty nie będą
nadal ujemne. Ponadto indeksy większe od długości sekwencji nie są
modyfikowane.
Przy braku metody __getslice__() utworzony zostanie obiekt
wykrojenia, a następnie przekazany do metody __getitem__().
self[i:j],
Do i i j odnoszą się te same uwagi, co przy metodzie
__getslice__().
Metoda ta jest przestarzała. Przy braku metody __setslice__()
lub w przypadku użycia rozszerzonego wykrojenia o postaci
self[i:j:k]
zamiast wywołania __setslice__() tworzony jest obiekt wykrojenia, a
następnie przekazywany do metody __setitem__().
self[i:j].
Do i i j odnoszą się te same uwagi, co przy metodzie
__getslice__().
Metoda ta jest przestarzała. Przy braku metody __delslice__()
lub w przypadku użycia rozszerzonego wykrojenia o postaci
self[i:j:k]
zamiast wywołania __delslice__() tworzony jest obiekt wykrojenia, a
następnie przekazywany do metody __delitem__().
Powyższe metody są wywoływane tylko, jeśli zostało użyte pojedyncze wykrojenie z jednym dwukropkiem oraz metoda wykrojenia jest dostępna. W przypadku operacji wykrojenia opartej na rozszerzonym zapisie wykrojenia lub w przypadku braku odpowiedniej metody wywoływana jest metoda __getitem__(), __setitem__() lub __delitem__() z obiektem wykrojenia jako argumentem.
Poniższy przykład pokazuje, w jaki sposób można przygotować program lub moduł tak, aby był zgodny z wcześniejszymi wersjami Pythona (przy założeniu, że metody __getitem__(), __setitem__() oraz __delitem__() dopuszczają obiekty wykrojenia jako argumenty):
class MojaKlasa:
...
def __getitem__(self, indeks):
...
def __setitem__(self, indeks, wartość):
...
def __delitem__(self, indeks):
...
if sys.version_info < (2, 0):
# Metody nie będą zdefiniowane, jeśli wersja jest wcześniejsza od 2.0
def __getslice__(self, i, j):
return self[max(0, i):max(0, j):]
def __setslice__(self, i, j, seq):
self[max(0, i):max(0, j):] = seq
def __delslice__(self, i, j):
del self[max(0, i):max(0, j):]
...
Zwróćmy uwagę na wywołania funkcji max(); są one potrzebne
ze względu na obsługiwanie indeksów ujemnych przed wywoływaniem metod
__*slice__(). W przypadku użycia indeksów ujemnych metody
__*item__() otrzymują je bez zmian, jednak __*slice__()
otrzymują zmodyfikowane wersje. Do każdego indeksu dodawana jest długość
sekwencji (co nie musi jednak dawać wartości nieujemnej); jest to zwyczajowy
sposób obsługi ujemnych indeksów przez wbudowane typy sekwencyjne i przyjmuje
się, że metody __*item__() zachowują się podobnie. Jednak, ponieważ
powinny one już to robić, nie można przekazywać ujemnych indeksów; muszą one
przed przekazaniem do metod __*item__() zostać zawężone do
granic sekwencji.
Wywołanie max(0, i) w wygodny sposób tworzy poprawną wartość.
Opisane poniżej metody mogą być wykorzystywane do emulacji obiektów liczbowych. Jeśli obiekty danego typu nie obsługują pewnych operacji (np. operacji bitowych w przypadku liczb niecałkowitych), odpowiadające im metody należy pozostawić niezdefiniowane.
+, -, *, //, %,
divmod() ,
pow() , **, <<,
>>, &, ^, |).
Na przykład, aby obliczyć wartość wyrażenia x+y,
gdzie x jest instancją klasy ze zdefiniowaną metodą
__add__(), wywoływane jest x.__add__(y).
Metoda __divmod__() powinna być odpowiednikiem użytych jednocześnie
metod __floordiv__() i __mod__(). Nie powinna ona być
powiązana z opisaną dalej metodą __truediv__().
Zwróćmy uwagę, że jeśli obsługiwana ma być trójargumentowa postać
wbudowanej funkcji pow() , to definicja
metody __pow__() powinna dopuszczać opcjonalny trzeci
argument.
/).
Jeśli aktywna jest cecha __future__.division, następuje użycie
metody __truediv__(), w przeciwnym wypadku używana jest
__div__(). Jeśli zdefiniowana jest tylko jedna z tych metod,
to obiekt nie będzie obsługiwał dzielenia w kontekście odmiennym od tego, w
którym jest ona stosowana, (tzw. nie jest wywoływana w zastępstwie druga
metoda). W tym przypadku generowany jest wyjątek TypeError.
+, -, *, /, %,
divmod() ,
pow() , **, <<,
>>, &, ^, |) z operandami
zamienionymi miejscami. Ich wywołanie następuje tylko wtedy, gdy
lewy operand nie obsługuje określonej operacji.
Na przykład, aby obliczyć wartość wyrażenia x-y, gdzie
y jest instancją klasy ze zdefiniowaną metodą __rsub__(),
wywoływane jest y.__rsub__(x).
Zwróćmy uwagę, iż przy trójargumentowym pow() nie nastąpi próba wywołania __rpow__() (reguły uzgadniania
stałyby się zbyt skomplikowane).
+=, -=, *=, /=, %=,
**=, <<=, >>=, &=,
^=, |=). Metody powinny starać się wykonywać operacje
na miejscu (modyfikując self) i zwracać wynik (którym może, ale
nie musi być self). Jeśli dana metoda nie jest zdefiniowana, operacja
modyfikacji wykonywana jest przy użyciu odpowiedniej zwykłej metody.
Na przykład, aby obliczyć wartość wyrażenia x+=y, gdzie
x jest instancją klasy ze zdefiniowaną metodą __iadd__(),
wywoływane jest x.__iadd__(y). Jeśli x jest
instancją klasy bez metody __iadd(), brane są pod uwagę metody
x.__add__(y) oraz y.__radd__(x), podobnie,
jak przy wyrażeniu x+y.
-, +, abs() oraz ~).
None, jeśli konwersja nie jest możliwa.
Jeśli wspólny typ ma być taki sam, jak typ argumentu inny, wygodnie jest
zwrócić None, gdyż interpreter spróbuje dokonać uzgodnienia również na
drugim argumencie (z drugiej strony, jeśli nie można zmienić implementacji drugiego
typu, czasem warto przeprowadzić jego konwersję przy pierwszym).
Zwrócenie wartości NotImplemented jest równoważne zwróceniu None.
W przeszłości sekcja ta opisywała reguły uzgadniania. Wraz z rozwojem języka reguły te stały się jednak zbyt złożone, aby je precyzyjnie zdefiniować, zaś szczegółowe dokumentowanie zachowania konkretnej wersji jednej implementacji nie byłoby zbyt użyteczne. Zamiast tego poniżej zamieszczono więc pewne wskazówki dotyczące uzgadniania. W Pythonie 3.0 uzgadnianie nie będzie obsługiwane.
Jeśli lewy operand operatora % jest napisem lub obiektem Unicode, uzgadnianie nie ma miejsca, a wykonywaną operacją jest operacja formatowania napisu.
Nie zaleca się już definiować operacji uzgadniania. W przypadku operacji na argumentach różnych typów, gdy oba typy nie definiują uzgadniania, operacji przekazywane są pierwotne argumenty.
Klasy w nowym stylu (pochodne po object) nigdy nie wywołują __coerce__() na skutek użycia operatora dwuargumentowego. Jedyną sytuacją, w której jest wywoływana metoda __coerce__() jest jawne użycie wbudowanej funkcji coerce().
W większości przypadków, operator zwracający NotImplemented traktowany
jest tak samo, jak ten, który nie jest w ogóle zaimplementowany.
W kolejnych akapitach zapisy __op__() i __rop__() oznaczają
nazwy metod odpowiadających operatorowi, zaś __iop__ oznacza
odpowiadającą mu metodę wykonującą operację w miejscu. Na przykład, przy
operatorze "+" lewostronnej i prawostronnej odmianie odpowiadają
metody __add__() i __radd__(), zaś __iadd__
odpowiada odmianie wykonującej operację w miejscu.
Przy operacji na obiektach x i y najpier wykonywane jest
x.__op__(y), jeśli odpowiednia metoda nie jest
zaimplementowana lub zwraca NotImplemented, wykonywane jest
y.__rop__(x) is tried. Jeśli ta metoda również nie
jest zaimplementowana lub zwraca NotImplemented, generowany jest
wyjątek TypeError. Występuje jednak pewien wyjątek od tej
zasady:
Wyjątek od powyższej zasady: jeśli lewy operand jest instancją wbudowanego typu lub klasy w nowym stylu, zaś prawy operand jest instancją podklasy tego typu lub klasy, próba użycia metody __rop__() następuje przed użyciem metody __op__(). Dzieje się tak, aby podklasa mogła całkowicie zmienić działanie operatorów dwuargumentowych. Gdyby tego wyjątku nie było, zawsze wywoływana byłaby metoda __op__ lewego argumentu, która akceptuje prawy argument (jeśli oczekiwana jest instancja pewnej klasy, instancja jej podklasy jest zawsze również akceptowana).
Jeśli typ któregokolwiek z operandów definiuje uzgadnianie, jest ono stosowane przed wywołaniem jego metody __op__() lub __rop__(), jednak nie wcześniej. Jeśli operacja uzgadniania da w wyniku obiekt typu różnego od tego, dla którego ją wykonano, część całego procesu jest ponawiana z nowym obiektem.
W przypadku użycia przypisania modyfikującego (np. "+="), gdy
jego lewy operand implementuje metodę __iop__(), jest ona wywoływana
bez uzgadniania. Jeśli jednak nastąpi wykonanie operacji przy użyciu metody
__op__() lub __rop__(), stosowane są zwykłe reguły
uzgadniania.
W przypadku wyrażenia x+y, jeśli x jest sekwencją
implementującą sklejenie, następuje sklejenie dwóch sekwencji.
W przypadku wyrażenia x*y, jeśli jeden z argumentów
jest sekwencją implementującą powielenie sekwencji, zaś drugi jest liczbą
całkowitą (int lub long), następuje powielenie sekwencji.
Operacje porównań szczegółowych (implementowane przez metody __eq__(), itp.) nigdy nie używają uzgodnień. Porównanie trójwartościowe (implementowane przez __cmp__()) używa uzgadniania na tych samych zasadach, co inne operacje dwuargumentowe.
W bieżącej implementacji, wbudowane typy liczbowe int, long i float nie używają uzgadniania, jednak używa go typ complex. Różnica może się objawić po utworzeniu klas pochodnych typów liczbowych. W przyszłości prawdopodobnie typ complex zostanie poprawiony tak, aby nie używał uzgadniania. Wszystkie te typy implementują metodę __coerce__() na potrzeby wbudowanej funkcji coerce().