280 likes | 433 Views
Namnrum, räckvidd och rekursion. Linda Mannila 29.11.2007. Liten repetition om funktioner. Vad händer om man i en funktion har en variabel med samma namn som en variabel på yttersta nivån (rotnivån)? Hur kan Python i sådana fall skilja på variablerna?. Namnrum ( namespaces ).
E N D
Namnrum, räckvidd och rekursion Linda Mannila 29.11.2007
Liten repetition om funktioner • Vad händer om man i en funktion har en variabel med samma namn som en variabel på yttersta nivån (rotnivån)? • Hur kan Python i sådana fall skilja på variablerna?
Namnrum (namespaces) • Alla namn ordnas i namnrum • Inte bara variabelnamn, utan även namn på funktioner etc. • Varje namn får endast förekomma en gång i ett namnrum • Men samma namn får finnas i godtyckligt många namnrum utan att störa varandra • På rotnivån finns ett globalt namnrum som alltid finns tillgängligt • Inne i en funktion finns ett lokalt namnrum som endast finns tillgängligt inne i den funktionen • Funktionen dir() visar alla namn som finns definierade i det aktuella namnrummet
>>> dir() ['__builtins__', '__doc__', '__name__'] >>> min_variabel = 3 >>> dir() ['__builtins__', '__doc__', '__name__', 'min_variabel'] >>> def min_funktion(): print "Jag är min egen funktion!" >>> dir() ['__builtins__', '__doc__', '__name__', 'min_funktion', 'min_variabel'] >>> def min_funktion(): print "Jag är en annan funktion med samma namn. Då försvinner" print "den första versionen för ett namnrum kan inte innehålla" print "fler än en version av ett namn." >>> dir() ['__builtins__', '__doc__', '__name__', 'min_funktion', 'min_variabel'] >>> min_funktion() Jag är en annan funktion med samma namn. Då försvinner Den första versionen för ett namnrum kan inte innehålla fler än en version av ett namn.
Räckvidd (scope) • En variabels räckvidd definieras som den programkod som har tillgång till det namnrum där variabeln finns definierad • En variabels räckvidd • anger var variabeln “syns” • utgörs av det block som den definierats i, med start från den plats där den definierats • Därför syns t.ex. en lokal variabel i en funktion inte utanför funktionen
Hur hittar Python rätt namn? • Då en funktion körs • Söker Python först efter namnet i det lokala namnrummet (dvs. inne i funktionen) • Om variabeln inte hittas där, fortsätter Python söka i det globala namnrummet • Om variabeln inte hittas där, fortsätter Python söka i det inbyggda namnrummet • Om variabeln inte heller hittas där, uppstår ett fel
Vilka namn hittas var? def get_info(): text = raw_input("Input info. Any info: ") return text def get_second_info(): text = raw_input("Input some other info. Any other info: ") return text info = get_info() info2 = get_second_info() all_info = info + info2 all_info = all_info.upper() print all_info
Skillnad? def get_info(): text = raw_input("Input info. Any info: ") return text def get_second_info(): text = raw_input("Input some other info. Any other info: ") return text def main(): info = get_info() info2 = get_second_info() all_info = info + info2 all_info = all_info.upper() print all_info
Lokala vs. globala variabler • Variabler som deklareras inne i en funktion är inte relaterade till andra variabler med samma namn utanför funktionen • Variablerna är lokala för funktionen • Variablernas räckvidd är just den funktionen, inget annat • Kan lista de lokala och globala variablerna i ett program var som helst med funktionerna locals() och globals()
Exempel def function(): x = 2 print 'Changed local x to', x x = 50 print 'x is', x function() print 'x is still', x Output: x is 50 Changed local x to 2 x is still 50
Exempel def function(): x = 2 print 'Changed local x to', x print 'Local variables inside the function: ', locals() x = 50 print 'x is', x function() print 'x is still', x print 'Local variables outside of the function: ', locals() Output x is 50 Changed local x to 2 Local variables inside the function: {'x': 2} x is still 50 Local variables outside of the function: {'function': <function function at 0x02AC4E70>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'C:\\Python25\\Lib\\idlelib\\idle.pyw', 'idlelib': <module 'idlelib' from 'C:\Python25\lib\idlelib\ __init__.pyc'>, 'x': 50, '__name__': '__main__'}
Parametrar blir också lokala variabler def upphoj(tal, potens): print locals() return tal**potens print upphoj(5,2) print tal print potens Output: {'tal': 5, 'potens': 2} 25 Traceback (most recent call last): File "local_global4.py", line 6, in <module> print tal NameError: name 'tal' is not defined
Namnrum och moduler • Om en modul importeras med import modulnamn måste modulens namn användas som ”prefix” för att komma åt modulens funktioner • Detta kan undvikas genom att använda from modulnamn import * eller from modulnamn import namn • Men! Om två moduler definierar samma namn som båda importeras till programmet sker en krock • Den andra importen skriver över gamla definitioner • T.ex. om vi skulle göra importen from webbrowser import open skulle vi inte längre kunna komma åt den inbyggda funktionen open för att öppna filer • Använd därför from-formen sparsamt
Rekursion • Fråga: Vad är rekursion? • Svar: Något som definieras rekursivt • Fråga: Vad betyder rekursiv? • Svar: En metod som är rekursiv är definierad genom rekursion. • Fråga: Vad är rekursion? • Svar: Något som definieras rekursivt • osv.
Rekursion • En rekursiv definition är definierad utgående från sig själv: • "Rekursion: ... För mer information, se Rekursion. “ • En funktion är rekursiv om dess definition innehåller ett anrop till sig själv • def minfunktion(): kod... kod... return minfunktion() + 1
Varför rekursion? • Ibland är ett problem för stort eller för komplext för att kunna lösas utan att bli alltför stort • Lösning: • bryt ner problemet i mindre delar av sig självt • lös dessa delar skilt för sig • kombinera alla dellösningar för att få en lösning till det ursprúngliga problemet • ”Divide and conquer” • Rekursion är en bra teknik som kan användas på många intressanta problem.
När används rekursion? • Många kända rekursiva exempel • Summaberäkning • Fakultet • Fibonacci • Towers of Hanoi • Binary search • Quick sort • Mergesort • ... • Se http://www.sparknotes.com/cs/recursion/examples/ • Alla algoritmer som bygger på iteration (loopar) kan även skrivas rekursivt och vice versa
Standardexempel: Fakultet (n!) • 0! = 1 • 1! = 1 • n! = n * (n-1)! • Rekursiv definition osv.
Att koda rekursivt • En rekursiv funktion är uppbyggd av två element som alltid måste finnas med • Ett basfall • Ett rekursivt anrop • Basfallet • det undantag som får den rekursiva funktionen att avslutas • får aldrig vara rekursivt, skall oftast returnera ett enkelt värde • Det rekursiva anropet • det som skall ske om inte basfallet gäller • anropar den egna funktionen • OBS! Som i en while-loop måste man se till att något ändras för att “minska problemet” för varje rekursivt anrop
Rekursiv fakultet i Python def factorial(n): # Basfallet if n == 0 or n == 1: return 1 # Rekursiva anropet else: return n * factorial (n-1)
Rekursiv fakultet - exekveringen factorial(5) 5 * factorial(4) 4 * factorial(3) 3 * factorial(2) 2* factorial(1) 1 * 1 Basfallet har nåtts! Kan börja ”nysta upp” exekveringen
Rekursiv fakultet - exekveringen factorial(5) 5 * factorial(4) 4 * factorial(3) 3 * factorial(2) 2* factorial(1) 1 * 1 5*24=120 4*6=24 3*2=6 2*1=2 1*1=1
Rekursiv summa def summa(n): # Basfall if n == 1: return 1 # Rekursivt anrop else: return n + summa(n-1)
Iterativ summa def summa(n): i = 1 summa = 0 while i <= n: summa += i i += 1 return summa
Rekursion vs. iteration • Vad är bättre? • Rekursion ger ett stort antal funktionsanrop • kostsamt då det slukar mycket minne • långsammare än iteration • Rekursiva funktioner är kortare • lättare att skriva och debugga
Rekursion - checklista • En rekursiv funktion måste ha (minst) ett basfall • En rekursiv funktion måste ha (minst) ett rekursivt anrop • Varje rekursivt anrop måste “minska på problemet”
Fibonacci • Sanskrit, ideala bisamhällen, gyllene snittet, Åbo Energis skorsten.. • Definieras enligt: • fib(0) = 0 • fib(1) = 1 • fib(n-1) + fib(n-2) för alla n > 1 • fibonacci.py