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 namedmy_list
whena + 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 thatb
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 objectmy_list
happens to refer to at that time intofunc_defaults
. Python never uses pass-by-reference - variables hold references and those references are always passed by value. So what's actually saved inb
, a reference (pointer), is copied and nobody remembers where it came from or bothers to update it.Not quite sure what you're asking, please clarify.You could, as suggested in another answer, makeb
will beVeli.func_defaults[0]
if no second argument was passed, but obviously different if it is passed (well, unless of course the caller accessesfunc_defaults
... you should assume he doesn't).b
default toNone
and use the globalmy_list
ifb 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 ofself
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 distinctid
and the same object always gives the sameid
during its lifetime. The easy return value, which CPython chooses, is the address.