Detta skapar en PDF som du sedan kan skriva ut. Du kan även spara ner PDFn och skriva ut senare.
Titel på utskriften?
Tack för ditt bidrag
Om vi kan använda det så lägger vi upp det på sidan. Nedan en länk till ditt bidrag om du vill spara det.
Spara som ...
Du sparar ditt skript under detta namn och kan sedan hämta tillbaka det med samma namn.
Läs in
Läs in ett tidigare sparat skript. Obs att du enbart kan läsa in skript i den webbläsare där du sparade skriptet. Vill du kunna läsa in och spara skript oberoende av webbläsare, så behöver du skaffa ett login (enkelt och gratis).
Skicka in bidrag
Föreslå rubrik
Beskriv vad din kod gör
Skapa kort länk
Använd en kort URL för att skicka länk till koden via SMS eller epost. När mottagaren klickar på länken, så öppnas denna webbsida, med din kod och din text. Länken rensas bort automatiskt om den inte används.
Rubrik (frivilligt)
Beskrivning (frivilligt)
Länk (kopiera hela)
Klasser: dundermetoder
Pythons magiska dundermetoder tillhandahåller ett enkelt sätt att få egna skapade objekt att bete sig som de inbyggda objekten i python.
bidrag till polymorfismen
Så, med dundermetoder kan vi kan få våra egna objekt att fungera med, inte bara inbyggda infixa operatorer för t.ex. räknesätt (+ - * / % & |) och jämförelser utan också andra vanliga metoder som används, t.ex. print(), abs(), osv.
Det finns alltså ett gäng fördefinierade metoder med vars hjälp vi kan koppla inbyggda funktioner i python till våra klasser. Om du kör nedan lilla kod, så får du en glimt vilka dundermetoderna är.
print(dir(int))
print(dir(int))
Exempel: komplex
Enklaste sättet få kunskapen att flyga är nog med ett exempel. Låt säga vi skapar en klass för komplexa tal. Typ, såhär:
class komplex:
def __init__(self,r,i):
self.r, self.i = r, i
c1 = komplex(1,1)
c2 = komplex(1,1)
class komplex:
def __init__(self,r,i):
self.r, self.i = r, i
c1 = komplex(1,1)
c2 = komplex(1,1)
Säg att vi vill skapa en utskriftsfunktion så att vi kan titta på innehållet i vår klass. Vi kan t.ex. skapa en metod vi kallar print_komplex().
Den gör jobbet, men hade det inte varit snyggare om vi kunde använda print() ? Vi kan ju använda print till alla möjliga datatyper utan att behöva tänka så mycket, varför inte också vårt komplexa tal?
Det finns en dunder -metod som heter __str__ vilken länkar upp möjligheten göra utskrifter till printfunktionen. Det som gäller är att __str__ skall lämna ifrån sig en sträng. Så vi kan komponera en sträng...
Vidare, vore det inte otroligt snyggt om vi även kunde addera 2 stycken komplexa tal med + -operatorn? Det finns en dunder -metod även för detta, nämligen __add__
Notera ovan att, givet att du definierar metoden __add__, faktiskt kan använda den infixa operatorn + mellan dina egna objekt. Infix betyder att argumenten finns till höger och vänster om metoden. Låt inte detta ögonblick av insikt passera oreflekterat. När vi ändå är på gång, kanske vi kan lägga till subtraktion också. Dundermetoden heter __sub__
Addition, subtraktion, multiplikation m.fl. är infixa operatorer. Det är väldigt snyggt att dessa går att använda. Men det går även att länka andra inbygga icke infixa vanliga funktioner, som t.ex. abs().
Absolutbeloppet, när vi pratar komplexa tal, det är ju som bekant hypotenusan i triangeln där sidorna är realdelen och imaginärdelen. Så vi ger abs(komplex) ett liv genom dundermetoden __abs__
Förutom dundermetoder för infixa operatorer (räknesätten m.fl.) och vissa vanliga funktioner (abs(), print() t.ex.), så finns även dundermetoder för unära operatorer. Exempel på en sådan är ~ (tilde) som används för bitvis invertering. Låt oss använda denna __invert__ för att skapa metoden invers.
Sådär kan vi hålla på. Det finns ganska många dunderfunktioner (se listan nedan).
rmul, radd, rsub, osv.
Om du sneglar på listan av dundermetoder nedan, så upptäcker du att det finns 2 eller 3 versioner av samma dundermetod ibland, där de andra varianterna har ett litet "r" framför sig. R står för right och L står för left om det förekommer. T.ex. av __mul__ (multiplikation) finns även varianten __rmul__ (right -multiplikation).
Låt oss titta lite på hur detta fungerar.
X * Y kommer anropa X.__mul__(Y) om __mul__ existerar i X. Vilken datatyp Y skall ha, det kan du bestämma själv. Det är ju du som skriver __mul__ metoden! Men låt säga det är tvärtom. Du har X * Y men du vill att operationen ska genomföras som Y.__mul__(X) därför att det är argumentet X som är lite speciellt, då måste du använda __rmul__
Exempel: Säg att du skapar en klass för matriser och vill implementera skalär, dvs att du kan multiplicera alla element i matrisen med en viss konstant. Du utför multiplikationen som t.ex. 3 * M, där 3 är en siffra och M är din matris. Då uppkommer direkt situationen att talet du ska multiplicera matrisen med är int eller float medans matrisen är ditt Matris -objekt. Din int eller float har ingen __mul__ -metod i sig som förstår din Matris -klass. Det är först efter X som din matris dyker upp, dvs du har situationen där du vill utföra Y.__mul__(X). Lösning är att sätta multiplikationen under dundermetoden __rmul__. Dvs, python använder dunderfunktionen i klassen Matris. Prova ta bort "r" i __rmul__ och kör koden. Vad får får du för fel? Du får detta fel:
TypeError: unsupported operand type(s) for *: 'int' and 'Matrix'
class Matrix:
def __init__(self, I=None):
if(I!=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
def __str__(self):
s = str(self.h)+'x'+str(self.w)+"\n"
for i in range(self.h):
for j in range(self.w):
s = s + "{:>4}".format(self.I[i][j])
s = s + "\n"
return(s)
def __rmul__(self,K):
C = [[0]*self.w for i in range(self.h)]
for i in range(self.w):
for j in range(self.h):
C[j][i]= self.I[j][i] * K
return(Matrix(C))
T = Matrix( [[1,2],
[3,4],
[5,1]])
U = Matrix( [[3,4],
[4,5],
[2,2]])
print(T)
print("Skala upp med 2")
print(2 * T)
print(U)
print("Skala upp med 3")
print(3 * U)
class Matrix:
def __init__(self, I=None):
if(I!=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
def __str__(self):
s = str(self.h)+'x'+str(self.w)+"\n"
for i in range(self.h):
for j in range(self.w):
s = s + "{:>4}".format(self.I[i][j])
s = s + "\n"
return(s)
def __rmul__(self,K):
C = [[0]*self.w for i in range(self.h)]
for i in range(self.w):
for j in range(self.h):
C[j][i]= self.I[j][i] * K
return(Matrix(C))
T = Matrix( [[1,2],
[3,4],
[5,1]])
U = Matrix( [[3,4],
[4,5],
[2,2]])
print(T)
print("Skala upp med 2")
print(2 * T)
print(U)
print("Skala upp med 3")
print(3 * U)
dundermetoder
Nedan är inte alla metoder, men de flesta.
Matematik
Användning
Utförs
Notis/Returvärde
x + y
x.__add__(y)
x + y
y.__radd__(x)
x - y
x.__sub__(y)
x - y
y.__rsub__(x)
x * y
x.__mul__(y)
x * y
y.__rmul__(x)
x / y
x.__truediv__(y)
x / y
y.__rtruediv__(x)
x % y
x.__mod__(y)
x % y
y.__rmod__(x)
x // y
x.__floordiv__(y)
x // y
y.__rfloordiv__(x)
x ** y
x.__pow__(y)
x ** y
y.__rpow__(x)
Bitvisa operationer
Användning
Utförs
Notis/Returvärde
x @ y
x.__matmul__(y)
Matrismult.
x @ y
y.__rmatmul__(x)
Matrismult.
x & y
x.__and__(y)
Bitvis and
x & y
y.__rand__(x)
Bitvis and
x | y
x.__or__(y)
Bitvis eller
x | y
y.__ror__(x)
Bitvis eller
x ^ y
x.__xor__(y)
Bitvis xor
x ^ y
y.__rxor__(x)
Bitvis xor
x >> y
x.__rshift__(y)
Bitvis shift
x >> y
y.__rrshift__(x)
Bitvis shift
x << y
x.__lshift__(y)
Bitvis shift
x << y
y.__rlshift__(x)
Bitvis shift
-x
x.__neg__()
+x
x.__pos__()
~x
x.__invert__()
x &= y
x.__iand__(y)
x |= y
x.__ior__(y)
x ^= y
x.__ixor__(y)
x >>= y
x.__irshift__(y)
x <<= y
x.__ilshift__(y)
Matematiska funktioner
Användning
Utförs
Notis/Returvärde
divmod(x, y)
x.__divmod__(y)
Tuple (t,n)
abs(x)
x.__abs__()
float
index
x.__index__()
int
round(x)
x.__round__()
Number
math.trunc(x)
x.__trunc__()
Number
math.floor(x)
x.__floor__()
Number
math.ceil(x)
x.__ceil__()
Number
Kortare version av inkrementeringar
Användning
Utförs
Notis/Returvärde
x += y
x.__iadd__(y)
x -= y
x.__isub__(y)
x *= y
x.__imul__(y)
x /= y
x.__itruediv__(y)
x %= y
x.__imod__(y)
x //= y
x.__ifloordiv__(y)
x **= y
x.__ipow__(y)
x @= y
x.__imatmul__(y)
Jämförelseoperationer
Användning
Utförs
Notis/Returvärde
x == y
x.__eq__(y)
bool
x != y
x.__ne__(y)
bool
x < y
x.__lt__(y)
bool
x > y
x.__rt__(y)
bool
x <= y
x.__le__(y)
bool
x >= y
x.__ge__(y)
bool
Konverteringar
Användning
Utförs
Notis/Returvärde
repr(x)
x.__repr__()
str
str(x)
x.__str__()
str
bool(x)
x.__bool__()
bool
int(x)
x.__int__()
int
float(x)
x.__float__()
float
bytes(x)
x.__bytes__()
bytes
complex(x)
x.__complex__()
complex
format(x, s)
x.__format__(s)
str
Kontextoperatorer
Användning
Utförs
Notis/Returvärde
with x as obj:
x.__enter__()
obj objektet
with x as obj:
x.__exit__()
True/False
Iteratorer och listor
Användning
Utförs
Notis/Returvärde
iter(x)
x.__iter__()
Iterator
reversed(x)
x.__reversed__()
Rev. iterator
next(x)
x.__next__()
Nästa iterator item
len(x)
x.__len__()
int
x[a]
x.__getitem__(a)
x[a] = b
x.__setitem__(a, b)
del x[a]
x.__delitem__(a)
a in x
x.__contains__(a)
bool
x[a]
x.__missing__(a)
x.__length_hint__()
int
Övrigt
Användning
Utförs
Notis/Returvärde
x.y
x.__getattribute__('y')
x.y
x.__getattr__('y')
x.y = z
x.__setattr__('y', z)
del x.y
x.__delattr__('y')
dir(x)
x.__dir__()
iterable
t.x
T.x.__get__(t, T)
t.x = y
T.x.__set__(t, y)
del t.x
T.x.__delete__(t)
x = T(a, b)
x.__init__(a, b)
x = T(a, b)
T.__new__(T, a, b)
Ny instans (x)
hash(x)
x.__hash__()
int
del x (ish)
x.__del__()
await x (ish)
x.__await__()
iterator
async with x:
x.__aenter__()
awaitable
async with x:
x.__aexit__()
awaitable
async for a in x:
x.__aiter__()
awaitable
async for a in x:
x.__anext__()
awaitable
lite frågor ...
Vad är en dundermetod?
Ett enkelt sätt att fixa dunder och brak i den egna klassen
Ett sätt att länka upp inbyggda vanliga operatorer och funktioner till den egna klassen
Vad gör __mul__ ?
Vid X * Y anropas Y.__mul__(X), dvs med X som argument.
Vid X * Y anropas X.__mul__(Y), dvs med Y som argument.
Vad gör __rmul__ ?
Vid X * Y anropas Y.__rmul__(X), dvs med X som argument.
Vid X * Y anropas X.__rmul__(Y), dvs med Y som argument.
När vill du använda __rmul__ ?
Om vi har X * Y och det behövs att det är Y som gör __rmul__, därför att X är av en annan typ.
Om vi har X * Y och det behövs att det är X som gör __rmul__, därför att Y är av en annan typ.