Hva er Python Name Spaces (og hvorfor trenger de det?)

Navnekonflikter skje hele tiden i virkeligheten. For eksempel har hver skole jeg noen gang gikk til, hatt minst to studenter i klassen som delte samme fornavn. Hvis noen kom inn i klassen og ba om student X, ville vi entusiastisk spørre: "Hvem snakker du om? Det er to studenter som heter X." Etter det ville den spørrende personen gi oss et etternavn, og vi ville introdusere ham til høyre X.

Alt denne forvirringen og prosessen med å bestemme den nøyaktige personen vi snakker om ved å lete etter annen informasjon utover et fornavn, kan unngås hvis alle hadde et unikt navn. Dette er ikke et problem i en klasse på 30 studenter. Det blir imidlertid stadig vanskeligere å komme opp med a unik, gir mening og lett å huske navn for hvert barn i en skole, by, by, land eller hele verden. Et annet problem med å gi hvert barn et unikt navn er at prosessen med å avgjøre om noen andre også har kalt sitt barn Macey, Maci eller Macie, kan være veldig slitsomt..

En veldig lignende konflikt kan også oppstå i programmeringen. Når du skriver et program på bare 30 linjer uten eksterne avhengigheter, er det veldig enkelt å gi unike og meningsfulle navn til alle variablene dine. Problemet oppstår når det er tusenvis av linjer i et program, og du har også lagt inn noen eksterne moduler. I denne opplæringen lærer du om navneområder, deres betydning og omfangsoppløsning i Python. 

Hva er navnegrupper?

Et navneområde er i utgangspunktet et system for å sikre at alle navnene i et program er unike og kan brukes uten konflikter. Du vet kanskje allerede at alt i Python-lignende strenger, lister, funksjoner, etc.-er et objekt. Et annet interessant faktum er at Python implementerer navneområder som ordbøker. Det er et navn-til-objekt kartlegging, med navnene som nøkler og objektene som verdier. Flere navneområder kan bruke samme navn og kartlegge det til et annet objekt. Her er noen eksempler på navneområder:

  • Lokalt navneområde: Dette navneområdet inkluderer lokale navn inne i en funksjon. Dette navneområdet opprettes når en funksjon kalles, og den varer bare til funksjonen returnerer.
  • Global Navneområde: Dette navneområdet inneholder navn fra ulike importerte moduler som du bruker i et prosjekt. Den er opprettet når modulen er inkludert i prosjektet, og den varer til skriptet avsluttes.
  • Innebygd navneskala: Dette navneområdet inneholder innebygde funksjoner og innebygde unntaksnavn.

I de matematiske modulene i Python-serien på Envato Tuts + skrev jeg om nyttige matematiske funksjoner som er tilgjengelige i forskjellige moduler. For eksempel har matematikk- og cmathmodulene mange funksjoner som er felles for dem begge, som log10 (), Acos (), cos (), exp (), etc. Hvis du bruker begge disse modulene i samme program, er den eneste måten å bruke disse funksjonene entydig på å prefikse dem med navnet på modulen, som math.log10 () og cmath.log10 ().

Hva er omfanget?

Navnegrupper hjelper oss med å identifisere alle navnene inne i et program. Dette innebærer imidlertid ikke at vi kan bruke et variabelt navn hvor som helst vi vil. Et navn har også et omfang som definerer delene av programmet der du kan bruke det navnet uten å bruke noe prefiks. Akkurat som navneområder, er det også flere mål i et program. Her er en liste over noen omfang som kan eksistere under utførelsen av et program.

  • Et lokalt omfang, som er det innerste omfanget som inneholder en liste over lokale navn som er tilgjengelige i den nåværende funksjonen.
  • Et omfang av alle de omsluttende funksjonene. Søket etter et navn starter fra det nærmeste lukkede omfanget og beveger seg utover.
  • Et modulnivåomfang som inneholder alle de globale navnene fra den nåværende modulen.
  • Det ytre omfanget som inneholder en liste over alle de innebygde navnene. Dette omfanget søkes sist for å finne navnet du refererte til. 

I de neste delene av denne opplæringen vil vi i stor utstrekning bruke den innebygde Python dir () -funksjonen til å returnere en liste over navn i gjeldende lokale omfang. Dette vil hjelpe deg å forstå begrepet navneområder og omfang tydeligere.

