I have some question about functions which have default parameters.
import sys
from random import randint
my_list = [1,2,3]
def Veli(a, b = my_list):
my_list.append(randint(1,1500))
print a + b[-1]
print "Number of Refs:", sys.getrefcount(my_list)
print "Def args:", Veli.func_defaults
Veli(1) # This is 4
Veli(1) # We almost always obtain different result because of randint
Veli(1) # Again different results.
print Veli.func_defaults
print "Number of Refs:", sys.getrefcount(my_list)
Veli(1)
my_list = [-5] # old my_list has different address
print "Number of Refs:", sys.getrefcount(my_list) # Less than previous
print "Def args:", Veli.func_defaults
Veli(1) # Now gives same results.
print "Def args:", Veli.func_defaults
Veli(1) # Same result again...
Outputs: (Some numbers depend on which values randint has returned, of course.)
Number of Refs: 3
Def args: ([1, 2, 3],)
322
1119
740
([1, 2, 3, 321, 1118, 739],)
Number of Refs: 3
303
Number of Refs: 2
Def args: ([1, 2, 3, 321, 1118, 739, 302],)
303
Def args: ([1, 2, 3, 321, 1118, 739, 302],)
303
The following code gives you a number less than the previous one, because b and my_list is not referenced to same address anymore.
print "#ref:", sys.getrefcount(my_list) # Less than previous
Now, we have a way (the only way?) to reach b, default argument of the function:
Veli.func_defaults[0]
Sorry about my long explanation. Here is my questions:
Is this a problem? Dictionary of my module crush my_list variable then now my_list variable has default address than previous. Then function which uses global variable named my_list in its body is changing (growing) while my default argument is not. Why cannot b
see global variable named my_list
when a + b[-1]
expression is executed? I know, b
has different address with my_list (because mutual objects (like list) are guaranteed to refer to different, unique, newly created list) now, but why were Python implemented so that b
cannot see the global variables when b is a function arguments? Could you explain comprehensively?
Is there any way to get same results with Veli.func_defaults[0]? This code executed then let say, I want to change my default arguments of my function named Veli. I cannot do this with my_list, because my_list and b have different addresses. One way is changing the elements of the list, Veli.func_defaults[0]. Is there any different way(s)?
(It is not so related to code above) How can get addresses of variable? For example, how can get address of b
? I use built-in function such as __hash__
, but there should be more appropriate way.
Notes:
a) This codes may be useless for any reason, but I want to learn opinions.
b) Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39)
[GCC 4.4.5] on linux2
def Veli(a, b = my_list):
puts a reference to the object my_list
happens to refer to at that time into func_defaults
. Python never uses pass-by-reference - variables hold references and those references are always passed by value. So what's actually saved in b
, a reference (pointer), is copied and nobody remembers where it came from or bothers to update it.b
will be Veli.func_defaults[0]
if no second argument was passed, but obviously different if it is passed (well, unless of course the caller accesses func_defaults
... you should assume he doesn't).b
default to None
and use the global my_list
if b is None
- this would give you a fresh, updated copy of its reference on every call. Perhaps you should write a class and keep the default value as an attribute of self
and apply the usual (... = None): if ... is None: use = default
idiom.id
. Actually, it's implementation defined what this returns (doesn't have to be the address), as long as it's an integer that represents the object identity, i.e. distinct objects (with overlapping lifetimes) have a distinct id
and the same object always gives the same id
during its lifetime. The easy return value, which CPython chooses, is the address.