I'm currently developing some things in Python and I have a question about variables scope.
This is the code:
a = None
anything = False
if anything:
a = 1
else:
a = 2
print a # prints 2
If I remove the first line (a = None) the code still works as before. However in this case I'd be declaring the variable inside an "if" block, and regarding other languages like Java, that variable would only be visible inside the "if".
How exactly variable scoping works in Python and what's the good way to program in cases like this?
Thanks!
As a rule of thumb, scopes are created in three places:
File-scope - otherwise known as module scope
Class-scope - created inside class blocks
Function-scope - created inside def blocks
(There are a few exceptions to these.)
Assigning to a name reserves it in the scope namespace, marked as unbound until reaching the first assignment. So for a mental model, you are assigning values to names in a scope.
I believe that Python uses function scope for local variables. That is, in any given function, if you assign a value to a local variable, it will be available from that moment onwards within that function until it returns. Therefore, since both branches of your code are guaranteed to assign to a, there is no need to assign None to a initially.
Note that when you can also access variables declared in outer functions -- in other words, Python has closures.
def adder(first):
def add(second):
return first + second
return add
This defines a function called adder. When called with an argument first, it will return a function that adds whatever argument it receives to first and return that value. For instance:
add_two = adder(2)
add_three = adder(3)
add_two(4) # = 6
add_three(4) # = 7
However, although you can read the value from the outer function, you can't change it (unlike in many other languages). For instance, imagine trying to implement an accumulator. You might write code like so:
def accumulator():
total = 0
def add(number):
total += number
return total
return add
Unfortunately, trying to use this code results in an error message:
UnboundLocalError: local variable 'total' referenced before assignment
This is because the line total += number tries to change the value of total, which cannot be done in this way in Python.
There is no problem assigning the variable in the if block.
In this case it is being assigned on both branches, so you can see it will definitely be defined when you come to print it.
If one of the branches did not assign to a then a NameError exception would be raise when you try to print it after that branch
Python doesn't need variables to be declared initially, so you can declare and define at arbitrary points. And yes, the scope is function scope, so it will be visible outside the if.
i'm quite a beginner programmer, but for what i know, in python private variables don't exist. see private variables in the python documentation for a detailed discussion.
useful informations can also be found in the section "scopes and namespaces" on the same page.
personally, i write code like the one you posted pretty much every day, especially when the condition relies in getting input from the user, for example
if len(sys.argv)==2:
f = open(sys.argv[1], 'r')
else:
print ('provide input file')
i do declare variables before using them for structured types, for example i declare an empty list before appending its items within a loop.
hope it helps.
Related
basically what the title says.
say i got a function definition
def add_one (num1):
numOut = num1 +1
return numOut
and im calling the function as follows
num1 = 11
numOut = add_one (num1)
is this considered bad practice, as we are naming two different objects with the same name, or is it good practice s it increases readability? Or is it something that I am missing completely?
(also checked pass variable to function using same name and Is it normal to use in the function some variable with the same name as it function? but they do not refer to python)
First, lets talk about scopes:
In python and a lot of other languages variables exist within its scope. This means that if you create a variable inside a scope it will stop existing when you leave that scope.
Variables on a outer scope are also accesible within an inner scope but if you asing something to that variable then it will be redeclared as a local variable inside this scope. Meaning that that variable will be diferent than the one on the outer scope.
If you ask me, I don't think is a bad practice to use the same name as the arguments of your functions. In fact I would call bad practice trying to avoid that as you would end up tryining to figure out new names for different variables that have the same meaning.
What you should avoid is to use variables that are not on the local scope (no matter what language are you using).
Try not to worry about that. Sometimes, it can make sense for argument variables to have the same name as the function's parameters, but you never want to enforce that. Your primary concern is that the code that defines a function should make sense regardless of how it might be called.
Remember that you might want to call a function passing some expression other than a plain variable, or that you might want to call the same function more than once in the same scope with different arguments. Trying to match the parameter names of a function you're calling only makes sense if you can't think of some better name for your variables.
When doing this there are always things to consider:
Am I overwriting the name of a variable I might need?
Am I overwriting the name of the function?
In the function's context, did the variable already exist?
However, in python the last point does not matter as outside variables (excluding globals) cannot be accessed within the function's scope.
In the following example, the name of the function is overwritten (which is bad):
def myFunc (a, b):
myFunc = 2
if a > 2 and a > b:
return a
return b
In this next example the context / scope of the function changes what variables you have access to in languages that are not python:
x = 3
def myFunc (a, b):
if a + x > b + x: # in some languages this would work, but in python this is an error because x is not defined in the function.
x = 5 # here x == 5, because we have redefined it. x is still 3 outside of our function though.
return a + x
return b
In the second example, using a variable's value before setting the value is regarded as bad practice, but you don't need to worry about that in python because it's not possible to do.
something that I am missing completely
Important feature of functions in python is their reusability, imagine changing requirementz force you to use your function
def add_one (num1):
numOut = num1 +1
return numOut
not for one, but for 2 different variables, you might end with
num1 = 11
num2 = 15
numOut = add_one (num1)
numOut2 = add_one (num2)
Now you have some variables which names are same like in function and same which are different. If you use different names from start not such problem occurs, for example:
x1 = 11
x2 = 15
x1out = add_one(x1)
x2out = add_one(x2)
I'm having trouble understanding why my code works the way it does. Right now, I'm initializing a global variable i set to 0, so it makes sense that if I print it anywhere outside my function, I should get 0.
When I print i inside the function, I get 6 and 12 after calling the function twice. I think this is because the global i is 0, but some local i variable isn't. However, when I'm calling reach_load with i as a parameter, aren't I passing in the global value of i (0)?
import sys
d = {}
size_0 = sys.getsizeof(d)
i = 0
def reach_load(d, size_0, i):
size_0 = sys.getsizeof(d)
while size_0 == sys.getsizeof(d):
d[i] = i
i += 1
print(i)
reach_load(d, size_0, i)
reach_load(d, size_0, i)
i is a purely local variable here. It is not linked to the global variable of the same name; the fact that you've called it the same thing makes no difference.
I think you've confused two things here: The global i doesn't change, but d does (as it's mutable). i starts off as 0 each time you call reach_load, but since the dictionary is bigger, the while loop will run longer and therefore, a higher number will be printed.
Because the i parameter to reach_load is a formal parameter it's local to the function. It's a local variable with the same label. If you really want to increment the global one, then put global i it the top of the function. However, this is considered bad design. If you need to keep some state define a new object with class to keep it.
When you call i in your function at line 10, in d[i], the Python interpreter you're using first checks for that variable in the local scope. If it doesn't find it, it then checks in the next scope, which in your case happens to be the global one. At this point, you are calling the global variable.
However, as soon as you do i += 1, i becomes a local variable since it's now defined in the local scope.
I'm not 100% on what you expect to happen, though. Are you wondering why the second run of the function returns different results?
If so, I believe your problem lies with your size_0 variable.
You define size_0 globally, but at the very start of your function, re-define it locally and that's the definition your function ends up using while the global size_0 ends up not being used at all. If you were to remove:
size_0 = sys.getsizeof(d)
from your function, each run would produce the same result.
What really helps to figure out these issues is adding various code that helps track the execution of your code. In this example, you could add a bunch of print() statements at critical points, such as print(d, size_0) # inside and outside the function.
It's difficult to give anymore advice as it's not clear to me what the code is supposed to accomplish.
I have a Python module which consists of a number of different functions.
Say my first function returns a variable which I want to use twice in the second and the second returns a variable which I want to use four times in the third function ( . . . and so on).
Is it better to declare the variables that I will want to use throughout the entire module as global and then call the function that returns said variable once to define it globally rather than to call functions more than once in order to use the variables they return?
Am I correct in saying that this is a trade-off between safety (not using global variables) and efficiency (not executing each function more than once if possible)?
def fn_for_reading_file():
# (Insert code for prompting user for filename, opening and reading file)
global file_as_string
# (Insert code for assigning user's file to file_as_string)
return file_as_string
fn_for_reading_file()
def extract_data_from_string():
global my_list = []
# (Insert code for going through return_file_as_string and appending data to my_list)
return my_list
extract_data_from_string()
def another_fn():
# (Insert code which uses file_as_string and my_list)
return fn_output
another_fn()
I would try to reframe the problem you're thinking about. If you're only thinking in terms of functional programming then yes, you're correct in that safety vs. more code is the basic trade off you're looking at.
However, there are a number of ways to get around your dilemma by reframing the problem. I obviously don't know what your code looks like, but it might be meaningful to think about building this functionality into a class. Rather than using global variables, set those values as class attributes with appropriate getters/setters, and then structure the module such that your functions become methods.
I saw in a book about language description that says
On the other hand, a name can be bound to no object (a dangling pointer),
one object (the usual case), or several objects (a parameter name in a
recursive function).
How can we bind a name to several objects? Isnt that what we call an array for example where all elements have the same name but with index? For a recursive function like the example here:
x = 0
def f(y):
global x
x += 1
if x < 4 :
y +=100
f(y)
else: return
f(100)
Is the name y binded with multiple values that are created recursively since the nametable has already the y name binded to an initial value which is being reproduced with recursion?
EDITED Just press here Visualizer and see what it generates. :)
No.
A name is bound to one single object . When we are talking about Python - it is either bound to a single object in a given context, or do not exist at all.
What happens, is that the inner workings may have the name defined in several "layers" - but your code will only see one of those.
If a name is a variable in a recursive function, you will only see whatver is bound to it in the current running context - each time there is a function call in Python, the execution frame, which is an object which holds several attributes of the running code, including a reference to the local variables, is frozen. On the called function, a new execuciton frame is created, and there, the variable names are bound again to whatever new values they have in the called context. Your code just "see" this instance.
Then, there is the issue of global variables and builtin objects in Python: if a name is not a local variable in the function execution context, it is searched in the globals variables for the module (again, just one of those will be visible).ANd if the name is not defiend in the globals, them, Python looks for it in globals().__builtins__ that is your last call.
If I understand you correctly, you're asking about what rules Python has for creating variables in different scopes. Python uses lexical scoping on the function level.
It's hard to tell exactly what you're getting at with the code you've written, but, while there may be a different value associated with y in different scopes (with a value of y defined at each level of recursion), your code will only ever be able to see one at a time (the value defined at the scope in which you're operating).
To really understand scoping rules in Python, I would have a look at PEP 227. Also, have a look at this Stack Overflow question.
Finally, to be able to speak intelligently about what a "name" is in Python, I suggest you read about how Python is a "Call-By-Object" language.
At this point, we are capable of understanding that, instead of a "nametable", python uses a dictionary to hold what is accessible in a given scope. See this answer for a little more detail. The implication of this is that you can never have two of the same name in a single scope (for the same reason you can't have two of the same key in a python dictionary). So, while y may exist in a dictionary for a different scope, you have no way of accessing it, since you can only access the variables in the current scope's dictionary.
The key is:
several objects (a parameter name in a recursive function).
The passage is almost certainly not referring to arrays, but simply to the fact that in a recursive function (or any function, but a recursive function is likely to have multiple activations at one time), a parameter may be bound to a different value in each recursive call.
This does not mean that you can access each such object in every stack frame; indeed the point of the technique is to ensure that only one such value is accessible in each stack frame.
Firstly, you should mention in the question that the sentence from the book is not related explicitly to Python (as jsbueno wrote, one name is bound to exactly one object in Python).
Anyway, name bound to no object is a bit inaccurate. Generally, names are related to variables, and name related to a dangling pointer is the name of that pointer variable.
When speaking about the variable scope (i.e. the part of code where the variable is used), one variable name can be used only for a single value at a time. However, there may be other parts of code, independent on the one where we think about that variable. In the other part of code, the same name can be used; however, the two variables with the same name are totally isolated. This is the case of local variables also in the case of function bodies. If the language allows recursion, it must be capable to create another isolated space of local variable even for another call of the same function.
In Python, each function can also access outer variables, but it is more usual to use the inner, local variables. Whenever you assign a name some value, it is created in the local space.
How do I obtain the non-local variables for the current scope? The functions vars, locals, and globals exist, but is there a function to get the nonlocals?
Why aren't the nonlocals listed when calling vars?
Update
My issue is that there's no way to enumerate the variables available in the current scope, as neither vars or globals includes the non-locals AFAICT.
I frequently use vars in code such as the following:
'{meh[0]}/{meh[3]} {a}{b}{c}'.format(**vars())
Which fails if any of these variables are in the scope of a containing function.
From within running code, you can easily get the names of the nonlocal variables - but retriving their content in a way a call to locals gets you a dictionary is a bit trickier.
The used nonlocal variable names are stored in the current running code object, in the co_freevars attribute.
So, getting the nonlocal names is a matter of:
names = inspect.currentframe().f_code.co_freevars
The contents for these variables, however, are stored in the __closure__ attribute (func_closure, in Python 2), of the function object instead. (Not the code object). The problem is that, without "aid from outside", there is no easy way for a running code to get to the function object it is running on. You can get to the frame object, which links to the code object, but there are no links back to the function object. (For a top level defined function one could explicitly use the function known name, as used in the def statement` but for an enclosed function, that is returned to a caller, there is no way of knowing its name either).
So, one has to resort to a trick - getting all the objects that link to the current code object, by using the gc module (garbage collector) - there is a gc.get_referrers call - it will return all the function objects that link to the code object one holds.
So, inside a function with non_local variables one could do:
import inspect, gc
from types import FunctionType
def a(b):
b1 = 2
def c():
nonlocal b1
print (b)
code = inspect.currentframe().f_code
names = code.co_freevars
function = [func for func in gc.get_referrers(code) if isinstance(func, FunctionType)][0]
nonlocals = dict (zip(names, (x.cell_contents for x in function.__closure__ )))
print(nonlocals)
return inspect.currentframe()
return c
c = a(5)
f = c()
And therefore retrieve the names and values of the nonlocals. But this won't work if you have more than one instance of that function around (that is, if the function of interested was created more than once with more than one call to the functin that generates it) - becasue all of those instances will link to the same code object. The example above, assumes there is only one function running with the current code - and would work correctly in this case. Another call to the factrory function would create another function, with potentially other values for the nonlocal variables, but with the same code object - the function = list genrator above would retrieve all of those, and arbitrarily pick the first of those.
The "correct" function is the one on which the current code is executing - I am trying to think of a way of retrieving this information, but can't get to it. If I can, I will complete this answer, but for now, this can't help you to retrieve the nonlocals values values.
(just found out that trying to use "eval" with a nonlocal variable name won't work as well)
It looks like that the only thing linking the current running frame to the function object where the nonlocal variables values are held is created at run time inside the native side of the Python interpreter. I can't think of a way of getting to it short of using the ctypes module to look at interpreters data structures at runtime, which would, of course, be unsuitable for any actual production code.
The bottom line: you can reliably retrieve the nonlocal variable names. But it looks like you can't get their value given their name as a string (nor rebind then).
You could try opening a feature-request for a "nonlocals" call on Python's bug tracker or on Python-ideas mailing list.