Answer 1:
(question)
Question:
Answer:
Question:
#!/usr/bin/python
i=1
def f():
print "i=%s" % i
i = i + 1
f()
This program fails due to a scoping error:
This has two undesirable effects:
Python has an unusual scoping system, where functions are pre-scanned for assignments before they are executed. Any variable which gets assigned is assumed to be local unless explicitly declaredTraceback (most recent call last): File "function_scope.py", line 8, in ? f() File "function_scope.py", line 5, in f print "i=%s" % i UnboundLocalError: local variable 'i' referenced before assignment
global
.
This has two undesirable effects:
- It confuses users, since the same sort of code would work in almost any other language. It's not intuitive to need to define parent variables as "global" in order to assign a value to them.
- It forces the use of kludges in order to access parent variables which are not global. Basically, you must put the parent data into a list or a hash, in order to trick the python interpreter into thinking you are not assigning a value to it.
Answer 2:
(question)
Question:
Answer:
Question:
#!/usr/bin/python
def outer():
i=1
def inner():
print "i=%s" % str(i)
i += 1
inner()
inner()
outer()
This program fails due to a scoping error:
This issue is further complicated by Python's lack of a way to access parent variables which are not global. In this case, there are three nested scopes:
This version of the code works:
Python has an unusual scoping system, where functions are pre-scanned for assignments before they are executed. Any variable which gets assigned is assumed to be local unless explicitly declaredTraceback (most recent call last): File "q/function_scope-2.py", line 12, in ? outer() File "q/function_scope-2.py", line 9, in outer inner() File "q/function_scope-2.py", line 6, in inner print "i=%s" % str(i) UnboundLocalError: local variable 'i' referenced before assignment
global
.
This issue is further complicated by Python's lack of a way to access parent variables which are not global. In this case, there are three nested scopes:
global
, outer
, and inner
. But
inner
has no direct way to access outer
's data for
assignment. The only way to assign data from inner
to outer
is to wrap the data in containers so Python's optimizer will not detect any
assignment, and will not create local variables to override the parent data.
This version of the code works:
#!/usr/bin/python def outer(): i=[1] def inner(): print "i=%s" % str(i[0]) i[0] += 1 inner() inner() outer()
Answer 3:
(question)
Question:
Answer:
Question:
#!/usr/bin/python
def add_evil(data=[]):
data.append(666)
return data
print add_evil()
print add_evil(["hi there"])
print add_evil()
print add_evil()
The output is:
Using mutable default values is not recommended.
Python has a bizarre way of handling default parameters. It binds the default value once, when the function is defined, instead of doing it each time the function is called. So, if a default value is mutable, its value may be different on successive calls.[666] ['hi there', 666] [666, 666] [666, 666, 666]
Using mutable default values is not recommended.
Answer 4:
(question)
Question:
Answer:
Question:
#!/usr/bin/python
a = [1,2,3]
b = a
a += [4]
b = b + [5]
print "a=%s" % a
print "b=%s" % b
Output:
For non-mutable objects, the effect is almost always the same, but mutable objects behave differently. The
Thea=[1, 2, 3, 4] b=[1, 2, 3, 4, 5]
+=
operator does not do the same thing as writing
foo = foo + value
.
For non-mutable objects, the effect is almost always the same, but mutable objects behave differently. The
+=
operator is designed to
change an object in-place, where the longer method will produce a new object
and re-bind the name to the new object. Taking away the syntactic sugar,
the example could be written more explicitly as:
a = [1,2,3] b = a a.__iadd__([4]) b = b.__add__([5])
Answer 5:
(question)
Question:
Answer:
Question:
#!/usr/bin/python
a = ([1,2,3], [7,8,9])
try:
a[0] += [4,5,6]
except Exception, e:
print "Error: %s" % e
print "a=%s" % str(a)
Output:
Python manages to modify the [1,2,3] list in-place, but then it fails after making the changes, because tuples are not mutable.Error: object doesn't support item assignment a=([1, 2, 3, 4, 5, 6], [7, 8, 9])