Is it possible to modify values for a dictionary inside a function without passing the dictionary as a parameter.
I would like not to return a dictionary, but only to modify its values.
That's possible, but not necessarily advisable, i can't imagine why you wouldn't like to pass or return the dictionary, if you merely don't want to return the dictionary, but could pass it, you can modify it to reflect in the original dictionary without having to return it, for example:
dict = {'1':'one','2':'two'}
def foo(d):
d['1'] = 'ONE'
print dict['1'] # prints 'one' original value
foo(dict)
print dict['1'] # prints 'ONE' ie, modification reflects in original value
# so no need to return it
However, if you absolutely cannot pass it for whatever reason, you can use a global dictionary as follows:
global dict # declare dictionary as global
dict = {'1':'one','2':'two'} # give initial value to dict
def foo():
global dict # bind dict to the one in global scope
dict['1'] = 'ONE'
print dict['1'] # prints 'one'
foo(dict)
print dict['1'] # prints 'ONE'
I'd recommend the first method demonstrated in the first code block, but feel free to use the second if absolutely necessary.
Enjoy :)
Yes you can, dictionary is an mutable object so they can be modified within functions, but it must be defined before you actually call the function.
To change the value of global variable pointing to an immutable object you must use the global statement.
>>> def func():
... dic['a']+=1
...
>>> dic = {'a':1} #dict defined before function call
>>> func()
>>> dic
{'a': 2}
For immutable objects:
>>> foo = 1
>>> def func():
... global foo
... foo += 3 #now the global variable foo actually points to a new value 4
...
>>> func()
>>> foo
4
Related
Lets say i have this function:
def test(t=[]):
t.append(1)
print(t)
if i run it a few times the list will be appended like this:
test() #[1]
test() #[1, 1]
so where is this list stored?
it is not in globals() // locals() the functions __dict__ is also empty
Okay found it:
It is stored in __defaults__
here you can even set it to a different tuple
This is because the python interpreter/compiler assigns the default value to the argument at compile time.
That's why default arguments should be immutable.
def test(t=None):
if t is None:
t = []
t.append(1)
print(t)
What is the difference between globals(), locals(), and vars()? What do they return? Are updates to the results useful?
Each of these return a dictionary:
globals() always returns the dictionary of the module namespace
locals() always returns a dictionary of the current namespace
vars() returns either a dictionary of the current namespace (if called with no argument) or the dictionary of the argument.
locals and vars could use some more explanation. If locals() is called inside a function, it updates a dict with the values of the current local variable namespace (plus any closure variables) as of that moment and returns it. Multiple calls to locals() in the same stack frame return the same dict each time - it's attached to the stack frame object as its f_locals attribute. The dict's contents are updated on each locals() call and each f_locals attribute access, but only on such calls or attribute accesses. It does not automatically update when variables are assigned, and assigning entries in the dict will not assign the corresponding local variables:
import inspect
def f():
x = 1
l = locals()
print(l)
locals()
print(l)
x = 2
print(x, l['x'])
l['x'] = 3
print(x, l['x'])
inspect.currentframe().f_locals
print(x, l['x'])
f()
gives us:
{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2
The first print(l) only shows an 'x' entry, because the assignment to l happens after the locals() call. The second print(l), after calling locals() again, shows an l entry, even though we didn't save the return value. The third and fourth prints show that assigning variables doesn't update l and vice versa, but after we access f_locals, local variables are copied into locals() again.
Two notes:
This behavior is CPython specific -- other Pythons may allow the updates to make it back to the local namespace automatically.
In CPython 2.x it is possible to make this work by putting an exec "pass" line in the function. This switches the function to an older, slower execution mode that uses the locals() dict as the canonical representation of local variables.
If locals() is called outside a function it returns the actual dictionary that is the current namespace. Further changes to the namespace are reflected in the dictionary, and changes to the dictionary are reflected in the namespace:
class Test(object):
a = 'one'
b = 'two'
huh = locals()
c = 'three'
huh['d'] = 'four'
print huh
gives us:
{
'a': 'one',
'b': 'two',
'c': 'three',
'd': 'four',
'huh': {...},
'__module__': '__main__',
}
So far, everything I've said about locals() is also true for vars()... here's the difference: vars() accepts a single object as its argument, and if you give it an object it returns the __dict__ of that object. For a typical object, its __dict__ is where most of its attribute data is stored. This includes class variables and module globals:
class Test(object):
a = 'one'
b = 'two'
def frobber(self):
print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()
which gives us:
three
Note that a function's __dict__ is its attribute namespace, not local variables. It wouldn't make sense for a function's __dict__ to store local variables, since recursion and multithreading mean there can be multiple calls to a function at the same time, each with their own locals:
def f(outer):
if outer:
f(False)
print('Outer call locals:', locals())
print('f.__dict__:', f.__dict__)
else:
print('Inner call locals:', locals())
print('f.__dict__:', f.__dict__)
f.x = 3
f(True)
which gives us:
Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}
Here, f calls itself recursively, so the inner and outer calls overlap. Each one sees its own local variables when it calls locals(), but both calls see the same f.__dict__, and f.__dict__ doesn't have any local variables in it.
My understanding of mutability and immutability in Python is, say we have a variable foo, if there exists a way to change how foo looks like (by using print) without changing its id, then foo is mutable. Otherwise, it's immutable.
For example, you can do this for a list,
foo = [1, 2, 3]
print(foo, id(foo))
foo[0] = 100
print(foo, id(foo))
but no way for int.
But what about function? First of all, is my definitions of mutability and immutability given above correct? If yes, can you find a way to mutate function without changing its id in order to prove it's mutable?
You can explicitly change the code of a function without affecting its id (here is code using python 2.7):
>>> def f():
... print "f"
...
>>> def g():
... print "g"
...
>>> id(f)
140305904690672
>>> f()
f
>>> f.func_code = g.func_code
>>> id(f)
140305904690672
>>> f()
g
What is the difference between globals(), locals(), and vars()? What do they return? Are updates to the results useful?
Each of these return a dictionary:
globals() always returns the dictionary of the module namespace
locals() always returns a dictionary of the current namespace
vars() returns either a dictionary of the current namespace (if called with no argument) or the dictionary of the argument.
locals and vars could use some more explanation. If locals() is called inside a function, it updates a dict with the values of the current local variable namespace (plus any closure variables) as of that moment and returns it. Multiple calls to locals() in the same stack frame return the same dict each time - it's attached to the stack frame object as its f_locals attribute. The dict's contents are updated on each locals() call and each f_locals attribute access, but only on such calls or attribute accesses. It does not automatically update when variables are assigned, and assigning entries in the dict will not assign the corresponding local variables:
import inspect
def f():
x = 1
l = locals()
print(l)
locals()
print(l)
x = 2
print(x, l['x'])
l['x'] = 3
print(x, l['x'])
inspect.currentframe().f_locals
print(x, l['x'])
f()
gives us:
{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2
The first print(l) only shows an 'x' entry, because the assignment to l happens after the locals() call. The second print(l), after calling locals() again, shows an l entry, even though we didn't save the return value. The third and fourth prints show that assigning variables doesn't update l and vice versa, but after we access f_locals, local variables are copied into locals() again.
Two notes:
This behavior is CPython specific -- other Pythons may allow the updates to make it back to the local namespace automatically.
In CPython 2.x it is possible to make this work by putting an exec "pass" line in the function. This switches the function to an older, slower execution mode that uses the locals() dict as the canonical representation of local variables.
If locals() is called outside a function it returns the actual dictionary that is the current namespace. Further changes to the namespace are reflected in the dictionary, and changes to the dictionary are reflected in the namespace:
class Test(object):
a = 'one'
b = 'two'
huh = locals()
c = 'three'
huh['d'] = 'four'
print huh
gives us:
{
'a': 'one',
'b': 'two',
'c': 'three',
'd': 'four',
'huh': {...},
'__module__': '__main__',
}
So far, everything I've said about locals() is also true for vars()... here's the difference: vars() accepts a single object as its argument, and if you give it an object it returns the __dict__ of that object. For a typical object, its __dict__ is where most of its attribute data is stored. This includes class variables and module globals:
class Test(object):
a = 'one'
b = 'two'
def frobber(self):
print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()
which gives us:
three
Note that a function's __dict__ is its attribute namespace, not local variables. It wouldn't make sense for a function's __dict__ to store local variables, since recursion and multithreading mean there can be multiple calls to a function at the same time, each with their own locals:
def f(outer):
if outer:
f(False)
print('Outer call locals:', locals())
print('f.__dict__:', f.__dict__)
else:
print('Inner call locals:', locals())
print('f.__dict__:', f.__dict__)
f.x = 3
f(True)
which gives us:
Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}
Here, f calls itself recursively, so the inner and outer calls overlap. Each one sees its own local variables when it calls locals(), but both calls see the same f.__dict__, and f.__dict__ doesn't have any local variables in it.
I would like to create instances of a class containing a list that's empty by default; instead of later setting this list to the final full list I would like to successively add items to it. Here's a piece of sample code illustrating this:
#!/usr/bin/python
class test:
def __init__(self, lst=[], intg=0):
self.lista = lst
self.integer = intg
name_dict = {}
counter = 0
for name in ('Anne', 'Leo', 'Suzy'):
counter += 1
name_dict[name] = test()
name_dict[name].integer += 1
name_dict[name].lista.append(counter)
print name, name_dict[name].integer, name_dict[name].lista
When I ran the above program I expected to get
Anne 1 [1]
Leo 1 [2]
Suzy 1 [3]
as I assumed lista to always be initialised to an empty list.
What I got instead was this:
Anne 1 [1]
Leo 1 [1, 2]
Suzy 1 [1, 2, 3]
If I replace self.lista = lst by self.lista = [] it works fine, just like when I add the line name_dict[name].lista = [] to the for loop.
Why is it that the contents of the previous objects' lists are retained, yet their values of integer aren't? I am rather new to Python, so it would be great if someone could point out to me where my thoughts/assumptions have gone astray.
Thanks a lot in advance for your replies.
It is a very bad idea to use a mutable object as a default value, as you do here:
def __init__(self, lst=[], intg=0):
# ...
Change it to this:
def __init__(self, lst=None, intg=0):
if lst is None:
lst = []
# ...
The reason that your version doesn't work is that the empty list is created just once when the function is defined, not every time the function is called.
In some Python implementations you can see the value of the default values of the function by inspecting the value of func_defaults:
print test.__init__.func_defaults
name_dict[name] = test()
# ...
Output:
([],)
Anne 1 [1]
([1],)
Leo 1 [1, 2]
([1, 2],)
Suzy 1 [1, 2, 3]
The problem lies in this line:
def __init__(self, lst=[], intg=0):
You shouldn't use a list as a default argument. The first time __init__ is called without lst specified the Python interpreter will define an empty list []. Subsequent calls to the function will operate on the same list if lst is not specified, without declaring a new list. This causes weird problems.
You should instead use a default value of None and add a check at the beginning of the function:
def __init__(self, lst=None, intg=0):
if lst is None:
lst = []
See this post for further details. Quoting the post:
Default arguments are evaluated at
function definition time, so they're
persistent across calls. This has some
interesting (and confusing) side
effects. An example:
>>> def foo(d=[]):
... d.append('a')
... return d
If
you've not tried this before, you
probably expect foo to always return
['a']: it should start with an empty
list, append 'a' to it, and return.
Here's what it actually does:
>>> foo() ['a']
>>> foo() ['a', 'a']
>>> foo() ['a', 'a', 'a']
This is because the default value for d is
allocated when the function is
created, not when it's called. Each
time the function is called, the value
is still hanging around from the last
call. This gets even weirder if you
throw threads into the mix. If two
different threads are executing the
function at the same time, and one of
them changes a default argument, they
both will see the change.
Of course, all of this is only true if
the default argument's value is a
mutable type. If we change foo to be
defined as
>>> def foo2(d=0):
... d += 1
... return d
then it will always return 1.
(The difference here is that in foo2,
the variable d is being reassigned,
while in foo its value was being
changed.)
The problem lies with the default constructor argument. You should read this question to find answer to your question: “Least Astonishment” in Python: The Mutable Default Argument
Python evaluates the default arguments once at function definition:
def init_a():
"""Initialize a."""
print("init_a")
return 1
def test(a_parameter=init_a()):
"""A test function."""
print("Execute test")
print("whatever")
test()
test()
gives
init_a
whatever
Execute test
Execute test
So your list gets defined once. You use the same list as before. This is why you should use the pattern
def a_function(a_parameter=None): # Create 'None' once
if a_parameter is None:
a_parameter = [] # Create a new list - each time