What are the multiple uses of '@' (at) symbol in Python?

Pythons '@'-symbol: Dekoratører og mere

08/08/2014

Rating: 4.14 (16664 votes)

I Python er syntaks ikke kun et sæt regler; det er en filosofi, der sigter mod læsbarhed og elegance. Blandt de mange symboler og operatorer findes et, der ofte skaber forvirring for nye udviklere: '@'-symbolet, også kendt som 'snabel-a'. Selvom det kan virke mystisk ved første øjekast, er det et utroligt kraftfuldt værktøj med to meget forskellige, men vigtige, funktioner i moderne Python. Det fungerer som en gateway til et af Pythons mest elegante koncepter, dekoratører, og som en afgørende operator inden for videnskabelig databehandling til matrixmultiplikation. Denne artikel vil afmystificere '@'-symbolet og vise dig, hvordan du kan bruge det til at skrive mere udtryksfuld, ren og effektiv kode.

What is pipe operator in Python?
In Python, the pipe operator can be used to chain functions together, where the result of one function is passed as the argument to the next function in the chain. This allows for a more declarative and linear way of expressing a sequence of operations, making the code easier to read and understand. 2. Usage Methods of the Pipe Operator
Indholdsfortegnelse

Dekoratører: Pythons elegante genvej

Den mest almindelige anvendelse af '@'-symbolet er at anvende en dekoratør. Men hvad er en dekoratør egentlig? I sin kerne er en dekoratør en funktion, der tager en anden funktion som input, tilføjer noget funktionalitet til den, og returnerer den modificerede funktion. Det er en måde at 'indpakke' en funktion for at udvide dens opførsel uden permanent at ændre dens kildekode. Tænk på det som at pakke en gave ind: gaven (din oprindelige funktion) forbliver den samme, men du tilføjer indpakningspapir og et bånd (ekstra funktionalitet) udenpå.

Den traditionelle måde vs. '@'-syntaksen

Før '@'-symbolet blev populært til dette formål, måtte man manuelt anvende en dekoratør. Lad os se på et eksempel:

# Vores dekoratørfunktion def min_dekorator(func): def wrapper(): print("Noget sker før funktionen kaldes.") func() print("Noget sker efter funktionen kaldes.") return wrapper # Vores oprindelige funktion def sig_hej(): print("Hej!") # Den manuelle måde at anvende dekoratøren på sig_hej = min_dekorator(sig_hej) sig_hej() # Kører nu den 'dekorerede' version

Dette virker, men det er ikke særlig læsbart. Man skal læse til bunden af funktionsdefinitionen for at se, at den bliver ændret. Her kommer syntaktisk sukker ind i billedet. '@'-symbolet er en ren genvej, der gør præcis det samme, men på en meget mere deklarativ og læsbar måde:

@min_dekorator def sig_hej(): print("Hej!") sig_hej() # Resultatet er identisk

Ved at placere @min_dekorator lige over def sig_hej(), fortæller vi Python: "Tag funktionen sig_hej og send den gennem min_dekorator, og erstat den oprindelige sig_hej med resultatet." Det er renere, mere direkte og en fundamental del af det, der gør Python-kode 'Pythonic'.

Indbyggede dekoratører, du skal kende

Python kommer med flere indbyggede dekoratører, der løser almindelige problemer. De tre mest almindelige er @property, @classmethod, og @staticmethod.

1. `@property`: For renere API'er

Denne dekoratør lader dig behandle en metode som et attribut. Det er især nyttigt, når du vil have en værdi, der beregnes dynamisk, men som skal tilgås som en simpel variabel. Dette kaldes også en 'getter'.

class Cirkel: def __init__(self, radius): self.radius = radius @property def areal(self): # Beregnes hver gang, det tilgås return 3.14159 * (self.radius ** 2) c = Cirkel(10) print(f"Radius er: {c.radius}") print(f"Arealet er: {c.areal}") # Bemærk: ingen parenteser! Det tilgås som et attribut.

2. `@classmethod`: For smarte konstruktører

En almindelig metode i en klasse modtager instansen (typisk kaldet self) som sit første argument. En klassemetode modtager derimod selve klassen (typisk kaldet cls) som sit første argument. Dette gør dem ideelle til at skabe alternative konstruktører.

Can I use arithmetic operators with std_logic_vector?
Thanks! In VHDL you cannot use arithmetic operators with std_logic_vector. The problem is that the compiler don't know whether you want to use a signed or unsigned vector. To avoid this, you can declare your signals as singed/unsigned or just convert them when you want to multiply them using unsigned(your_slv) or signed(your_slv).
import datetime class Person: def __init__(self, navn, alder): self.navn = navn self.alder = alder @classmethod def fra_fødselsår(cls, navn, fødselsår): nuværende_år = datetime.date.today().year alder = nuværende_år - fødselsår return cls(navn, alder) # Kalder den normale __init__ konstruktør person1 = Person("Alice", 30) person2 = Person.fra_fødselsår("Bob", 1990) print(f"{person1.navn} er {person1.alder} år gammel.") print(f"{person2.navn} er {person2.alder} år gammel.")