Scope Resolution

Som nevnt i forrige avsnitt starter søket etter et gitt navn fra den innerste funksjonen, og flyttes deretter høyere og høyere til programmet kan kartlegge det navnet til en gjenstand. Når det ikke finnes noe slikt navn i noen av navneområdene, øker programmet a NameError unntak.

Før du begynner, prøv å skrive dir () i IDLE eller noen annen Python IDE.

dir () # ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

Alle disse navnene oppført av dir () er tilgjengelig i alle Python-programmer. For korthetens skyld vil jeg begynne å referere til dem som '__builtins __' ... '__spec__' i resten av eksemplene.

La oss se utgangen av dir () funksjon etter definere en variabel og en funksjon.

a_num = 10 dir () # ['__builtins __' ... '__spec__', 'a_num'] def some_func (): b_num = 11 skriv ut (dir ()) some_func () # ['b_num'] dir () # ['__builtins__ '...' __spec__ ',' a_num ',' some_func '] 

De dir () Funksjonen utsender bare listen over navn innenfor det nåværende omfanget. Det er derfor innenfor rammen av some_func (), det er bare ett navn som heter b_num. ringe dir () etter å ha definert some_func () legger den til listen over navn som er tilgjengelige i det globale navneområdet.

Nå, la oss se listen over navn i noen nestede funksjoner. Koden i denne blokken fortsetter fra den forrige blokken.

def outer_func (): c_num = 12 def inner_func (): d_num = 13 skriv ut (dir (), '- navn i inner_func') e_num = 14 inner_func () print (dir (), '- navn i outer_func') outer_func ) # ['d_num'] - navn i inner_func # ['c_num', 'e_num', 'inner_func'] - navn i outer_func

Ovennevnte kode definerer to variabler og en funksjon innenfor rammen av outer_func (). Innsiden inner_func (), de dir () Funksjonen bare skriver ut navnet d_num. Dette virker rettferdig som d_num er den eneste variabelen som er definert der.

Med mindre eksplisitt spesifisert ved bruk av global, omorganisere et globalt navn i et lokalt navneområde lager en ny lokal variabel med samme navn. Dette fremgår av følgende kode.

a_num = 10 b_num = 11 def outer_func (): global a_num a_num = 15 b_num = 16 def inner_func (): global a_num a_num = 20 b_num = 21 print ('a_num inside inner_func:', a_num) print ('b_num inside inner_func: ', b_num) inner_func () skriv ut (' a_num inside outer_func: ', a_num) print (' b_num inside outer_func: ', b_num) outer_func () print (' a_num utenfor alle funksjoner: ', a_num) funksjoner: ', b_num) # a_num inside inner_func: 20 # b_num inside inner_func: 21 # a_num inside outer_func: 20 # b_num inside outer_func: 16 # a_num utenfor alle funksjoner: 20 # b_num utenfor alle funksjonene: 11

Inne i begge outer_func () og inner_func (), a_num har blitt erklært å være en global variabel. Vi setter bare en annen verdi for den samme globale variabelen. Dette er grunnen til at verdien av a_num På alle steder er 20. På den annen side skaper hver funksjon sin egen b_num variabel med lokalt omfang, og skrive ut() funksjonen skriver ut verdien av denne lokalt scoped variabelen.

Riktig Importer Moduler

Det er svært vanlig å importere eksterne moduler i prosjektene dine for å fremskynde utviklingen. Det er tre forskjellige måter å importere moduler på. I denne delen lærer du om alle disse metodene, diskuterer deres fordeler og ulemper i detalj.

  • fra modulen import *: Denne metoden for å importere en modul importerer alle navnene fra den oppgitte modulen direkte i ditt nåværende navneområde. Du kan være fristet til å bruke denne metoden fordi den lar deg bruke en funksjon direkte uten å legge til navnet på modulen som et prefiks. Det er imidlertid veldig feilaktig, og du mister også muligheten til å fortelle hvilken modul som faktisk importerte den funksjonen. Her er et eksempel på å bruke denne metoden:
