Pythonsyntaks og semantikk - Python syntax and semantics
Den syntaks av programmeringsspråket Python er et sett med regler som definerer hvordan et Python-programmet vil bli skrevet og tolket (av både runtime-systemet og ved menneskelige lesere). Python -språket har mange likheter med Perl , C og Java . Imidlertid er det noen klare forskjeller mellom språkene.
Designfilosofi
Python ble designet for å være et svært lesbart språk. Den har et relativt ryddig visuelt oppsett og bruker engelske søkeord ofte der andre språk bruker tegnsetting . Python har som mål å være enkel og konsistent i utformingen av syntaksen, innkapslet i mantraet "Det skal være en - og helst bare en - åpen måte å gjøre det", fra Zen of Python .
Dette mantraet er bevisst i motsetning til Perl og Ruby -mantraet, " det er mer enn én måte å gjøre det på ".
Stikkord
Python har 35 søkeord eller reserverte ord ; de kan ikke brukes som identifikatorer .
andasassertasyncawaitbreakclasscontinuedefdelelifelseexceptFalsefinallyforfromglobalifimportinislambdaNonenonlocalnotorpassraisereturnTruetrywhilewithyield
- Merknader
Innrykk
Python bruker mellomrom for å avgrense kontrollflytblokker (etter off-side-regelen ). Python låner denne funksjonen fra forgjengeren ABC : i stedet for tegnsetting eller søkeord bruker den innrykk for å indikere kjøring av en blokk .
På såkalte "gratisformat" -språk-som bruker blokkstrukturen som er hentet fra ALGOL-blir blokkblokker med kode satt av med seler ( { }) eller søkeord. I de fleste kodingskonvensjoner for disse språkene innrykker programmerere koden konvensjonelt i en blokk, for å visuelt skille den fra den omkringliggende koden.
En rekursiv funksjon navngitt foo, som sendes en enkelt parameter , xog hvis parameteren er 0, vil en annen funksjon bli kalt barog ellers ringe baz, passere xog også kalle seg rekursivt, som passerer x-1som parameteren, kan implementeres slik i Python :
def foo(x):
if x == 0:
bar()
else:
baz(x)
foo(x - 1)
og kan skrives slik i C med K & R innrykkstil :
void foo(int x)
{
if (x == 0) {
bar();
} else {
baz(x);
foo(x - 1);
}
}
Python gir mandat til en konvensjon som programmerere på språk i ALGOL -stil ofte følger.
Feil innrykket kode kan bli lest av en menneskelig leser på en annen måte enn den ville blitt tolket av en kompilator eller tolk. Dette eksemplet illustrerer en feil som ble introdusert ved feil innrykk:
def foo(x):
if x == 0:
bar()
else:
baz(x)
foo(x - 1)
Her, i motsetning til fooeksemplet ovenfor , er funksjonsanropet foo(x - 1)på den siste linjen feilaktig innrykket for å være utenfor if/ elseblokken. Dette vil føre til at den alltid blir utført, selv når den xer 0, noe som resulterer i en endeløs rekursjon .
Selv om både mellomrom og tabulatortegn godtas som former for innrykk og flere mellomrom kan brukes, anbefales mellomrom og 4 mellomrom (som i denne artikkelen) anbefales og er langt den mest brukte. Det er ikke tillatt å blande mellomrom og faner på påfølgende linjer i samme kildekodefil med Python 3 fordi det kan skape feil som er vanskelige å se, siden mange verktøy ikke skiller mellomrom og faner visuelt.
Datastrukturer
Siden Python er et dynamisk skrevet språk , bærer Python -verdier, ikke variabler, typeinformasjon. Dette har implikasjoner for mange aspekter av måten språket fungerer på.
Alle variablene i Python inneholder referanser til objekter, og disse referansene overføres til funksjoner; en funksjon kan ikke endre verdien av variable referanser i sin kallfunksjon (men se nedenfor for unntak). Noen mennesker (inkludert Guido van Rossum selv) har kalt denne parameteroverføringsplanen "call by object reference". En objektreferanse betyr et navn, og den passerte referansen er et "alias", dvs. en kopi av referansen til det samme objektet, akkurat som i C/ C ++ . Objektets verdi kan endres i den kalt funksjonen med "alias", for eksempel:
>>> alist = ['a', 'b', 'c']
>>> def my_func(al):
... al.append('x')
... print(al)
...
>>> my_func(alist)
['a', 'b', 'c', 'x']
>>> alist
['a', 'b', 'c', 'x']
Funksjon my_funcendret verdien av alistmed det formelle argumentet al, som er et alias av alist. Ethvert forsøk på å operere på aliaset i seg selv vil imidlertid ikke ha noen effekt på det opprinnelige objektet. I Python er ikke-innerste-lokale og ikke-erklærte-globale tilgjengelige navn alle aliaser.
Blant dynamisk tastede språk er Python moderat typekontrollert. Implisitt konvertering er definert for numeriske typer (så vel som booleans ), så man kan multiplisere et komplekst tall med et helt tall (for eksempel) uten eksplisitt casting. Imidlertid er det ingen implisitt konvertering mellom for eksempel tall og strenger ; en streng er et ugyldig argument for en matematisk funksjon som forventer et tall.
Basetyper
Python har et bredt spekter av grunnleggende datatyper. Ved siden av konvensjonelt heltall og flytende aritmetikk, støtter det transparent aritmetikk med vilkårlig presisjon , komplekse tall og desimaltall .
Python støtter et stort utvalg av strengoperasjoner. Strenger i Python er uforanderlige , så en strengoperasjon, for eksempel en substitusjon av tegn , som i andre programmeringsspråk kan endre strengen på plass , returnerer en ny streng i Python. Ytelseshensyn presser noen ganger på for å bruke spesielle teknikker i programmer som endrer strenger intensivt, for eksempel å bare kombinere karakterarrayer i strenger etter behov.
Samlingstyper
En av de veldig nyttige aspektene ved Python er konseptet med samlingstyper (eller containertyper ) . Generelt er en samling et objekt som inneholder andre objekter på en måte som lett kan refereres til eller indekseres . Samlinger kommer i to grunnleggende former: sekvenser og tilordninger .
De ordnede sekvensielle typene er lister (dynamiske matriser ), tupler og strenger. Alle sekvenser indekseres posisjonelt ( 0 til og med lengde - 1 ), og alle unntatt strenger kan inneholde alle typer objekter, inkludert flere typer i samme sekvens. Både strenger og tupler er uforanderlige, noe som gjør dem til perfekte kandidater for ordbokenøkler (se nedenfor). Lister, derimot, er foranderlige; elementer kan settes inn, slettes, endres, legges til eller sorteres på plass .
Kartlegging er derimot (ofte uordnet) typer implementert i form av ordbøker som "kartlegger" et sett med uforanderlige nøkler til tilsvarende elementer (omtrent som en matematisk funksjon). For eksempel kan man definere en ordbok som har en streng "toast"tilordnet heltallet 42eller omvendt. Nøklene i en ordbok må være av en uforanderlig Python -type, for eksempel et heltall eller en streng, for under hetten blir de implementert via en hashfunksjon . Dette gir mye raskere oppslagstid, men krever at nøkler ikke endres.
Ordbøker er sentrale for det indre av Python, ettersom de er kjernen i alle objekter og klasser: kartleggingene mellom variabelnavn (strenger) og verdiene som navnene refererer til, er lagret som ordbøker (se Objektsystem ). Siden disse ordbøkene er direkte tilgjengelige (via et objekts __dict__attributt), er metaprogrammering en grei og naturlig prosess i Python.
Et sett samling type er en unindexed, uordnet samling som ikke inneholder duplikater, og implementerer satt teoretiske operasjoner som union , kryss , forskjell , symmetrisk forskjell , og delsett testing. Det er to typer sett: setog frozensetden eneste forskjellen er at den setkan forandres og frozenseter uforanderlig. Elementer i et sett må være hashable. Således kan for eksempel a frozensetvære et element i en vanlig setmens det motsatte ikke er sant.
Python tilbyr også omfattende samling manipulerende evner som innebygd inneslutningskontroll og en generisk iterasjonsprotokoll.
Objektsystem
I Python er alt et objekt, selv klasser. Klasser, som objekter, har en klasse, som er kjent som deres metaklasse . Python støtter også flere arv og mixins .
Språket støtter omfattende introspeksjon av typer og klasser. Typer kan leses og sammenlignes - typer er forekomster av type. Attributtene til et objekt kan trekkes ut som en ordbok.
Operatører kan overbelastes i Python ved å definere spesielle medlemsfunksjoner - for eksempel ved å definere en metode som er navngitt __add__på en klasse, lar en bruke +operatøren på objekter i den klassen.
Bokstavelig
Strenger
Python har forskjellige typer strengbokstaver .
Vanlige strengbokstaver
Enten enkle eller doble anførselstegn kan brukes til å sitere strenger. I motsetning til i Unix- skallspråk , fungerer Perl- eller Perl-påvirkede språk som Ruby eller Groovy , enkle anførselstegn og doble anførselstegn identisk, det vil si at det ikke er noen strenginterpolasjon av $ foo- uttrykk. Imidlertid kan interpolering utføres på forskjellige måter: med "f-strings" (siden Python 3.6), ved hjelp av formatmetoden eller den gamle % string-formatoperatøren.
For eksempel Perl -setningen:
print "I just printed $num pages to the printer $printer\n"
tilsvarer noen av disse Python -setningene:
print(f"I just printed {num} pages to the printer {printer}")
print("I just printed {} pages to the printer {}".format(num, printer))
print("I just printed {0} pages to the printer {1}".format(num, printer))
print("I just printed {num} pages to the printer {printer}".format(num=num, printer=printer))
print("I just printed %s pages to the printer %s" % (num, printer))
print("I just printed %(num)s pages to the printer %(printer)s" % {"num": num, "printer": printer})
Flerlinjet strengbokstav
Det er også flerlinjestrenger, som begynner og slutter med en serie på tre enkle eller doble anførselstegn og fungerer som her dokumenter i Perl og Ruby .
Et enkelt eksempel med variabel interpolasjon (ved bruk av formatmetoden) er:
print("""Dear {recipient},
I wish you to leave Sunnydale and never return.
Not Quite Love,
{sender}
""".format(sender="Buffy the Vampire Slayer", recipient="Spike"))
Rå strenger
Til slutt kommer alle de tidligere nevnte strengtypene i " rå " varianter (angitt ved å plassere en bokstavelig r før åpningssitatet), som ikke gjør omvendt skråstrek-interpolasjon og derfor er veldig nyttige for vanlige uttrykk ; sammenligne "@-quote" i C# . Rå strenger ble opprinnelig inkludert spesielt for vanlige uttrykk. På grunn av begrensninger i tokenizeren kan det hende at råstrenger ikke har et bakoverstrekk. Å lage en rå streng som holder en Windows -bane som slutter med en skråstrek krever en rekke forskjellige løsninger (vanligvis ved å bruke skråstreker i stedet for bakoverstrekk, siden Windows godtar begge deler).
Eksempler inkluderer:
>>> # A Windows path, even raw strings cannot end in a backslash
>>> r"C:\Foo\Bar\Baz\"
File "<stdin>", line 1
r"C:\Foo\Bar\Baz\"
^
SyntaxError: EOL while scanning string literal
>>> dos_path = r"C:\Foo\Bar\Baz\ " # avoids the error by adding
>>> dos_path.rstrip() # and removing trailing space
'C:\\Foo\\Bar\\Baz\\'
>>> quoted_dos_path = r'"{}"'.format(dos_path)
>>> quoted_dos_path
'"C:\\Foo\\Bar\\Baz\\ "'
>>> # A regular expression matching a quoted string with possible backslash quoting
>>> re.match(r'"(([^"\\]|\\.)*)"', quoted_dos_path).group(1).rstrip()
'C:\\Foo\\Bar\\Baz\\'
>>> code = 'foo(2, bar)'
>>> # Reverse the arguments in a two-arg function call
>>> re.sub(r'\(([^,]*?),([^ ,]*?)\)', r'(\2, \1)', code)
'foo(2, bar)'
>>> # Note that this won't work if either argument has parens or commas in it.
Sammenkopling av tilstøtende strengbokstaver
Strenge bokstaver (ved å bruke muligens forskjellige sitatkonvensjoner) som vises sammenhengende og kun atskilt med mellomrom (inkludert nye linjer), er tillatt og er samlet i en enkelt lengre streng. Og dermed
title = "One Good Turn: " \
'A Natural History of the Screwdriver and the Screw'
tilsvarer
title = "One Good Turn: A Natural History of the Screwdriver and the Screw"
Unicode
Siden Python 3.0 er standard tegnsett UTF-8 både for kildekoden og tolken. I UTF-8 håndteres unicode-strenger som tradisjonelle byte-strenger. Dette eksemplet vil fungere:
s = "Γειά" # Hello in Greek
print(s)
Tall
Numeriske konstanter i Python er av den normale typen, for eksempel 0, -1, 3.4, 3.5e-8.
Python har heltall med vilkårlig lengde og øker lagringsstørrelsen automatisk etter behov. Før Python 3 var det to typer integrerte tall: tradisjonelle heltall med faste størrelser og "lange" heltall av vilkårlig størrelse. Konverteringen til "lange" heltall ble utført automatisk når det var nødvendig, og dermed trengte programmereren vanligvis ikke å være klar over de to integraltypene. I nyere språkversjoner er skillet helt borte, og alle heltall oppfører seg som heltall med vilkårlig lengde.
Python støtter normale flytende tall, som opprettes når en prikk brukes i bokstavelig (f.eks. 1.1), Når et heltall og et flytende punktnummer brukes i et uttrykk, eller som et resultat av noen matematiske operasjoner ("sann divisjon" via den /operatør, eller eksponentiering med en negativ eksponent).
Python støtter også komplekse tall innfødt. Komplekse tall er angitt med Jeller jendelsen, f.eks 3 + 4j.
Lister, tupler, sett, ordbøker
Python har syntaktisk støtte for opprettelse av containertyper.
Lister (klasse list) er foranderlige sekvenser av elementer av vilkårlige typer, og kan opprettes enten med den spesielle syntaksen
a_list = [1, 2, 3, "a dog"]
eller ved bruk av normal objektopprettelse
a_second_list = list()
a_second_list.append(4)
a_second_list.append(5)
Tupler (klasse tuple) er uforanderlige sekvenser av gjenstander av vilkårlige typer. Det er også en spesiell syntaks for å lage tuples
a_tuple = 1, 2, 3, "four"
a_tuple = (1, 2, 3, "four")
Selv om tupler opprettes ved å skille elementer med kommaer, er hele konstruksjonen vanligvis pakket i parentes for å øke lesbarheten. En tom tupel er betegnet med ().
Sett (klasse set) er beholdere med hashbare varer av vilkårlige typer, uten duplikater. Varene er ikke bestilt, men setter støtte iterasjon over elementene. Syntaksen for settopprettelse bruker krøllete parenteser
some_set = {0, (), False}
Pythonsett er veldig mye som matematiske sett , og støtter operasjoner som settkryss og forening . Python har også en frozensetklasse for uforanderlige sett, se samlingstyper .
Ordbøker (klasse dict) er mutable mappings som knytter nøkler og tilsvarende verdier. Python har spesiell syntaks for å lage ordbøker ( {key: value})
a_dictionary = {"key 1": "value 1", 2: 3, 4: []}
Ordbokssyntaksen ligner den angitte syntaksen, forskjellen er tilstedeværelsen av kolon. De tomme bokstavelig {}resulterer i en tom ordbok heller enn et tomt sett, som i stedet opprettet ved hjelp av ikke-bokstave konstruktør: set().
Operatører
Aritmetikk
Python inkluderer +, -, *, /( "true divisjon") //( gulv divisjon), %( modulus ), og **( eksponensieringen ) operatører, med sine vanlige matematiske forrang .
I Python 3 x / yutfører den "sann divisjon", noe som betyr at den alltid returnerer en flottør, selv om begge deler xog yer heltall som deler seg jevnt.
>>> 4 / 2
2.0
og //utfører heltallsinndeling eller etasjedeling , og returnerer gulvet i kvotienten som et heltall.
I Python 2 (og de fleste andre programmeringsspråk), med mindre det er eksplisitt forespurt, x / yutførte heltallsdeling , og returnerte en float bare hvis begge inngangene var en flyter. Fordi Python er et dynamisk tastet språk, var det imidlertid ikke alltid mulig å fortelle hvilken operasjon som ble utført, noe som ofte førte til subtile feil, noe som førte til introduksjonen av //operatøren og endringen i /operatorens semantikk i Python 3.
Sammenligningsoperatører
Sammenligningsoperatorene, det vil si ==, !=, <, >, <=, >=, is, is not, inog not inbrukes på alle slags verdier. Tall, strenger, sekvenser og tilordninger kan alle sammenlignes. I Python 3 har forskjellige typer (for eksempel a strog an int) ikke en konsekvent relativ rekkefølge. Selv om det var mulig å sammenligne om en streng var større enn eller mindre enn et heltall i Python 2, ble dette ansett som en historisk design-finurlighet og ble til slutt fjernet i Python 3.
Kjedede sammenligningsuttrykk som a < b < char omtrent den betydningen de har i matematikk, snarere enn den uvanlige betydningen som finnes på C og lignende språk. Vilkårene evalueres og sammenlignes i rekkefølge. Operasjonen har kortslutningssemantikk , noe som betyr at evalueringen garantert vil stoppe så snart en dom er klar: hvis den a < ber falsk, cblir den aldri vurdert, ettersom uttrykket umulig kan være sant lenger.
For uttrykk uten bivirkninger, a < b < ctilsvarer a < b and b < c. Imidlertid er det en vesentlig forskjell når uttrykkene har bivirkninger. a < f(x) < bvil evaluere f(x)nøyaktig en gang, mens a < f(x) and f(x) < bvil evaluere det to ganger hvis verdien av aer mindre enn f(x)og en gang ellers.
Logiske operatører
I alle versjoner av Python, boolske operatorer behandle nullverdier eller tomme verdier som "", 0, None, 0.0, [], og {}som falsk, mens i den generelle behandling av ikke-tomme, ikke-null verdier som sann. De boolske verdiene Trueog Falseble lagt til språket i Python 2.2.1 som konstanter (underklasse fra 1og 0) og ble endret til å være fullstendige søkeord i Python 3. De binære sammenligningsoperatorene som ==og >returnerer enten Trueeller False.
De boolske operatørene andog orbruker minimal evaluering . For eksempel y == 0 or x/y > 100vil aldri heve et divider-på-null-unntak. Disse operatørene returnerer verdien av den siste operanden som ble evaluert, i stedet for Trueeller False. Dermed (4 and 5)evaluerer uttrykket til 5, og (4 or 5)evaluerer til 4.
Funksjonell programmering
Som nevnt ovenfor er en annen styrke ved Python tilgjengeligheten av en funksjonell programmeringsstil . Som det kan forventes, gjør dette arbeidet med lister og andre samlinger mye mer greit.
Forståelser
En slik konstruksjon er listeforståelsen , som kan uttrykkes med følgende format:
L = [mapping_expression for element in source_list if filter_expression]
Bruke listeforståelse for å beregne de fem første effektene av to:
powers_of_two = [2**n for n in range(1, 6)]
Den Quicksort Algoritmen kan uttrykkes elegant (om enn lite effektiv måte) ved hjelp av liste oppfattelser:
def qsort(L):
if L == []:
return []
pivot = L[0]
return (qsort([x for x in L[1:] if x < pivot]) +
[pivot] +
qsort([x for x in L[1:] if x >= pivot]))
Python 2.7+ støtter også settforståelser og ordboksforståelser.
Førsteklasses funksjoner
I Python er funksjoner førsteklasses objekter som kan opprettes og passeres dynamisk.
Pythons begrensede støtte for anonyme funksjoner er lambdakonstruksjonen. Et eksempel er den anonyme funksjonen som kvadrerer inputene, kalt med argumentet 5:
f = lambda x: x**2
f(5)
Lambdas er begrenset til å inneholde et uttrykk i stedet for utsagn , selv om kontrollstrømmen fortsatt kan implementeres mindre elegant i lambda ved å bruke kortslutning, og mer idiomatisk med betingede uttrykk.
Nedleggelser
Python har hatt støtte for leksikalske nedleggelser siden versjon 2.2. Her er en eksempelfunksjon som returnerer en funksjon som tilnærmer derivatet til den gitte funksjonen:
def derivative(f, dx):
"""Return a function that approximates the derivative of f
using an interval of dx, which should be appropriately small.
"""
def function(x):
return (f(x + dx) - f(x)) / dx
return function
Pythons syntaks får noen ganger programmerere på andre språk til å tro at nedleggelser ikke støttes. Variabelt omfang i Python bestemmes implisitt av omfanget der man tildeler variabelen en verdi, med mindre omfang eksplisitt er erklært med globaleller nonlocal.
Vær oppmerksom på at nedleggelsen av et navn til en verdi ikke kan forandres fra funksjonen. Gitt:
>>> def foo(a, b):
... print(f'a: {a}')
... print(f'b: {b}')
... def bar(c):
... b = c
... print(f'b*: {b}')
... bar(a)
... print(f'b: {b}')
...
>>> foo(1, 2)
a: 1
b: 2
b*: 1
b: 2
og du kan se at b, som synlig fra lukkingens omfang, beholder verdien den hadde; den endrede bindingen av bden indre funksjonen forplantet seg ikke ut. Veien rundt dette er å bruke en nonlocal buttalelse i bar. I Python 2 (som mangler nonlocal) er den vanlige løsningen å bruke en foranderlig verdi og endre den verdien, ikke bindingen. For eksempel en liste med ett element.
Generatorer
Introdusert i Python 2.2 som en valgfri funksjon og ferdigstilt i versjon 2.3, er generatorer Pythons mekanisme for lat evaluering av en funksjon som ellers ville returnere en plassforbudende eller beregningsintensiv liste.
Dette er et eksempel for lat å generere primtallene:
from itertools import count
def generate_primes(stop_at=None):
primes = []
for n in count(start=2):
if stop_at is not None and n > stop_at:
return # raises the StopIteration exception
composite = False
for p in primes:
if not n % p:
composite = True
break
elif p ** 2 > n:
break
if not composite:
primes.append(n)
yield n
Når du kaller denne funksjonen, kan den returnerte verdien gjentas omtrent som en liste:
for i in generate_primes(100): # iterate over the primes between 0 and 100
print(i)
for i in generate_primes(): # iterate over ALL primes indefinitely
print(i)
Definisjonen av en generator virker identisk med en funksjon, bortsett fra at søkeordet yieldbrukes i stedet for return. Imidlertid er en generator et objekt med vedvarende tilstand, som gjentatte ganger kan gå inn og forlate samme omfang. Et generatoranrop kan deretter brukes i stedet for en liste eller en annen struktur hvis elementer vil bli iterert over. Når forløkken i eksemplet krever det neste elementet, kalles generatoren og gir neste element.
Generatorer trenger ikke å være uendelige som eksemplet med primtall ovenfor. Når en generator avsluttes, heves et internt unntak som indikerer for enhver ringe kontekst at det ikke er flere verdier. En forsløyfe eller annen iterasjon vil da avsluttes.
Generatoruttrykk
Generatoruttrykk, introdusert i Python 2.4, er lat evalueringsekvivalent til listeforståelser. Ved å bruke primtallgeneratoren i delen ovenfor, kan vi definere en lat, men ikke helt uendelig samling.
from itertools import islice
primes_under_million = (i for i in generate_primes() if i < 1000000)
two_thousandth_prime = islice(primes_under_million, 1999, 2000).next()
Det meste av minnet og tiden som trengs for å generere så mange primtal vil ikke bli brukt før det nødvendige elementet faktisk er tilgjengelig. Dessverre kan du ikke utføre enkel indeksering og kutting av generatorer, men må bruke itertools -modulen eller "rulle dine egne" sløyfer. I kontrast er en listeforståelse funksjonelt ekvivalent, men er grådig i å utføre alt arbeidet:
primes_under_million = [i for i in generate_primes(2000000) if i < 1000000]
two_thousandth_prime = primes_under_million[1999]
Listeforståelsen vil umiddelbart opprette en stor liste (med 78498 elementer, i eksemplet, men midlertidig opprette en liste med primtall under to millioner), selv om de fleste elementene aldri er tilgjengelig. Generatorforståelsen er mer sparsom.
Ordbok og sett forståelse
Mens lister og generatorer hadde forståelser/uttrykk, i Python-versjoner eldre enn 2,7 måtte de andre Python-innebygde samlingstypene (dikter og sett) slås inn ved hjelp av lister eller generatorer:
>>> dict((n, n*n) for n in range(5))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Python 2.7 og 3.0 forenet alle samlingstyper ved å introdusere ordbok og settforståelser, som ligner på listeforståelser:
>>> [n*n for n in range(5)] # regular list comprehension
[0, 1, 4, 9, 16]
>>>
>>> {n*n for n in range(5)} # set comprehension
{0, 1, 4, 9, 16}
>>>
>>> {n: n*n for n in range(5)} # dict comprehension
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Objekter
Python støtter de fleste objektorienterte programmering (OOP) teknikker. Det tillater polymorfisme , ikke bare innenfor et klassehierarki, men også ved andetyping . Ethvert objekt kan brukes til alle typer, og det vil fungere så lenge det har de riktige metodene og attributtene. Og alt i Python er et objekt, inkludert klasser, funksjoner, tall og moduler. Python har også støtte for metaclasses , et avansert verktøy for å forbedre klassens funksjonalitet. Naturligvis støttes arv , inkludert flere arv . Python har svært begrenset støtte for private variabler som bruker navnemangling som sjelden brukes i praksis ettersom informasjon som gjemmer seg blir sett på som lite pytonisk , ved at det antyder at den aktuelle klassen inneholder uestetiske eller dårlig planlagte internt. Slagordet "vi er alle ansvarlige brukere her" brukes for å beskrive denne holdningen.
Som det er tilfelle for moduler, legger klasser i Python ikke en absolutt barriere mellom definisjon og bruker, men stoler heller på brukerens høflighet for ikke å "bryte inn i definisjonen."
- 9. klasser , The Python 2.6 Tutorial (2013)
OOP -doktriner som bruk av tilgangsmetoder for å lese datamedlemmer håndheves ikke i Python. Akkurat som Python tilbyr funksjonelle programmeringskonstruksjoner, men ikke prøver å kreve referansetransparens , tilbyr den et objektsystem, men krever ikke OOP- oppførsel. Videre er det alltid mulig å omdefinere klassen ved hjelp av egenskaper (se Egenskaper ) slik at når en bestemt variabel er angitt eller hentet i ringekode, påkaller den virkelig et funksjonsanrop, slik at spam.eggs = toastdet virkelig kan påkalle spam.set_eggs(toast). Dette opphever den praktiske fordelen med accessor -funksjoner, og det forblir OOP fordi eiendommen eggsblir en legitim del av objektets grensesnitt: den trenger ikke gjenspeile en implementeringsdetalj.
I versjon 2.2 av Python ble klasser i "ny stil" introdusert. Med klasser i ny stil ble objekter og typer forent, noe som tillot underklassering av typer. Selv helt nye typer kan defineres, komplett med tilpasset oppførsel for infix -operatører. Dette gjør at mange radikale ting kan gjøres syntaktisk i Python. En ny metodeoppløsningsordre for flere arv ble også vedtatt med Python 2.3. Det er også mulig å kjøre tilpasset kode mens du får tilgang til eller angir attributter, selv om detaljene i disse teknikkene har utviklet seg mellom Python -versjoner.
Med uttalelse
Den withuttalelsen håndterer ressurser, og tillater brukere å arbeide med Context Manager-protokollen. En funksjon ( __enter__()) kalles når du angir omfang og en annen ( __exit__()) når du forlater. Dette forhindrer å glemme å frigjøre ressursen, og håndterer også mer kompliserte situasjoner som å frigjøre ressursen når et unntak oppstår mens den er i bruk. Kontekstledere brukes ofte med filer, databasetilkoblinger, testcases, etc.
Egenskaper
Egenskaper tillater at spesialdefinerte metoder påkalles på en objektforekomst ved å bruke samme syntaks som brukes for attributtilgang. Et eksempel på en klasse som definerer noen egenskaper er:
class MyClass:
def __init__(self):
self._a = None
@property
def a(self):
return self._a
@a.setter # makes the property writable
def a(self, value):
self._a = value
Beskrivelser
En klasse som definerer ett eller flere av de tre spesielle metoder __get__(self, instance, owner), __set__(self, instance, value), __delete__(self, instance)kan brukes som beskrivelse. Å opprette en forekomst av en deskriptor som et klassemedlem i en andre klasse gjør forekomsten til en egenskap for den andre klassen.
Klasse og statiske metoder
Python tillater opprettelse av klassemetoder og statiske metoder via bruk av @classmethod og @staticmethod dekoratører . Det første argumentet til en klassemetode er klasseobjektet i stedet for selvreferansen til forekomsten. En statisk metode har ikke noe spesielt første argument. Verken forekomsten eller klasseobjektet overføres til en statisk metode.
Unntak
Python støtter (og bruker i stor grad) unntaksbehandling som et middel for å teste for feilforhold og andre "eksepsjonelle" hendelser i et program. Det er faktisk mulig å fange unntaket forårsaket av en syntaksfeil .
Python -stil krever bruk av unntak når en feiltilstand kan oppstå. I stedet for å teste for tilgang til en fil eller ressurs før du faktisk bruker den, er det konvensjonelt i Python å bare gå videre og prøve å bruke den, og få unntaket hvis tilgangen blir avvist.
Unntak kan også brukes som et mer generelt middel for ikke-lokal overføring av kontroll, selv om det ikke er noen feil. For eksempel bruker Mailman- postlisteprogramvaren, skrevet i Python, unntak for å hoppe ut av dypt nestet meldingshåndteringslogikk når en beslutning er tatt om å avvise en melding eller beholde den for moderatorens godkjenning.
Unntak brukes ofte som et alternativ til if-blokken, spesielt i gjengede situasjoner. Et motto som ofte påberopes er EAFP, eller "Det er lettere å be om tilgivelse enn tillatelse", som tilskrives Grace Hopper . Alternativet, kjent som LBYL, eller "Look Before You Leap", tester eksplisitt for forutsetninger.
I dette første kodeeksemplet, etter LBYL -tilnærmingen, er det en eksplisitt kontroll av attributtet før tilgang:
if hasattr(spam, 'eggs'):
ham = spam.eggs
else:
handle_missing_attr()
Denne andre prøven følger EAFP -paradigmet:
try:
ham = spam.eggs
except AttributeError:
handle_missing_attr()
Disse to kodeeksemplene har samme effekt, selv om det vil være ytelsesforskjeller. Når spamhar attributtet eggs, kjører EAFP -prøven raskere. Når spamikke har attributtet eggs(det "eksepsjonelle" tilfellet), kjører EAFP -prøven saktere. Python -profilen kan brukes i spesifikke tilfeller for å bestemme ytelseskarakteristika. Hvis unntakstilfeller er sjeldne, vil EAFP -versjonen ha overlegen gjennomsnittlig ytelse enn alternativet. I tillegg unngår man det hele klassen av time-of-check-til-tid-av-bruk (TOCTTOU) sårbarheter, andre race conditions , og er forenlig med anda typing . En ulempe med EAFP er at den bare kan brukes med uttalelser; et unntak kan ikke fanges opp i et generatoruttrykk, listeforståelse eller lambda -funksjon.
Kommentarer og dokumentasjon
Python har to måter å kommentere Python -kode på. Den ene er ved å bruke kommentarer for å indikere hva en del av koden gjør. Kommentarer på én linje begynner med hash-tegnet ( #) og fortsetter til slutten av linjen. Kommentarer som strekker seg over mer enn én linje oppnås ved å sette inn en flerlinjes streng (med """eller '''som skilletegn i hver ende) som ikke brukes i oppgaven eller på annen måte evalueres, men sitter mellom andre utsagn.
Kommenterer et stykke kode:
import sys
def getline():
return sys.stdin.readline() # Get one line and return it
Kommenterer et stykke kode med flere linjer:
def getline():
return sys.stdin.readline() """this function
gets one line
and returns it"""
Dokstringer (dokumentasjonsstrenger), det vil si strenger som er plassert alene uten tildeling som den første innrykkede linjen i en modul, klasse, metode eller funksjon, setter automatisk innholdet som et attributt __doc__som er navngitt , som er ment å lagre en lesbar beskrivelse av objektets formål, oppførsel og bruk. Den innebygde helpfunksjonen genererer utdata basert på __doc__attributter. Slike strenger kan avgrenses med "eller 'for enkeltlinjestrenger, eller de kan strekke seg over flere linjer hvis de er avgrenset med enten """eller '''som er Pythons notasjon for å spesifisere flerlinjestrenger. Imidlertid angir """stilguiden for språket at trippel doble anførselstegn ( ) er foretrukket for både enkelt- og flerlinjede dokstringer.
Enkelt linje docstring:
def getline():
"""Get one line from stdin and return it."""
return sys.stdin.readline()
Flerlinjes docstring:
def getline():
"""Get one line
from stdin
and return it.
"""
return sys.stdin.readline()
Dokstringer kan være så store som programmereren ønsker og inneholde linjeskift . I motsetning til kommentarer, er dokstrings i seg selv Python -objekter og er en del av den tolkede koden som Python kjører. Det betyr at et program som kjører kan hente sine egne dokumenter og manipulere denne informasjonen, men normal bruk er å gi andre programmerere informasjon om hvordan de kan påberope objektet som blir dokumentert i dokstringen.
Det er tilgjengelige verktøy som kan trekke ut dokumentene fra Python -koden og generere dokumentasjon. Dokstringsdokumentasjon kan også nås fra tolken med help()funksjonen, eller fra skallet med pydoc -kommandoen pydoc.
De doctest standard modul bruker interaksjoner som er kopiert fra Python skall-økter i docstrings for å lage tester, mens docopt modulen bruker dem for å definere alternativer i kommandolinjen.
Funksjonskommentarer
Funksjonskommentarer (hint) er definert i PEP 3107. De tillater vedleggelse av data til argumentene og retur av en funksjon. Oppførselen til merknader er ikke definert av språket, og er overlatt til tredjeparts rammer. For eksempel kan et bibliotek skrives for å håndtere statisk skriving:
def haul(item: Haulable, *vargs: PackAnimal) -> Distance
Dekorerere
En dekoratør er ethvert kallbart Python -objekt som brukes til å endre en funksjon, metode eller klassedefinisjon. En dekoratør passeres det opprinnelige objektet som defineres og returnerer et modifisert objekt, som deretter bindes til navnet i definisjonen. Python -dekoratører ble delvis inspirert av Java -merknader , og har en lignende syntaks; dekoratørsyntaksen er rent syntaktisk sukker , @som brukes som nøkkelord:
@viking_chorus
def menu_item():
print("spam")
tilsvarer
def menu_item():
print("spam")
menu_item = viking_chorus(menu_item)
Dekoratorer er en form for metaprogrammering ; de forbedrer handlingen til funksjonen eller metoden de dekorerer. I eksempelet nedenfor kan det for viking_choruseksempel føre menu_itemtil at det kjøres 8 ganger (se spamskisse ) for hver gang det kalles:
def viking_chorus(myfunc):
def inner_func(*args, **kwargs):
for i in range(8):
myfunc(*args, **kwargs)
return inner_func
Kanonisk bruk av funksjonsdekoratører er for å lage klassemetoder eller statiske metoder , legge til funksjonsattributter, spore , sette for- og etterbetingelser og synkronisering , men kan brukes til langt mer, inkludert eliminering av hale rekursjon , memoisering og til og med forbedre skriving av andre dekoratører.
Dekoratorer kan lenkes ved å plassere flere på tilstøtende linjer:
@invincible
@favourite_colour("Blue")
def black_knight():
pass
tilsvarer
def black_knight():
pass
black_knight = invincible(favourite_colour("Blue")(black_knight))
eller ved å bruke mellomvariabler
def black_knight():
pass
blue_decorator = favourite_colour("Blue")
decorated_by_blue = blue_decorator(black_knight)
black_knight = invincible(decorated_by_blue)
I eksempelet ovenfor, den favourite_colourarkitekt fabrikken tar et argument. Dekoratorfabrikker må returnere en dekoratør, som deretter kalles med objektet som skal dekoreres som argument:
def favourite_colour(colour):
def decorator(func):
def wrapper():
print(colour)
func()
return wrapper
return decorator
Dette vil deretter dekorere black_knightfunksjonen slik at fargen,, "Blue"vil bli skrevet ut før black_knightfunksjonen kjøres. Lukking sikrer at fargeargumentet er tilgjengelig for den innerste innpakningsfunksjonen, selv når den returneres og går utenfor rekkevidde, noe som gjør det mulig for dekoratører å jobbe.
Til tross for navnet er ikke Python -dekoratører en implementering av dekoratormønsteret . Dekoratormønsteret er et designmønster som brukes i statisk tastede objektorienterte programmeringsspråk for å la funksjonalitet legges til objekter under kjøretid; Python-dekoratører legger funksjonalitet til funksjoner og metoder ved definisjonstidspunktet, og er dermed en konstruksjon på et høyere nivå enn dekoratormønsterklasser. Dekoratormønsteret i seg selv er trivielt implementerbart i Python, fordi språket er andetypet , og derfor vanligvis ikke blir sett på som det.
Påskeegg
Brukere av krøllete parentes-språk , for eksempel C eller Java , forventer eller ønsker at Python følger en blokkavgrensningskonvensjon. Brace-avgrenset blokksyntaks har blitt gjentatt forespurt og konsekvent avvist av kjerneutviklere. Python -tolken inneholder et påskeegg som oppsummerer utviklernes følelser om dette problemet. Koden from __future__ import braceshever unntaket SyntaxError: not a chance. Den __future__Modulen brukes vanligvis for å tilveiebringe funksjoner fra fremtidige versjoner av Python.
En annen skjult melding, Zen of Python (et sammendrag av Python designfilosofi ), vises når du prøver import this.
Meldingen Hello world!skrives ut når importoppgaven import __hello__brukes. I Python 2.7 Hello world!skrives det i stedet for det Hello world....
Importering av antigravitymodulen åpner en nettleser til xkcd tegneserie 353 som skildrer en humoristisk fiktiv bruk for en slik modul, ment å demonstrere hvor enkelt Python -moduler muliggjør ekstra funksjonalitet. I Python 3 inneholder denne modulen også en implementering av algoritmen "geohash", en referanse til xkcd tegneserie 426 .
Referanser
Eksterne linker
- Python -opplæring skrevet av forfatteren av Python, Guido van Rossum.