In Python, module, class, def, lambda can introduce new variable scope, if/elif/else/, try/except, for/while will not introduce new variable scope.
if True:
msg = 'I am from Shanghai'
print(msg) # We can use msg.
def test():
msg = 'I am from Shanghai'
print(msg) # error
Global and Local
msg_loc = "Shanghai" # Global
def test():
msg = 'I am from Shanghai' # Local
New Assignment
msg = 'I am from Shanghai'
def test():
msg = 'I am from Beijing'
print(msg)
test()
print(msg)
I am from Beijing
I am from Shanghai
Reference
msg = 'I am from Shanghai'
def test():
print(msg)
test()
I am from Shanghai
Modification
msg = 'I am from Shanghai'
def test():
print(msg)
msg = 'I am from Beijing'
test()
UnboundLocalError: local variable 'msg'
referenced before assignment
How to modify the variable outside? The global keyword
num = 1
def fun():
global num
num = 123
print(num)
fun()
print(num)
123
123
num = 1
def fun():
print(num)
global num
num = 123
print(num)
fun()
SyntaxError: name 'num' is used
prior to global declaration
a = 10
def test():
a = a + 1
print(a)
test()
UnboundLocalError: local variable 'a'
referenced before assignment
a = 10
def test():
global a
a = a + 1
print(a)
test()
11
a = 10
def test():
a = 10
a = a + 1
print(a)
test()
print(a)
11
10
a = [1,2,3]
def test():
print(a)
a = [1,2,3,4]
test()
UnboundLocalError: local variable 'a'
referenced before assignment
a = [1,2,3]
def test():
print(a)
a.append(4)
test()
print(a)
[1, 2, 3]
[1, 2, 3, 4]
a = {"color": "green"}
def test():
print(a)
a["color"] = "red"
a["position"] = "left"
test()
print(a)
{'color': 'green'}
{'color': 'red', 'position': 'left'}
For immutable objects (number, string, tuple), the assignment inside a function cannot change the value of the variable outside the function even if the variable name inside is the same with the variable name outside.
def ChangeInt(a):
a = 10
return a
b = 2
print(ChangeInt(b))
print(b)
10
2
def ChangeInt(b):
b = 10
return b
b = 2
x = ChangeInt(b)
print(x, b)
10 2
def ChangeInt(a):
a = 10
print(a)
return a
b = 2
ChangeInt(b)
print(b)
print(ChangeInt(b))
10
2
10
10
def ChangeInt(a):
a = 10
print(a)
b = 2
ChangeInt(b)
print(b)
print(ChangeInt(b))
10
2
10
None
For mutable objects (list, dictionary), the assignment inside a function cannot change the value of the variable outside the function. (the same with immutable objects!)
def changeme(mylist):
mylist = [1,2]
print("inside: ", mylist)
x = [10,20]
changeme(x)
print("outside: ", x)
inside: [1, 2]
outside: [10, 20]
However, the modification can change the value of the variable outside.
def changeme(mylist):
mylist.extend([1,2])
print ("inside: ", mylist)
x = [10,20]
changeme(x)
print ("outside: ", x)
inside: [10, 20, 1, 2]
outside: [10, 20, 1, 2]
def outer():
def inner():
print(100)
inner()
outer()
def outer():
def inner():
num = 100
print(num)
inner()
outer()
Local$\rightarrow$Enclosing$\rightarrow$Global$\rightarrow$ Build-in (LEGB)
num = 3 # Global
def outer():
num = 10 # Enclosing
def inner():
num = 100 # Local
print(num)
inner()
print(num)
outer()
def outer():
num = 10
def inner():
nonlocal num
# nonlocal keyword
num = 100
print(num)
inner()
print(num)
outer()
100
100
def outer():
num = 10
def inner():
global num
# global does not work
num = 100
print(num)
inner()
print(num)
outer()
100
10
def outer():
global num
num = 10
def inner():
global num
num = 100
print(num)
inner()
print(num)
outer()
100
100
def outer():
global num
num = 10
def inner():
num = 100
print(num)
inner()
print(num)
outer()
100
10
num = 3
def outer():
global num
num = 10
def inner():
num = 100
print(num)
inner()
print(num)
outer()
print(num)
100
10
10
num = 3
def outer():
num = 10
def inner():
global num
num = 100
print(num)
inner()
print(num)
outer()
print(num)
100
10
100
num = 3
def outer():
num = 10
def inner():
nonlocal num
num = 100
print(num)
inner()
print(num)
outer()
print(num)
100
100
3
num = 3
def outer():
global num
num = 10
def inner():
global num
num = 100
print(num)
inner()
print(num)
outer()
print(num)
100
100
100
def make_pizza(toppings):
print(toppings)
make_pizza('pepperoni')
If we want to pass multiple arguments, we may create a list at first.
x=['mushrooms', 'green peppers', 'extra cheese']
def make_pizza(toppings):
for y in toppings:
print(y, end=', ')
make_pizza(x)
def make_pizza(topping_1, topping_2, topping_3):
print(topping_1, topping_2, topping_3)
make_pizza('mushrooms', 'green peppers', 'extra cheese')
However, sometimes we are not sure about the exact number of the arguments.
We can pass multiple arguments at once in the following way.
def make_pizza(*toppings):
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
Note that Python packs the arguments into a tuple, even if the function receives only one value.
def make_pizza(*toppings):
for topping in toppings:
print("- " + topping)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
- pepperoni
- mushrooms
- green peppers
- extra cheese
Mixing Positional and Arbitrary Arguments
If you want a function to accept several different kinds of arguments, the parameter that accepts an arbitrary number of arguments must be placed last in the function definition.
def make_pizza(size, *toppings):
print(str(size) + "-inch pizza:")
for topping in toppings:
print("- " + topping)
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
16-inch pizza:
- pepperoni
12-inch pizza:
- mushrooms
- green peppers
- extra cheese
Using Arbitrary Keyword Arguments
def build_profile(**user_info):
print(user_info)
build_profile(location='Shanghai',field='Management')
{'location': 'Shanghai', 'field': 'Management'}
Using Arbitrary Keyword Arguments
def build_profile(first, last, **user_info):
profile = {}
for key, value in user_info.items():
profile[key] = value
return first, last, profile
user_profile = build_profile('albert', 'einstein',
location='princeton',
field='physics')
print(user_profile)
('albert', 'einstein',
{'location': 'princeton', 'field': 'physics'})
def build_profile(*name, **user_info):
print(name)
print(user_info)
build_profile('albert', 'einstein',
location='princeton',
field='physics')
('albert', 'einstein')
{'location': 'princeton', 'field': 'physics'}
As a tradition, we often use *args and **kw
Example
def test(x,y=1,*a,**b):
print(x,y,a,b)
test(1)
test(1,2)
test(1,2,3)
test(1,2,3,4)
test(x=1,y=2)
test(1,a=2)
test(1,2,3,a=4)
test(1,2,3,y=4)
Result
1 1 () {}
1 2 () {}
1 2 (3,) {}
1 2 (3, 4) {}
1 2 () {}
1 1 () {'a': 2}
1 2 (3,) {'a': 4}
TypeError: test() got multiple values