dir () # ['__builtins __' ... '__spec__'] fra matematikk import * dir () # ['__builtins __' ... '__spec__', 'acos', 'acosh', 'asin', 'asinh', # 'atan' , 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'grader', 'e', ​​'erf', 'erfc', 'exp', 'expm1' 'fabs', 'factorial', 'floor', 'fmod', # 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite' 'isinf', 'isnan', 'ldexp', 'lgamma', 'logg', 'log10', 'log1p', 'log2', # 'modf', 'nan', 'pi', 'pow' radans ',' sin ',' sinh ',' sqrt ',' tan ', #' tanh ',' trunc '] log10 (125) # 2.0969100130080562 fra cmath import * dir () # [' __builtins __ '...' __spec__ ' , 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees' 'e', 'erf', # 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', # 'gamma' 'gcd', 'hypot', 'inf', 'islose', 'isfinite', 'isinf', 'isnan', # 'ldexp', 'lgamma', 'logg', 'log10', 'log1p' log2 ',' modf ',' nan ',' fase ', #' pi ',' polar ',' pow ',' radianer ',' re ' ct ',' sin ',' sinh ',' sqrt ',' tan ',' tanh ', #' trunc '] log10 (125) # (2,0969100130080562 + 0j)

Hvis du er kjent med matte og cmath moduler, vet du allerede at det finnes noen få vanlige navn som er definert i begge disse modulene, men gjelder for henholdsvis reelle og komplekse tall. 

Siden vi har importert cmath modul etter matte modul, overskriver funksjon definisjonene av disse vanlige funksjonene fra matte modul. Det er derfor den første log10 (125) returnerer et reelt tall og det andre log10 (125) returnerer et komplekst nummer. Det er ingen måte for deg å bruke log10 () Funksjonen fra matematikkmodulen nå. Selv om du prøvde å skrive math.log10 (125), Du vil få et NameError-unntak fordi matte Faktisk eksisterer ikke i navneområdet.

Bunnlinjen er at du ikke bør bruke denne måten å importere funksjoner fra forskjellige moduler bare for å lagre noen tastetrykk.

  • fra modulets importnavnA, navnB: Hvis du vet at du bare skal bruke ett eller to navn fra en modul, kan du importere dem direkte ved hjelp av denne metoden. På denne måten kan du skrive koden mer konsistent, samtidig som du beholder navngitte forurensning til et minimum. Vær imidlertid oppmerksom på at du fortsatt ikke kan bruke noe annet navn fra modulen ved å bruke module.nameZ. Enhver funksjon som har samme navn i programmet, vil også overskrive definisjonen av den funksjonen som er importert fra modulen. Dette vil gjøre den importerte funksjonen ubrukelig. Her er et eksempel på å bruke denne metoden:
dir () # ['__builtins __' ... '__spec__'] fra matematikk import log2, log10 dir () # ['__builtins __' ... '__spec__', 'log10', 'log2'] log10 (125) # 2.0969100130080562
  • importeringsmodul: Dette er den sikreste og anbefalte måten å importere en modul på. Den eneste ulempen er at du må prefikse navnet på modulen til alle navnene du skal bruke i programmet. Du vil imidlertid kunne unngå forurensning av navnerom og også definere funksjoner hvis navn samsvarer med navnet på funksjonene fra modulen.
dir () # ['__builtins __' ... '__spec__'] import matematikk dir () # ['__builtins __' ... '__spec__', 'math'] math.log10 (125) # 2.0969100130080562

Siste tanker

Jeg håper denne opplæringen hjalp deg med å forstå navneområder og deres betydning. Du bør nå kunne bestemme omfanget av forskjellige navn i et program og unngå potensielle fallgruver. 

I tillegg, ikke nøl med å se hva vi har tilgjengelig for salg og for studier på markedet, og ikke nøl med å stille spørsmål og gi din verdifulle tilbakemelding ved hjelp av feedet under.

Den endelige delen av artikkelen diskuterte forskjellige måter å importere moduler på i Python og fordelene og ulemperne til hver av dem. Hvis du har spørsmål relatert til dette emnet, vennligst gi beskjed i kommentarene.

Lær python

Lær Python med vår komplette pythonveiledning, enten du er bare i gang eller du er en erfaren coder som ønsker å lære nye ferdigheter..