I am confused by the scope of the outer function variable with respect to the inner function in Python.
It seems that if a variable in the outer function is a list or array, it can be changed by the inner function while it can not if it is a scalar. For example, the following code gives an output of c = [0,-10].
def foo1():
a = [0,1]
def foo2():
a[1] = -10
foo2()
return a
c = foo1()
Whereas the following code gives c = 1.
def foo1():
a = 1
def foo2():
a = -10
foo2()
return a
c = foo1()
Why should there be a difference with respect to the type of the variable? Does this have to do with pointers?
It doesnt have anything to do with pointers, its how lists are used, when you do list[1] = x, this is a member assignment, which is actually a “method call”. Basically when ur changing the value of a member in a list, its doing a method call, that can find the name of the list in the global name space.
In the first example, "a" is passed in as a parameter, therefore you are able to access or change it as normal. In the second example, any changes to "a" stay saved only within the inner function. To fix this you can make "a" global:
def foo1():
a = 1
def foo2():
global a
a = -10
foo2()
return a
c = foo1()
def foo():
global a
a = 10
vs
a = 0
def foo():
a = 10
What is the use of declaring global in a function instead of declaring variables right at the top. It should be cleaner this way ?
Q. What is the use of declaring global in a function instead of declaring variables right at the top?
Generally we define few regularly used constants as global variables.
>>> import math
>>> math.pi
3.141592653589793
Mathematical contants/Web Page/Servernames/URLs - which wont change over a period of time.
In general, it is not recommended to RE-DEFINE global variable or define global variables with in a function. But few exception cases are there where we are left with no option but to re-define it. Could be due to a new upgrade in old system where this variable is heavily used across.
So please go with your second approach. Define 'a' outside your
function. This also looks good & easy to read.
>>> a = 10
>>> def foo():
... a = 14 # defining a local variable called a
...
>>> a
10
>>>
>>> foo()
>>> a
10
>>> # a = 14 has no scope outside foo function
>>>
>>> def foo():
... global a # notify function to use global variable here.
... a = 15 # re-defining global ==> nt preferred it
...
>>> a
10
>>> foo()
>>> a # see now it changed here.
15
Hope this helps.
In the first case the value remains same in all the functions.
def set_globvar_to_one():
global globvar
globvar = 1
print globvar
def print_globvar():
print globvar # No need for global declaration to read value of globvar
set_globvar_to_one()
print_globvar()
The output will be 1 and 1.
But 2nd case
def set_globvar_to_one():
globvar = 1
print globvar
def print_globvar():
print globvar # No need for global declaration to read value of globvar
set_globvar_to_one()
print_globvar()
Here you get error saying globvar is not defiend, coz there is no local or global variable named globavar
That would make it ambiguous. Look at this,
a = 0
def foo():
a = 10 # *
Look at the line marked *. Are you assigning to the global a or is this a local variable a with a value 10. The interpreter has no way to knowing what you meant. Thus, the need for global.
a = 0
def foo():
a = 10 # local variable a
def bar():
global a # will be modifying global variable a in this function
a = 10 # assign 10 to global variable
In your first example "a" is not available before foo() is called. Once it is defined in the function it available outside of the function.
In the second example it is available before foo() is called butchanges to it inside the function do not affect the global version .
This example should demonstrate the difference between the two examples
#!/usr/bin/python
def foo():
global a
a = 10
print a
try:
print a
except Exception,e:
print e
foo()
print a
print "-"*70
b = 0
def bar():
b = 10
print b
print b
bar()
print b
Output:
global name 'a' is not defined
10
10
----------------------------------------------------------------------
0
10
0
If you declare it as a global, you don't have to return it.
If you don't use global, you have the function to return a.
Without global it be like this:
In [7]: def foo():
...: a = 10
...: return a
...:
In [9]: a = foo()
In [10]: a
Out[10]: 10
With global:
In [11]: a = 0
In [12]: def foo2():
....: global a
....: a = 10
....:
In [13]: a
Out[13]: 0
In [14]: foo2()
In [15]: a
Out[15]: 10
It is you who decide if you want your function to return or to use global.
It can simplify you code, it can be useful for function that calculates some constants that you don't want to call it each time.
But if use it for single procedure, prefer "return" method.
if you are using the same variable inside the loop then there will be a competition between the global and local variable . so if you want to use the value of the global variable in the loop you have to mention the 'global' keyword
It's ok to get and print the outer function variable a
def outer():
a = 1
def inner():
print a
It's also ok to get the outer function array a and append something
def outer():
a = []
def inner():
a.append(1)
print a
However, it caused some trouble when I tried to increase the integer:
def outer():
a = 1
def inner():
a += 1 #or a = a + 1
print a
>> UnboundLocalError: local variable 'a' referenced before assignment
Why does this happen and how can I achieve my goal (increase the integer)?
In Python 3 you can do this with the nonlocal keyword. Do nonlocal a at the beginning of inner to mark a as nonlocal.
In Python 2 it is not possible.
Workaround for Python 2:
def outer():
a = [1]
def inner():
a[0] += 1
print a[0]
A generally cleaner way to do this would be:
def outer():
a = 1
def inner(b):
b += 1
return b
a = inner(a)
Python allows a lot, but non-local variables can be generally considered as "dirty" (without going into details here).
So i'm trying to make a function that keeps track how many times a method is called.
for example:
a = [1,2,3,4]
a.pop()
i want to know how many times a.pop() was called so far so for this example, i would get 1.
Is there a way to do this?
This doesn't work for builtin functions, but an interesting approach would be:
def myfunction():
myfunction.counter += 1
myfunction.counter = 0
You're giving the function an attribute, so every call that attribute is updated. No global variables needed.
Built-ins are read-only. They cannot be modified.
You could use a decorator that tracks how many times the function is called. Since list is a built-in, you can't decorate or replace its pop method so you'd have to use your own list class, for example.
def counted(f):
def wrapped(*args, **kwargs):
wrapped.calls += 1
return f(*args, **kwargs)
wrapped.calls = 0
return wrapped
class MyList(list):
#counted
def pop(self, *args, **kwargs):
return list.pop(self, *args, **kwargs)
x = MyList([1, 2, 3, 4, 5])
for i in range(3):
x.pop()
print x.pop.calls # prints 3
i used the following little trick to track how many times the function was called
def myfun(s,i=[0]):
print(s)
i[0]+=1 # mutable variable get evaluated ONCE
return i[0]
>>> myfun('aaa')
aaa
1
>>> myfun('bbb')
bbb
2
Here is a simple and elegant solution for a self counting function, without any decorators, global variables, etc:
def hello():
hello.counter += 1
print(hello.counter)
hello.counter = 0
Each time you call hello(), it will print 1, 2, etc.
Let's not forget that, in Python, a function is a first-class citizen
and it has rights. And one of them is to have attributes!
If you are willing to include your method call in a function, it can be easy:
def pop_counted(a):
pop_counted.counter += 1
return a.pop()
pop_counted.counter = 0
Voilà!
Comment
This works because a Python function "knows" itself (this is a necessary feature, so that functions can call themselves recursively if desired).
If you wish to keep some information about a function, it might be better to keep it where it belongs: in an attribute of the function.
The advantage of not using a global variable is scope:
no risk of name collisions in the global namespace
the information you were keeping will vanish as soon as the function is taken off the stack, which is what you want -- no garbage left.
A bonus is that this approach will work in cases where a global variable is not really a good option, typically for nested functions where you can't declare a "global" in the outer function.
For kicks, I wrote up an answer using a decorator:
class counter:
#wraps a function, to keep a running count of how many
#times it's been called
def __init__(self, func):
self.func = func
self.count = count
def __call__(self, *args, **kwargs):
self.count += 1
return self.func(*args, **kwargs)
To use it, simply decorate a function. You can then check how many times that function has been run by examining the "count" attribute. Doing it this way is nice because:
1.) No global variables. The count is associated directly with the function.
2.) You can wrap builtin functions easily, by calling the class directly:
sum_wrapped = counter(sum)
sum_wrapped([1, 2 ,3, 4])
#outputs 10
print sum_wrapped.count
#outputs 1
Of course, this could be improved by using the Decorators module to keep the docstrings and other good things intact. Also, for an excellent overview of what decorators are, and how they work, check out this stackoverflow answer.
One approach is to create a proxy of the instance for which you want to count attribute access:
from collections import Counter
class CountingProxy():
def __init__(self, instance):
self._instance = instance
self.count = Counter()
def __getattr__(self, key):
if hasattr(self._instance, key):
self.count[key] += 1
return getattr(self._instance, key)
>>> l = [1,2,3,4,5]
>>> cl = CountingProxy(l)
>>> cl.pop()
5
>>> cl.append(10)
>>> cl.index(3)
2
>>> cl.reverse()
>>> cl.reverse()
>>> cl.count
Counter({'reverse': 2, 'pop': 1, 'append': 1, 'index': 1})
A simple way to do this is to increment a global variable each time you call the function.
counter = 0
a = [1,2,3,4]
a.pop()
counter += 1
i guess the following code will be helpful to you. you just need to make local variable global in order to access the global variable from a method
MYGLOBAL = 5
def func1():
global MYGLOBAL
MYGLOBAL +=10
def func2():
print (MYGLOBAL)
func1() #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func1() #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func1() #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func2() #this will printout 5+30=35
counter = 0
def pop():
counter += 1
print counter
#other function code
a = [1,2,3,4]
a.pop()
this should solve your issue and you should be able to see whats being counted. +
every time you call the function the counter is going to be increased and printed with every pass of the function.
IF ITS BUILT IN:
counter = 0
def newfunction():
a = [1,2,3,4]
a.pop()
counter += 1
print counter
the logic in this is that it will call your new function go into the function that is premade then step out of the built in function and then go on to mark the counter as increased. the output your counter.
Just define a global statement in your function.
count = 1
def your_func():
global count
print(count)
count= count +1
Just define a global variable and increment it inside function.
a = 0
def some_function():
global a
a+=1
<..Your code.>
This will automatically be incremented as function is used and you can access it globally.
I did it copying the way JavaScript console.count() method works. That's my code:
class Terminal(object):
__count_names = []
def count(self, name='default'):
# check if name already exists
i = next((self.__count_names.index(item) for item in self.__count_names if item['name'] == name), None)
# if name argument does not exist register it
if i is None:
dictionary = { 'name': name, 'count': 1 }
self.__count_names.append(dictionary)
# if exists increment 'count'
else:
dictionary = self.__count_names[i]
dictionary['count'] += 1
self.__count_names[i] = dictionary
# finally print name and count
print(f"{dictionary['name']} : {dictionary['count']}")
Your code should look like this:
terminal = Terminal()
def myFunc():
terminal.count("myFunc")
myFunc()
myFunc()
myFunc("myFunc")
Output:
myFunc: 1
myFunc: 2
myFunc: 3
myFunc: 4
An example from Datacamp, using decorators:
def counter(func):
def wrapper(*args, **kwargs):
wrapper.count += 1
# Call the function being decorated and return the result
return func(*args, **kwargs)
wrapper.count = 0
# Return the new decorated function
return wrapper
# Decorate foo() with the counter() decorator
#counter
def foo():
print('calling foo()')
foo()
foo()
print('foo() was called {} times.'.format(foo.count))
# output
calling foo()
calling foo()
foo() was called 2 times.
I solve this with closure. This is a generic function:
def counter(fn):
cnt=0
def inner(*args,**kwargs):
nonlocal cnt
cnt+=1
print('{0} has been called {1} times'.format(fn.__name__,cnt))
return fn(*args,**kwargs)
return inner
a=[1,2,3,4]
a_pop=counter(a.pop)
It's so basic it should work. I want a function that adds a value to something
There must be something I don't know about python 3, so here we go.
x = 0
def foo(x=x): ##### with out x=x there is a error
x = x + 1 # option one
x = 1 # option two
# when we run it
foo()
print(x)
# it returns 0, it should return 1
x is a local variable in foo(); Assigning x as a default value for a keyword argument won't make it any less a local.
If you wanted it to be a global, mark it as such:
x = 0
def foo():
global x
x = x + 1
print(x)
foo()
print(x)
but you probably just wanted to pass in the value as an argument instead:
def foo(value):
return value + 1
x = 0
print(x)
x = foo(x)
print(x)
This is basically and example of scoping rules. The variable x within foo is local to foo, so nothing that happens to the local x changes anything outside foo, including the global x with which is actually a different variable. When the interpreter exits foo the global x comes back into scope and it hasn't changed from its initial value of 0. The function header foo(x=x) defines a local x whose default value is the global x. The interpreter allows it but it's generally considered bad programming practice to have the same variable name representing two variables because it leads to this kind of confusion.