Vad Är Python-Namnområden (Och Varför Behövs De?)
namnkonflikter händer hela tiden i verkligheten. Till exempel, varje skola som jag någonsin gick på hade minst två elever i min klass som delade samma förnamn. Om någon kom in i klassen och bad om student X, skulle vi entusiastiskt fråga, ” Vilken pratar du om? Det finns två studenter som heter X. ” Efter det skulle den frågande personen ge oss ett efternamn, och vi skulle presentera honom till höger X.
all denna förvirring och processen att bestämma den exakta personen vi pratar om genom att leta efter annan information förutom ett förnamn kan undvikas om alla hade ett unikt namn. Detta är inte ett problem i en klass på 30 studenter. Det blir dock allt svårare att komma med ett unikt, meningsfullt och lätt att komma ihåg namn för varje barn i en skola, stad, stad, land eller hela världen. En annan fråga i att ge varje barn ett unikt namn är att processen för att avgöra om någon annan har också namngett sitt barn Macey, Maci eller Macie kan vara mycket tröttsamt.
en mycket liknande konflikt kan också uppstå vid programmering. När du skriver ett program med bara 30 rader utan externa beroenden är det väldigt enkelt att ge unika och meningsfulla namn till alla dina variabler. Problemet uppstår när det finns tusentals rader i ett program och du har laddat några externa moduler också. I denna handledning kommer du att lära dig om namnrymder, deras betydelse och omfångsupplösning i Python.
Vad är Namnrymder?
ett namnområde är i grunden ett system för att se till att alla namn i ett program är unika och kan användas utan konflikt. Du kanske redan vet att allt i Python-liknande strängar, listor, funktioner etc.- är ett objekt. Ett annat intressant faktum är att Python implementerar namnområden som ordböcker. Det finns en namn-till-objekt-mappning, med Namnen som nycklar och objekten som värden. Flera namnrymder kan använda samma namn och mappa det till ett annat objekt. Här är några exempel på namnrymder:
- lokal namnrymd: Det här namnområdet innehåller lokala namn i en funktion. Denna namnrymd skapas när en funktion anropas, och den varar bara tills funktionen återgår.
- Global namnrymd: det här namnrymden innehåller namn från olika importerade moduler som du använder i ett projekt. Det skapas när modulen ingår i projektet, och det varar tills skriptet slutar.
- inbyggt namnrymd: det här namnrymden innehåller inbyggda funktioner och inbyggda undantagsnamn.
i de matematiska modulerna i Python-serien på Envato Tuts+ skrev jag om användbara matematiska funktioner som finns i olika moduler. Till exempel har math-och cmath-modulerna många funktioner som är gemensamma för dem båda, som log10()
acos()
cos()
exp()
, etc. Om du använder båda dessa moduler i samma program är det enda sättet att använda dessa funktioner entydigt att prefixa dem med namnet på modulen, som math.log10()
och cmath.log10()
.
Vad är omfattning?
namnområden hjälper oss att identifiera alla namn i ett program. Detta innebär dock inte att vi kan använda ett variabelnamn var som helst vi vill. Ett namn har också ett omfång som definierar de delar av programmet där du kan använda det namnet utan att använda något prefix. Precis som namnområden finns det också flera omfattningar i ett program. Här är en lista över några omfattningar som kan existera under genomförandet av ett program.
- ett lokalt omfång, vilket är det innersta omfånget som innehåller en lista med lokala namn som är tillgängliga i den aktuella funktionen.
- en omfattning av alla omslutande funktioner. Sökningen efter ett namn börjar från närmaste omslutande räckvidd och rör sig utåt.
- ett modulnivåomfång som innehåller alla globala namn från den aktuella modulen.
- det yttersta omfånget som innehåller en lista över alla inbyggda namn. Det här omfånget söks sist för att hitta namnet som du refererade till.
i de kommande avsnitten i denna handledning kommer vi i stor utsträckning att använda den inbyggda Python dir () – funktionen för att returnera en lista med namn i det aktuella lokala omfånget. Detta hjälper dig att förstå begreppet namnområden och omfattning tydligare.
Scope Resolution
som jag nämnde i föregående avsnitt börjar sökningen efter ett visst namn från den innersta funktionen och flyttar sedan högre och högre tills programmet kan mappa det namnet till ett objekt. När inget sådant namn finns i något av namnrymderna, höjer programmet ett NameError-undantag.
innan vi börjar, försök skriva dir()
I IDLE eller någon annan Python IDE.
dir()#
Låt oss se utmatningen från funktionen dir()
efter att ha definierat en variabel och en funktion.
a_num = 10dir()# def some_func(): b_num = 11 print(dir()) some_func()# dir()#
dir()
funktionen matar bara ut listan med namn inom det aktuella omfånget. Det är därför inom ramen för some_func()
finns det bara ett namn som heter b_num
. Anropar dir()
efter att ha definierat some_func()
lägger till den i listan över namn som finns i det globala namnområdet.
låt oss nu se listan över namn i vissa kapslade funktioner. Koden i det här blocket fortsätter från föregående block.
ovanstående kod definierar två variabler och en funktion inom ramen för outer_func()
. Inutiinner_func()
skriver funktionendir()
endast namnetd_num
. Detta verkar rättvist eftersom d_num
är den enda variabeln som definieras där.
om det inte uttryckligen anges med global
, omfördelas ett globalt namn i en lokal namnrymd skapar en ny lokal variabel med samma namn. Detta framgår av följande kod.
inuti både outer_func()
och inner_func()
a_num
har förklarats vara en global variabel. Vi ställer bara in ett annat värde för samma globala variabel. Detta är anledningen till att värdet på a_num
på alla platser är 20. Å andra sidan skapar varje funktion sin egen b_num
variabel med ett lokalt omfång, och funktionen print()
skriver ut värdet på denna lokalt scoped variabel.
korrekt importera moduler
det är mycket vanligt att importera externa moduler i dina projekt för att påskynda utvecklingen. Det finns tre olika sätt att importera moduler. I det här avsnittet kommer du att lära dig om alla dessa metoder och diskutera deras fördelar och nackdelar i detalj.
-
from module import *
: Denna metod för att importera en modul importerar alla namn från den angivna modulen direkt i din nuvarande namnrymd. Du kan frestas att använda den här metoden eftersom den låter dig använda en funktion direkt utan att lägga till modulens namn som ett prefix. Det är dock mycket felbenägen, och du förlorar också möjligheten att berätta vilken modul som faktiskt importerade den funktionen. Här är ett exempel på att använda den här metoden:
om du är bekant med matte-och CMATH-modulerna vet du redan att det finns några vanliga namn som definieras i båda dessa moduler men gäller för reella respektive komplexa tal.
eftersom vi har importerat CMATH-modulen efter math-modulen skriver den över funktionsdefinitionerna för dessa vanliga funktioner från math-modulen. Det är därför det första log10(125)
returnerar ett reellt tal och det andra log10(125)
returnerar ett komplext tal. Det finns inget sätt för dig att använda funktionen log10()
från math-modulen nu. Även om du försökte skriva math.log10(125)
får du ett NameError-undantag eftersom math
faktiskt inte finns i namnområdet.
summan av kardemumman är att du inte ska använda detta sätt att importera funktioner från olika moduler bara för att spara några tangenttryckningar.
-
from module import nameA, nameB
: om du vet att du bara ska använda ett eller två namn från en modul kan du importera dem direkt med den här metoden. På så sätt kan du skriva koden mer kortfattat medan du fortfarande håller föroreningen av namnområdet till ett minimum. Tänk dock på att du fortfarande inte kan använda något annat namn från modulen genom att användamodule.nameZ
. Alla funktioner som har samma namn i ditt program kommer också att skriva över definitionen av den funktionen som importeras från modulen. Detta gör den importerade funktionen oanvändbar. Här är ett exempel på att använda den här metoden:
dir()# from math import log2, log10dir()# log10(125)# 2.0969100130080562
-
import module
: detta är det säkraste och rekommenderade sättet att importera en modul. Den enda nackdelen är att du måste prefixa modulens namn till alla namn som du ska använda i programmet. Du kommer dock att kunna undvika förorening av namnrymden och även definiera funktioner vars namn matchar namnet på funktioner från modulen.
dir()# import mathdir()# math.log10(125)# 2.0969100130080562
slutliga tankar
Jag hoppas att denna handledning hjälpte dig att förstå namnrymder och deras betydelse. Du bör nu kunna bestämma omfattningen av olika namn i ett program och undvika potentiella fallgropar.
dessutom, tveka inte att se vad vi har tillgängliga för försäljning och för studier på marknaden, och tveka inte att ställa några frågor och ge din värdefulla feedback med hjälp av flödet nedan.
den sista delen av artikeln diskuterade olika sätt att importera moduler i Python och för-och nackdelar med var och en av dem. Om du har några frågor relaterade till detta ämne, vänligen meddela mig i kommentarerna.
lär dig Python
lär dig Python med vår kompletta python tutorial guide, Oavsett om du precis har börjat eller om du är en erfaren kodare som vill lära sig nya färdigheter.