3. `@staticmethod`: For logisk organisering

En statisk metode er en funktion, der er placeret inde i en klasse, men som ikke modtager hverken instansen (self) eller klassen (cls) som sit første argument. Den opfører sig som en almindelig funktion, men den 'bor' inde i klassens navnerum. Man bruger den typisk til hjælpefunktioner, der er logisk relateret til klassen, men ikke afhænger af klassens eller instansens tilstand.

class MatematikHjælper: @staticmethod def er_lige(n): return n % 2 == 0 @staticmethod def adder(x, y): return x + y print(MatematikHjælper.er_lige(10)) # True print(MatematikHjælper.adder(5, 3)) # 8

Matrixmultiplikation: '@' i den numeriske verden

Den anden store anvendelse af '@' er helt anderledes og blev introduceret i Python 3.5. Her fungerer '@' som en binær infix-operator til matrixmultiplikation. Før denne tilføjelse var der en del forvirring i det videnskabelige Python-økosystem. Operatoren * blev brugt forskelligt afhængigt af konteksten; nogle gange betød den elementvis multiplikation, andre gange matrixmultiplikation. Dette førte til kode, der var svær at læse og fejlbehæftet.

PEP 465 introducerede @ specifikt til matrixmultiplikation for at skabe en klar og utvetydig syntaks. Dette har gjort numerisk kode i Python, især med biblioteker som NumPy, meget renere.

Sammenligning: `*` (Elementvis) vs. `@` (Matrix)

Forskellen er fundamental for lineær algebra. Lad os se på et eksempel med NumPy.

import numpy as np A = np.array([[1, 2], [3, 4]]) B = np.array([[5, 6], [7, 8]]) # Elementvis multiplikation med * print("Elementvis multiplikation (A * B):") print(A * B) # Resultat: # [[ 1*5 2*6 ] # [ 3*7 4*8 ]] # -> [[ 5 12] # [21 32]] # Matrixmultiplikation med @ print("\nMatrixmultiplikation (A @ B):") print(A @ B) # Resultat: # [[ 1*5+2*7 1*6+2*8 ] # [ 3*5+4*7 3*6+4*8 ]] # -> [[19 22] # [43 50]]

Som det ses, er resultaterne vidt forskellige. Ved at have en dedikeret operator (@) bliver hensigten med koden krystalklar, hvilket reducerer fejl og forbedrer læsbarheden markant.

Under motorhjelmen: `__matmul__` metoden

Ligesom + bruger __add__ og * bruger __mul__, bruger @-operatoren en speciel 'dunder'-metode kaldet __matmul__. Dette betyder, at du kan implementere operatoren for dine egne brugerdefinerede klasser, hvis det giver mening i din kontekst.

What is operator module in Python?
Source code: Lib/operator.py The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python. For example, operator.add(x, y) is equivalent to the expression x+y. Many function names are those used for special methods, without the double underscores.

Ofte Stillede Spørgsmål (FAQ)

Hvad er den primære anvendelse af '@'-symbolet i Python?

Den mest almindelige og udbredte anvendelse er som syntaks for at anvende en dekoratør til en funktion eller metode. Dette er en kernefunktion i sproget, som bruges i utallige frameworks og biblioteker til at tilføje funktionalitet som logging, caching, adgangskontrol og meget mere.

Hvornår blev '@' introduceret til matrixmultiplikation?

Denne funktionalitet blev officielt tilføjet i Python version 3.5 efter godkendelsen af Python Enhancement Proposal (PEP) 465. Det var en direkte respons på behovet for en klarere syntaks i det videnskabelige computing-fællesskab.

Kan jeg oprette mine egne dekoratører?

Absolut! At skrive dine egne dekoratører er en avanceret, men utrolig kraftfuld teknik. Enhver funktion, der tager en funktion som argument og returnerer en funktion, kan fungere som en dekoratør.

Hvorfor bruge `@property` i stedet for en almindelig metode?

Det primære formål er at skabe en renere og mere intuitiv API (Application Programming Interface) for din klasse. Når en bruger af din klasse skal hente en værdi, er det mere naturligt at skrive `objekt.værdi` end `objekt.hent_værdi()`. `@property` giver dig det bedste fra begge verdener: en simpel attribut-lignende adgang, men med logikken fra en metode bag kulisserne.

Opsummering: Mestring af '@'-symbolet

Selvom det kan virke som et simpelt tegn, er '@' et symbol med dobbelt betydning og stor kraft i Python. Det repræsenterer en af sprogets mest elegante funktioner i form af dekoratører, som giver os mulighed for at ændre og udvide adfærd på en ren og genanvendelig måde. Samtidig har det løst et langvarigt problem inden for numerisk databehandling ved at levere en utvetydig operator til matrixmultiplikation. At forstå og mestre begge anvendelser af '@'-symbolet er et vigtigt skridt på vejen til at skrive mere avanceret, læsbar og effektiv Python-kode.

Hvis du vil læse andre artikler, der ligner Pythons '@'-symbol: Dekoratører og mere, kan du besøge kategorien Teknologi.

Go up