Python-syntax och semantik
Syntaxen för programmeringsspråket Python är den uppsättning regler som definierar hur ett Python-program kommer att skrivas och tolkas ( av både runtime-systemet och av mänskliga läsare). Språket Python har många likheter med Perl , C och Java . Det finns dock vissa tydliga skillnader mellan språken.
Designfilosofi
Python designades för att vara ett mycket läsbart språk. Den har en relativt enkel visuell layout och använder ofta engelska nyckelord där andra språk använder skiljetecken . Python strävar efter att vara enkel och konsekvent i utformningen av sin syntax, inkapslad i mantrat "Det bör finnas ett - och helst bara ett - självklart sätt att göra det", från Zen of Python .
Detta mantra är medvetet emot Perl- och Ruby -mantrat, " det finns mer än ett sätt att göra det" .
Nyckelord
Python har 35 nyckelord eller reserverade ord ; de kan inte användas som identifierare .
och
som
hävda
-
asynkron
-
vänta
ha sönder
klass
Fortsätta
def
del
elif
annan
bortsett från
-
Falsk
till sist
för
från
global
om
importera
i
är
lambda
Ingen
-
icke-lokala
inte
eller
passera
höja
lämna tillbaka
-
Sann
Prova
medan
med
avkastning
Dessutom har Python också 3 mjuka nyckelord . Till skillnad från vanliga hårda sökord är mjuka sökord reserverade ord endast i de begränsade sammanhang där det skulle vara syntaktisk meningsfullt att tolka dem som nyckelord. Dessa ord kan användas som identifierare någon annanstans; Du kan definiera en funktion eller variabel med namnet matchning eller skiftläge .
-
_
-
fall
-
match
- Anteckningar
Indrag
Python använder blanksteg för att avgränsa kontrollflödesblock (enligt off-side-regeln) . Python lånar den här funktionen från sin föregångare ABC : istället för skiljetecken eller nyckelord använder den indrag för att indikera körningen av ett block .
I så kallade "fritt format"-språk – som använder blockstrukturen härledd från ALGOL – sätts kodblock av med klammerparenteser ( { }
) eller nyckelord. I de flesta kodningskonventioner för dessa språk drar programmerare konventionellt in koden i ett block för att visuellt skilja den från den omgivande koden.
En rekursiv funktion som heter foo
, som skickas en enskild parameter , x
, och om parametern är 0 kommer att anropa en annan funktion som heter bar
och annars anropar baz
, passerar x
, och även anropa sig själv rekursivt, och skickar x-1
som parameter , skulle kunna implementeras så här i Python:
0
def foo ( x ): om x == : bar () else : baz ( x ) foo ( x - 1 )
och skulle kunna skrivas så här i C med K&R indragsstil :
0
void foo ( int x ) { if ( x == ) { bar (); } annat { baz ( x ); foo ( x - 1 ); } }
Felaktigt indragen kod kan felläsas av en mänsklig läsare på ett annat sätt än den skulle tolkas av en kompilator eller tolk. Till exempel, om funktionsanropet foo(x - 1)
på den sista raden i exemplet ovan felaktigt indragits för att vara utanför if
/ else
-blocket:
0
def foo ( x ): om x == : bar () else : baz ( x ) foo ( x - 1 )
det skulle göra att den sista raden alltid exekveras, även när x
är 0, vilket resulterar i en oändlig rekursion .
Även om både blanksteg och tabbtecken accepteras som former av indrag och valfri multipel av blanksteg kan användas, rekommenderas blanksteg och 4 blanksteg (som i exemplen ovan) rekommenderas och är den överlägset vanligaste. [ opålitlig källa? ] Att blanda mellanslag och flikar på rader i följd är inte tillåtet från och med Python 3 eftersom det kan skapa buggar som är svåra att se, eftersom många verktyg inte visuellt särskiljer mellanslag och flikar.
Data struktur
Eftersom Python är ett dynamiskt skrivet språk, innehåller Python- värden, inte variabler, typinformation . Alla variabler i Python innehåller referenser till objekt , och dessa referenser skickas till funktioner. Vissa människor (inklusive Guido van Rossum själv) har kallat detta parameteröverförande schema "anrop genom objektreferens". En objektreferens betyder ett namn, och den godkända referensen är ett "alias", dvs en kopia av referensen till samma objekt, precis som i C/ C++ . Objektets värde kan ändras i den anropade funktionen med "alias", till exempel:
>>> alist = [ 'a' , 'b' , 'c' ] >>> def my_func ( al ): ... al . lägg till ( 'x' ) ... skriv ut ( al ) ... >>> my_func ( alist ) ['a', 'b', 'c', 'x'] >>> alist ['a', ' b', 'c', 'x']
Funktionen my_func
ändrar värdet på alist
med det formella argumentet al
, som är ett alias för alist
. Alla försök att använda (tilldela en ny objektreferens till) på själva aliaset kommer dock inte att ha någon effekt på det ursprungliga objektet. [ förtydligande behövs ]
>>> alist = [ 'a' , 'b' , 'c' ] >>> def my_func ( al ): ... # al.append('x') ... al = al + [ 'x' ] # en ny lista skapad och tilldelad till al betyder att al inte längre är alias för alist ... print ( al ) ... >>> my_func ( alist ) ['a', 'b', 'c', 'x '] >>> skriv ut ( alist ) ['a', 'b', 'c']
I Python är icke-innersta-lokala och inte-deklarerade-globala tillgängliga namn alla alias.
Bland dynamiskt typade språk är Python måttligt typkontrollerad. Implicit konvertering definieras för numeriska typer (såväl som booleans ), så man kan giltigt multiplicera ett komplext tal med ett heltal (till exempel) utan explicit casting . Det finns dock ingen implicit konvertering mellan till exempel tal och strängar ; en sträng är ett ogiltigt argument för en matematisk funktion som förväntar sig ett tal.
Bastyper
Python har ett brett utbud av grundläggande datatyper. Vid sidan av konventionell heltals- och flyttalsaritmetik stöder den på ett transparent sätt aritmetik med godtycklig precision , komplexa tal och decimaltal .
Python stöder en mängd olika strängoperationer. Strängar i Python är oföränderliga , så en strängoperation som en ersättning av tecken , som i andra programmeringsspråk kan ändra strängen på plats , returnerar en ny sträng i Python. Prestandaöverväganden tvingar ibland till att använda speciella tekniker i program som modifierar strängar intensivt, till exempel att sammanfoga teckenuppsättningar till strängar endast efter behov.
Samlingstyper
En av de mycket användbara aspekterna av Python är konceptet med insamlings- (eller containertyper ). I allmänhet är en samling ett objekt som innehåller andra objekt på ett sätt som lätt kan refereras eller indexeras . Samlingar finns i två grundläggande former: sekvenser och mappningar .
De ordnade sekventiella typerna är listor (dynamiska arrayer ), tupler och strängar. Alla sekvenser indexeras positionellt ( 0 till längd - 1 ) och alla utom strängar kan innehålla vilken typ av objekt som helst, inklusive flera typer i samma sekvens. Både strängar och tupler är oföränderliga, vilket gör dem till perfekta kandidater för ordboksnycklar (se nedan). Listor, å andra sidan, är föränderliga; element kan infogas, raderas, ändras, läggas till eller sorteras på plats .
Mappningar, å andra sidan, är (ofta oordnade) typer implementerade i form av ordböcker som "mappar" en uppsättning oföränderliga nycklar till motsvarande element (ungefär som en matematisk funktion). Till exempel skulle man kunna definiera en ordbok med en sträng "toast"
mappad till heltal 42
eller vice versa. Nycklarna i en ordbok måste vara av en oföränderlig Python-typ, till exempel ett heltal eller en sträng, eftersom de under huven implementeras via en hashfunktion . Detta ger mycket snabbare uppslagstider, men kräver att nycklar inte ändras.
Ordböcker är centrala för Pythons inre delar eftersom de finns i kärnan av alla objekt och klasser: mappningarna mellan variabelnamn (strängar) och de värden som namnen refererar till lagras som ordböcker (se Objektsystem ) . Eftersom dessa ordböcker är direkt tillgängliga (via ett objekts __dict__-
attribut), är metaprogrammering en enkel och naturlig process i Python.
En uppsättningssamlingstyp är en oindexerad, oordnad samling som inte innehåller några dubbletter och implementerar uppsättningsteoretiska operationer som union , intersection , difference , symmetrisk skillnad och delmängdstestning . Det finns två typer av set: set
och frozenset
, den enda skillnaden är att setet
är föränderligt och frozenset
är oföränderligt. Element i en uppsättning måste vara hashbara. Således kan till exempel en frusen uppsättning
vara en del av en vanlig uppsättning
medan motsatsen inte är sant.
Python tillhandahåller också omfattande samlingsmanipulerande förmågor som inbyggd kontroll av inneslutning och ett generiskt iterationsprotokoll.
Objektsystem
I Python är allt ett objekt, även klasser. Klasser, som objekt, har en klass, som är känd som deras metaklass . Python stöder också flera arv och mixins .
Språket stöder omfattande introspektion av typer och klasser. Typer kan läsas och jämföras – typer är instanser av typ
. Attributen för ett objekt kan extraheras som en ordbok.
Operatörer kan överbelastas i Python genom att definiera speciella medlemsfunktioner – till exempel att definiera en metod som heter __add__
på en klass tillåter en att använda operatorn +
på objekt i den klassen.
Bokstäver
Strängar
Python har olika typer av strängliteraler .
Normala strängbokstavar
Antingen enkla eller dubbla citattecken kan användas för att citera strängar. Till skillnad från i Unix-skalspråk, Perl- eller Perl-influerade språk som Ruby eller Groovy , fungerar enkla citattecken och dubbla citattecken identiskt, dvs det finns ingen stränginterpolation av $foo -uttryck. Interpolation kan dock göras på olika sätt: med "f-strängar" (sedan Python 3.6), med formatmetoden eller
den gamla % -strängformatoperatorn.
Till exempel, alla dessa Python-satser:
print ( f "Jag har precis skrivit ut { num } sidor till skrivaren { printer } " ) print ( "Jag har precis skrivit ut {} sidor till skrivaren {} " . format ( num , printer )) print ( "Jag har precis skrivit ut {0) } sidor till skrivaren {1} " . format ( num , skrivare )) print ( "Jag skrev precis ut {num} sidor till skrivaren {printer} " . format ( num = num , skrivare = skrivare )) print ( "I har precis skrivit ut %s sidor till skrivaren %s " % ( num , skrivare )) print ( "Jag har precis skrivit ut %(num)s sidor till skrivaren %(printer)s " % { "num" : num , "printer" : skrivare })
motsvarar Perl-påståendet:
print "Jag har precis skrivit ut $num sidor till skrivaren $printer\n"
De bygger en sträng med hjälp av variablerna num
och printer
.
Flerradiga strängar
Det finns också flerradiga strängar, som börjar och slutar med en serie av tre enkla eller dubbla citattecken och fungerar som här dokument i Perl och Ruby .
Ett enkelt exempel med variabel interpolation (med formatmetoden
) är:
print ( '''Kära {recipient} , jag önskar att du lämnar Sunnydale och aldrig kommer tillbaka. Not Quite Love, {sender} ''' . format ( avsändare = "Buffy the Vampire Slayer" , mottagare = "Spike" ))
Råa strängar
Slutligen kommer alla de tidigare nämnda strängtyperna i " rå " varianter (betecknas genom att placera ett bokstavligt r före det inledande citatet), som inte gör någon omvänd snedstreck-interpolation och därför är mycket användbara för reguljära uttryck ; jämför "@-quoting" i C# . Råsträngar inkluderades ursprungligen specifikt för reguljära uttryck. På grund av tokenizerns begränsningar kanske råsträngar inte har ett bakåtstreck. Att skapa en obearbetad sträng som innehåller en Windows- sökväg som slutar med ett omvänt snedstreck kräver en mängd olika lösningar (vanligtvis använder snedstreck i stället för bakåtstreck, eftersom Windows accepterar båda).
Exempel inkluderar:
>>> # En Windows-sökväg, även råsträngar kan inte sluta med ett snedstreck >>> r "C:\Foo\Bar\Baz \" File "<stdin>" , rad 1 r "C:\Foo\Bar\Baz \" ^ SyntaxError : EOL under scanning av strängen literal >>> dos_path = r "C:\Foo\Bar\Baz\ " # undviker felet genom att lägga till >>> dos_path . rstrip () # och ta bort det efterföljande utrymmet 'C:\\Foo\\Bar\\Baz\\' >>> quoted_dos_path = r ' " {} " ' . format ( dos_path ) >>> quoted_dos_path '"C:\\Foo\\Bar\\Baz\\ "' >>> # Ett reguljärt uttryck som matchar en citerad sträng med eventuellt omvänt snedstreck som citerar >>> re . match ( r '"(([^" \\ ]| \\ .)*)"' , quoted_dos_path ) . group ( 1 ) . rstrip () 'C:\\Foo\\Bar\\Baz\\' > >> code = 'foo(2, bar)' >>> # Vänd argumenten i ett tvåarg funktionsanrop >>> re . sub ( r '\(([^,]*?),([^ , ]*?)\)' , r '(\2, \1)' , code ) 'foo(2, bar)' >>> # Observera att detta inte fungerar om något av argumenten har parens eller kommatecken.
Sammanfogning av angränsande strängliteraler
Strängliteraler (med möjligen olika citatkonventioner) som visas sammanhängande och endast separerade av blanksteg (inklusive nya rader), är tillåtna och aggregeras till en enda längre sträng. Således
title = "En bra sväng: " \ ' En naturhistoria av skruvmejseln och skruven'
är ekvivalent med
title = "One Good Turn: A Natural History of the Screwdriver and the Screw"
Unicode
Sedan Python 3.0 är standardteckenuppsättningen UTF-8 både för källkod och tolk. I UTF-8 hanteras unicode-strängar som traditionella bytesträngar. Detta exempel kommer att fungera:
s = "Γειά" # Hej på grekiska tryck ( s )
Tal
0
Numeriska bokstaver i Python är av normal sort, t.ex. -1 ,
3.4 ,
3.5e -8
.
Python har heltal av godtycklig längd och ökar automatiskt deras lagringsstorlek vid behov. Före Python 3 fanns det två typer av heltal: traditionella heltal med fast storlek och "långa" heltal av godtycklig storlek. Omvandlingen till "långa" heltal utfördes automatiskt när det krävdes, och därför behövde programmeraren vanligtvis inte vara medveten om de två integraltyperna. I nyare språkversioner är distinktionen helt borta och alla heltal beter sig som heltal av godtycklig längd.
Python stöder normala flyttal , som skapas när en punkt används i en bokstavlig (t.ex. 1.1
), när ett heltal och ett flyttal används i ett uttryck, eller som ett resultat av vissa matematiska operationer ("sann division" via operatorn /
, eller exponentiering med en negativ exponent).
Python stöder också komplexa tal inbyggt. Komplexa tal indikeras med J
eller j
, t.ex. 3 + 4j
.
Listor, tupler, uppsättningar, ordböcker
Python har syntaktisk stöd för att skapa containertyper.
Listor (klasslista) är
föränderliga sekvenser av objekt av godtyckliga typer, och kan skapas antingen med den speciella syntaxen
a_list = [ 1 , 2 , 3 , "en hund" ]
eller genom att använda normalt objektskapande
a_second_list = lista () a_second_list . lägg till ( 4 ) en_andra_lista . bifoga ( 5 )
Tuples (klass tuple
) är oföränderliga sekvenser av föremål av godtyckliga typer. Det finns också en speciell syntax för att skapa tupler
a_tuple = 1 , 2 , 3 , "fyra" a_tuple = ( 1 , 2 , 3 , "fyra" )
Även om tuplar skapas genom att separera objekt med kommatecken, är hela konstruktionen vanligtvis inslagen inom parentes för att öka läsbarheten. En tom tuppel betecknas med ()
, medan en tupel med ett enda värde kan skapas med (1,)
.
Uppsättningar (klassuppsättning )
är föränderliga behållare med hashbara objekt av godtyckliga typer, utan dubbletter. Artiklarna är inte beställda, men ställer in supportiteration över artiklarna. Syntaxen för att skapa set använder parenteser
0 some_set = { , (), False }
Python-uppsättningar är mycket som matematiska uppsättningar , och stödoperationer som uppsättningsskärning och union . Python har också en frozenset-
klass för oföränderliga uppsättningar, se Samlingstyper .
Ordböcker (klass dict
) är föränderliga mappningar som knyter nycklar och motsvarande värden. Python har speciell syntax för att skapa ordböcker ( {nyckel: värde}
)
a_dictionary = { "nyckel 1" : "värde 1" , 2 : 3 , 4 : []}
Ordbokssyntaxen liknar den inställda syntaxen, skillnaden är närvaron av kolon. Den tomma bokstavliga {}
resulterar i en tom ordbok snarare än en tom uppsättning, som istället skapas med den icke-literala konstruktorn: set()
.
Operatörer
Aritmetisk
Python inkluderar operatorerna +
, -
, *
, /
("sann division"), //
( våningsindelning ), %
( modul ) och **
( exponentiering ) med deras vanliga matematiska företräde .
I Python 3 utför x/y
"sann division", vilket betyder att den alltid returnerar ett float, även om både x
och y
är heltal som delar sig jämnt.
>>> 4/2 2.0 _ _
och //
utför heltalsdelning eller våningsdelning och returnerar golvet för kvoten som ett heltal.
I Python 2 (och de flesta andra programmeringsspråk), såvida inget uttryckligen begärts, utförde x/y
heltalsdelning , vilket returnerade en float endast om någon av indata var en float. Men eftersom Python är ett dynamiskt typat språk, var det inte alltid möjligt att avgöra vilken operation som utfördes, vilket ofta ledde till subtila buggar, vilket ledde till introduktionen av //-operatorn och förändringen i semantiken för
/ -operatorn
i Python 3.
Jämförelseoperatörer
Jämförelseoperatorerna, dvs ==
, !=
, <
, >
, <=
, >=
, är
, är inte
, in
och inte i
används på alla möjliga värden. Siffror, strängar, sekvenser och mappningar kan alla jämföras. I Python 3 har olika typer (som en str
och en int
) inte en konsekvent relativ ordning. Även om det var möjligt att jämföra om en sträng var större än eller mindre än något heltal i Python 2, ansågs detta vara en historisk designquirk och togs till slut bort i Python 3.
Kedjade jämförelseuttryck som a < b < c
har ungefär samma betydelse som de har i matematik, snarare än den ovanliga betydelsen som finns i C och liknande språk. Villkoren utvärderas och jämförs i ordning. Operationen har kortslutningssemantik , vilket innebär att utvärderingen garanterat upphör så snart en dom är klar: om a < b
är falskt utvärderas c
aldrig eftersom uttrycket omöjligt kan vara sant längre.
För uttryck utan biverkningar är a < b < c
ekvivalent med a < b och b < c
. Det är dock en väsentlig skillnad när uttrycken har biverkningar. a < f(x) < b
kommer att utvärdera f(x)
exakt en gång, medan a < f(x) och f(x) < b
kommer att utvärdera det två gånger om värdet på a
är mindre än f(x)
och en gång annars .
Logiska operatorer
0
0
I alla versioner av Python behandlar booleska operatorer nollvärden eller tomma värden som ""
, , None
, 0.0
, []
och {}
som falskt, medan de i allmänhet behandlar icke-tomma, icke-nollvärden som sanna. De booleska värdena True
och False
lades till språket i Python 2.2.1 som konstanter (underklassade från 1
och ) och ändrades till att vara fullständiga nyckelord i Python 3. De binära jämförelseoperatorerna som ==
och >
returnerar antingen True
eller Falskt
.
De booleska operatorerna och
och eller
använder minimal utvärdering . Till exempel y == 0 eller x/y > 100
aldrig att höja ett dividera-med-noll-undantag. Dessa operatorer returnerar värdet för den senast utvärderade operanden, snarare än True
eller False
. Sålunda evalueras uttrycket (4 och 5) till
5
och (4 eller 5)
evalueras till 4
.
Funktionell programmering
Som nämnts ovan är en annan styrka med Python tillgången till en funktionell programmeringsstil . Som man kan förvänta sig gör detta arbetet med listor och andra samlingar mycket enklare.
Förståelser
En sådan konstruktion är listförståelsen , som kan uttryckas med följande format:
L = [ mapping_expression för element i källlistan om filter_expression ]
Använda listförståelse för att beräkna de första fem potenserna av två:
powers_of_two = [ 2 ** n för n i intervallet ( 1 , 6 )]
Quicksort - algoritmen kan uttryckas elegant (om än ineffektivt) med hjälp av listuppfattningar:
0
def qsort ( L ): om L == []: returnera [] pivot = L [ ] return ( qsort ([ x för x i L [ 1 :] om x < pivot ]) + [ pivot ] + qsort ([ x för x i L [ 1 :] om x >= pivot ]))
Python 2.7+ stöder också uppsättningsförståelser och ordboksförståelser.
Förstklassiga funktioner
I Python är funktioner förstklassiga objekt som kan skapas och skickas runt dynamiskt.
Pythons begränsade stöd för anonyma funktioner är lambda-
konstruktionen. Ett exempel är den anonyma funktionen som kvadrerar sin inmatning, anropad med argumentet 5:
f = lambda x : x ** 2 f ( 5 )
Lambdas är begränsade till att innehålla ett uttryck snarare än påståenden , även om kontrollflödet fortfarande kan implementeras mindre elegant inom lambda genom att använda kortslutning och mer idiomatiskt med villkorliga uttryck.
Stängningar
Python har haft stöd för lexikaliska stängningar sedan version 2.2. Här är en exempelfunktion som returnerar en funktion som approximerar derivatan av den givna funktionen:
def derivata ( f , dx ): """Returnera en funktion som approximerar derivatan av f med hjälp av ett intervall på dx, som bör vara lämpligt litet. """ def funktion ( x ): return ( f ( x + dx ) - f ( x ) ) / dx returfunktion
Pythons syntax leder dock ibland till att programmerare av andra språk tror att nedläggningar inte stöds. Variabelt omfattning i Python bestäms implicit av omfattningen där man tilldelar ett värde till variabeln, såvida inte omfattningen uttryckligen deklareras med global
eller icke-lokal
.
Observera att stängningens bindning av ett namn till något värde inte kan ändras inifrån funktionen. Given:
>>> 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
och du kan se att b
, som syns från stängningens omfattning, behåller det värde den hade; den förändrade bindningen av b
inuti den inre funktionen fortplantade sig inte ut. Vägen runt detta är att använda en icke-lokal b
-sats i bar
. I Python 2 (som saknar icke-lokal
) är den vanliga lösningen att använda ett föränderligt värde och ändra det värdet, inte bindningen. T.ex. en lista med ett element.
Generatorer
Introducerade i Python 2.2 som en valfri funktion och färdigställda i version 2.3, är generatorer Pythons mekanism för lat utvärdering av en funktion som annars skulle returnera en utrymmeskrävande eller beräkningsintensiv lista.
Detta är ett exempel för att lätta generera primtal:
från itertools import count def gener_primes ( stop_at = None ): primtal = [] för n i count ( start = 2 ): om stop_at inte är None och n > stop_at : return # höjer StopIteration undantaget composite = False för p i primtal : om inte n % p : sammansatt = Sann brytning elif p ** 2 > n : brytning om inte sammansatt : primtal . lägga till ( n ) ge n
När du anropar den här funktionen kan det returnerade värdet itereras över ungefär som en lista:
för i i generera_primtal ( 100 ): # iterera över primtal mellan 0 och 100 skriv ut ( i ) för i i generera_primtal ( ): # iterera över ALLA primtal på obestämd tid skriv ut ( i )
Definitionen av en generator verkar identisk med den för en funktion, förutom att nyckelordet avkastning
används i stället för avkastning
. En generator är dock ett objekt med beständigt tillstånd, som upprepade gånger kan komma in i och lämna samma omfång. Ett generatoranrop kan sedan användas i stället för en lista eller annan struktur vars element kommer att itereras över. När for-
slingan i exemplet kräver nästa objekt, anropas generatorn och ger nästa objekt.
Generatorer behöver inte vara oändliga som exemplet med primtal ovan. När en generator avslutas uppstår ett internt undantag som indikerar för alla anropskontexter att det inte finns fler värden. En for-
loop eller annan iteration kommer då att avslutas.
Generatoruttryck
Generatoruttryck, som introducerades i Python 2.4, är den lata utvärderingens motsvarighet till listförståelse. Med hjälp av primtalsgeneratorn i avsnittet ovan kan vi definiera en lat, men inte helt oändlig samling.
från itertools importera islice primes_under_million = ( i för i i gener_primes () om i < 1000000 ) two_thousandth_prime = islice ( primes_under_million , 1999 , 2000 ) . nästa ()
Det mesta av minnet och tiden som behövs för att generera så många primtal kommer inte att användas förrän det nödvändiga elementet faktiskt har nåtts. Tyvärr kan du inte utföra enkel indexering och skivning av generatorer, utan måste använda itertools -modulen eller "rulla dina egna" loopar. Däremot är en listförståelse funktionellt likvärdig, men är girig när det gäller att utföra allt arbete:
primes_under_million = [ i för i i generera_primtal ( 2000000 ) om jag < 1000000 ] two_thousandth_prime = primes_under_million [ 1999 ]
Listförståelsen kommer omedelbart att skapa en stor lista (med 78498 objekt, i exemplet, men tillfälligt skapa en lista med primtal under två miljoner), även om de flesta element aldrig nås. Generatorförståelsen är mer sparsam.
Ordbok och uppsättningsförståelser
Medan listor och generatorer hade uppfattningar/uttryck, måste i Python-versioner äldre än 2.7 de andra inbyggda Python-samlingstyperna (dikt och uppsättningar) klumpas in i att använda listor eller generatorer:
0 0 >>> dict (( n , n * n ) för n i intervallet ( 5 )) { : , 1 : 1 , 2 : 4 , 3 : 9 , 4 : 16 }
Python 2.7 och 3.0 förenade alla samlingstyper genom att introducera ordbok och uppsättningsförståelser, liknande listförståelser:
0
0
0 0 >>> [ n * n för n i intervallet ( 5 )] # vanlig listförståelse [ , 1 , 4 , 9 , 16 ] >>> >>> { n * n för n i intervallet ( 5 )} # set förståelse { , 1 , 4 , 9 , 16 } >>> >>> { n : n * n för n i intervallet ( 5 )} # diktförståelse { : , 1 : 1 , 2 : 4 , 3 : 9 , 4 : 16 }
Föremål
Python stöder de flesta objektorienterade programmeringstekniker (OOP). Det tillåter polymorfism , inte bara inom en klasshierarki utan också genom att skriva . Vilket objekt som helst kan användas för alla typer, och det kommer att fungera så länge det har rätt metoder och attribut. Och allt i Python är ett objekt, inklusive klasser, funktioner, siffror och moduler. Python har också stöd för metaklasser , ett avancerat verktyg för att förbättra klassernas funktionalitet. Naturligtvis stöds arv , inklusive multipelt arv . Python har mycket begränsat stöd för privata variabler som använder namnmangling som sällan används i praktiken eftersom informationsdöljning av vissa ses som opytoniskt , eftersom det antyder att klassen i fråga innehåller oestetiska eller dåligt planerade interna delar. Sloganen "vi är alla ansvarsfulla användare här" används för att beskriva denna attityd.
Som är sant för moduler, sätter inte klasser i Python en absolut barriär mellan definition och användare, utan förlitar sig snarare på användarens artighet att inte "bryta sig in i definitionen."
— 9. Klasser , The Python 2.6 Tutorial (2013)
OOP -doktriner som användningen av accessormetoder för att läsa datamedlemmar tillämpas inte i Python. Precis som Python erbjuder funktionella programmeringskonstruktioner men inte försöker kräva referenstransparens , erbjuder den ett objektsystem men kräver inte OOP- beteende. Dessutom är det alltid möjligt att omdefiniera klassen med hjälp av egenskaper (se Egenskaper ) så att när en viss variabel ställs in eller hämtas i anropskod, anropar den verkligen ett funktionsanrop, så att spam.eggs = toast
verkligen kan anropa spam.set_eggs (toast)
. Detta upphäver den praktiska fördelen med accessorfunktioner, och det förblir OOP eftersom egenskapsäggen blir en legitim del av objektets gränssnitt: det behöver inte återspegla en implementeringsdetalj .
I version 2.2 av Python introducerades "ny stil"-klasser. Med klasser i ny stil förenades objekt och typer, vilket möjliggjorde underklassificering av typer. Även helt nya typer kan definieras, komplett med anpassat beteende för infix-operatörer. Detta gör att många radikala saker kan göras syntaktisk inom Python. En ny metodupplösningsordning för multipelt arv antogs också med Python 2.3. Det är också möjligt att köra anpassad kod medan du använder eller ställer in attribut, även om detaljerna i dessa tekniker har utvecklats mellan Python-versionerna.
Med uttalande
With -
satsen hanterar resurser och tillåter användare att arbeta med Context Manager-protokollet. En funktion ( __enter__()
) anropas när man går in i scope och en annan ( __exit__() )
när man lämnar. Detta förhindrar att man glömmer att frigöra resursen och hanterar även mer komplicerade situationer som att frigöra resursen när ett undantag inträffar medan den används. Kontexthanterare används ofta med filer, databasanslutningar, testfall etc.
Egenskaper
Egenskaper tillåter att speciellt definierade metoder anropas på en objektinstans genom att använda samma syntax som används för attributåtkomst. Ett exempel på en klass som definierar vissa egenskaper är:
klass MyClass : def __init__ ( själv ): själv . _a = Ingen @property def a ( själv ): returnera själv . _a @a . setter # gör egenskapen skrivbar def a ( self , value ): self . _a = värde
Beskrivningar
En klass som definierar en eller flera av de tre specialmetoderna __get__(själv, instans, ägare)
, __set__(self, instans, värde)
, __delete__(self, instans)
kan användas som en deskriptor. Att skapa en instans av en deskriptor som en klassmedlem i en andra klass gör instansen till en egenskap hos den andra klassen.
Klassiska och statiska metoder
Python tillåter skapandet av klassmetoder och statiska metoder med hjälp av dekoratorerna @classmethod
och @staticmethod
. Det första argumentet till en klassmetod är klassobjektet istället för självreferensen till instansen. En statisk metod har inget speciellt första argument. Varken instansen eller klassobjektet skickas till en statisk metod.
Undantag
Python stöder (och använder i stor utsträckning) undantagshantering som ett sätt att testa för feltillstånd och andra "exceptionella" händelser i ett program.
Python-stil kräver användning av undantag närhelst ett feltillstånd kan uppstå. Istället för att testa för åtkomst till en fil eller resurs innan den faktiskt används, är det vanligt i Python att bara gå vidare och försöka använda den och fånga undantaget om åtkomst avvisas.
Undantag kan också användas som ett mer allmänt sätt för icke-lokal överföring av kontroll, även när ett fel inte är aktuellt. Mailman- programvaran för e-postlistor, skriven i Python, använder till exempel undantag för att hoppa ur djupt inkapslad logik för meddelandehantering när ett beslut har fattats att avvisa ett meddelande eller hålla det för moderatorgodkännande.
Undantag används ofta som ett alternativ till if
-blocket, speciellt i gängade situationer. Ett vanligt motto är EAFP, eller "Det är lättare att be om förlåtelse än tillåtelse", som tillskrivs Grace Hopper . Alternativet, känt som LBYL, eller "Look Before You Leap", testar uttryckligen för förutsättningar.
I detta första kodexempel, efter LBYL-metoden, finns det en explicit kontroll av attributet före åtkomst:
om hasattr ( skräppost , 'ägg' ): ham = skräppost . ägg annat : handle_missing_attr ()
Detta andra exempel följer EAFP-paradigmet:
försök : ham = skräppost . ägg utom AttributeError : handle_missing_attr ()
Dessa två kodexempel har samma effekt, även om det kommer att finnas prestandaskillnader. När spam
har attributet eggs
kommer EAFP-provet att köras snabbare. När spam
inte har attributet eggs
(det "exceptionella" fallet), kommer EAFP-provet att gå långsammare. Python- profileraren kan användas i specifika fall för att bestämma prestandaegenskaper. Om exceptionella fall är sällsynta kommer EAFP-versionen att ha överlägsen genomsnittlig prestanda än alternativet. Dessutom undviker den hela klassen av TOCTTOU-sårbarheter ( time-of-check-to-time-of-use), andra rasförhållanden och är kompatibel med duck typing . En nackdel med EAFP är att den endast kan användas med uttalanden; ett undantag kan inte fångas i ett generatoruttryck, listförståelse eller lambdafunktion.
Kommentarer och docstrings
Python har två sätt att kommentera Python-kod. En är genom att använda kommentarer för att indikera vad någon del av koden gör. Enradskommentarer börjar med hash-tecknet ( #
) och fortsätter till slutet av raden. Kommentarer som sträcker sig över mer än en rad uppnås genom att infoga en flerradssträng (med """
eller "'"
som avgränsare i varje ände) som inte används i tilldelningen eller på annat sätt utvärderas, men som sitter mellan andra påståenden.
Kommentera en kodbit:
import sys def getline (): return sys . stdin . readline () # Få en rad och returnera den
Kommentera en kod med flera rader:
def getline (): return sys . stdin . readline () """denna funktion får en rad och returnerar den"""
Docstrings (dokumentationssträngar), det vill säga strängar som är placerade ensamma utan tilldelning som den första indragna raden inom en modul, klass, metod eller funktion, ställer automatiskt in sitt innehåll som ett attribut med namnet __doc__ , som är avsett att lagra en läsbar för
människor beskrivning av objektets syfte, beteende och användning. Den inbyggda hjälpfunktionen
genererar sin utdata baserat på __doc__-
attribut. Sådana strängar kan avgränsas med "
eller '
för enradiga strängar, eller kan sträcka sig över flera rader om de avgränsas med antingen """ eller
' ''
som är Pythons notation för att specificera flerradiga strängar. Men stilguiden för språket anger att tredubbla citattecken ( """
) är att föredra för både enkel- och flerradiga docstrings.
Enrads docstring:
def getline (): """Hämta en rad från stdin och returnera den.""" return sys . stdin . läsrad ()
Flerrads docstring:
def getline (): """Hämta en rad från stdin och returnera den. "" " return sys . stdin . läsrad ()
Docstrings kan vara så stora som programmeraren vill och innehålla radbrytningar . Till skillnad från kommentarer är docstrings i sig Python-objekt och är en del av den tolkade koden som Python kör. Det betyder att ett program som körs kan hämta sina egna docstrings och manipulera den informationen, men den normala användningen är att ge andra programmerare information om hur man anropar objektet som dokumenteras i docstringen.
Det finns tillgängliga verktyg som kan extrahera docstrings från Python-kod och generera dokumentation. Docstring-dokumentation kan också nås från tolken med hjälp()
-funktionen, eller från skalet med pydoc -kommandot pydoc
.
Standardmodulen doctest använder interaktioner som kopierats från Python-skalsessioner till docstrings för att skapa tester, medan docopt -modulen använder dem för att definiera kommandoradsalternativ.
Funktionskommentarer
Funktionskommentarer (typtips) definieras i PEP 3107. De tillåter att bifoga data till argumenten och returnera en funktion. Anteckningarnas beteende definieras inte av språket och överlåts till tredje parts ramverk. Till exempel kan ett bibliotek skrivas för att hantera statisk typning:
def haul ( artikel : Haulable , * vargs : PackAnimal ) -> Avstånd
Dekoratörer
En dekoratör är alla anropsbara Python-objekt som används för att modifiera en funktion, metod eller klassdefinition. En dekoratör passerar det ursprungliga objektet som definieras och returnerar ett modifierat objekt, som sedan binds till namnet i definitionen. Python-dekoratörer inspirerades delvis av Java-anteckningar och har en liknande syntax; dekorationssyntaxen är rent syntaktisk socker , med @
som nyckelord:
@viking_chorus def menu_item (): print ( "spam" )
är ekvivalent med
def menu_item (): print ( "spam" ) menu_item = viking_chorus ( menu_item )
Dekoratörer är en form av metaprogrammering ; de förstärker verkan av funktionen eller metoden de dekorerar. Till exempel, i exemplet nedan, viking_chorus
göra att menu_item
körs 8 gånger (se Spam-skiss ) för varje gång det anropas:
def viking_chorus ( myfunc ): def inner_func ( * args , ** kwargs ): för i i intervallet ( 8 ): myfunc ( * args , ** kwargs ) returnera inner_func
Kanoniska användningar av funktionsdekoratorer är för att skapa klassmetoder eller statiska metoder , lägga till funktionsattribut, spåra , ställa in för- och eftervillkor och synkronisering , men kan användas för mycket mer, inklusive eliminering av svansrekursion , memoisering och till och med förbättra skrivningen av andra dekoratörer.
Dekoratörer kan kedjas genom att placera flera på intilliggande linjer:
@invincible @favourite_colour ( "Blå" ) def black_knight (): pass
är ekvivalent med
def black_knight (): pass black_knight = oövervinnerlig ( favoritfärg ( "Blå" )( black_knight ) )
eller med hjälp av mellanliggande variabler
def black_knight (): pass blue_decorator = favourite_colour ( "Blue" ) decorated_by_blue = blue_decorator ( black_knight ) black_knight = oövervinnerlig ( decorated_by_blue )
I exemplet ovan tar favourite_colour
dekoratörsfabriken ett argument . Dekoratörsfabriker måste returnera en dekoratör, som sedan anropas med föremålet som ska dekoreras som argument:
def favourite_colour ( color ): def decorator ( func ): def wrapper (): print ( color ) func () returnera wrapper return decorator
Detta skulle sedan dekorera black_knight-
funktionen så att färgen, "Blå"
, skulle skrivas ut innan black_knight
-funktionen körs. Stängning säkerställer att färgargumentet är tillgängligt för den innersta omslagsfunktionen även när den returneras och går utom räckvidd, vilket är det som gör att dekoratörer kan arbeta.
Trots namnet är Python-dekoratörer inte en implementering av dekorationsmönstret . Dekorationsmönstret är ett designmönster som används i statiskt skrivna objektorienterade programmeringsspråk för att tillåta funktionalitet att läggas till objekt under körning; Python-dekoratörer lägger till funktionalitet till funktioner och metoder vid definitionstidpunkten och är därför en konstruktion på högre nivå än klasser av dekoratörsmönster. Själva dekorationsmönstret är trivialt implementerbart i Python, eftersom språket är ducktypat och därför vanligtvis inte betraktas som sådant. [ förtydligande behövs ]
påskägg
Användare av språk med parenteser , som C eller Java , förväntar sig eller önskar ibland att Python följer en blockavgränsningskonvention. Klammeravgränsad blocksyntax har upprepade gånger begärts och konsekvent avvisats av kärnutvecklare. Python-tolken innehåller ett påskägg som sammanfattar utvecklarnas känslor i denna fråga. Koden från __future__ import parentes
höjer undantaget SyntaxError: not a chance
. Modulen __future__
används normalt för att tillhandahålla funktioner från framtida versioner av Python.
Ett annat dolt meddelande, Zen of Python (en sammanfattning av Pythons designfilosofi ), visas när du försöker importera detta
.
Meddelandet Hej världen!
skrivs ut när importsatsen import __hello__
används. I Python 2.7, istället för Hello world!
det trycker Hello world...
.
Genom att importera antigravitationsmodulen
öppnas en webbläsare till xkcd comic 353 som skildrar en humoristisk fiktiv användning av en sådan modul, avsedd att demonstrera hur lätt Python-modulerna möjliggör ytterligare funktionalitet. I Python 3 innehåller denna modul även en implementering av "geohash"-algoritmen, en referens till xkcd comic 426 .
externa länkar
- Python handledning skriven av författaren till Python, Guido van Rossum.
- Fluent Python (andra upplagan)