When running my lint, I am getting the error below:
Redefining name 'tmp_file' from outer scope (line 38) (redefined-outer-name)
Here is my snippet of code in that line:
tmp_file = open('../build/' + me_filename + '.js','w')
That happens because you have a local name identical to a global name. The local name takes precedence, of course, but it hides the global name, makes it inaccesible, and cause confusion to the reader.
Solution
Change the local name. Or maybe the global name, whatever makes more sense. But note that the global name may be part of the public module interface. The local name should be local and thus safe to change.
Unless... your intention is for these names to be the same. Then you will need to declare the name as global in the local scope:
tmp_file = None
def do_something():
global tmp_file # <---- here!
tmp_file = open(...)
Without the global declaration, the local tmp_file will be unrelated to the global one. Hence the warning.
Solution
Create main() function which be holding all the main logic etc.
def pow(x):
return x ** 2
def add(x, y):
return x + y
def main():
x, y = 2, 4
print(pow(x))
print(add(x, y))
if __name__ == '__main__':
main()
Explanation
This works, because every new function instance creates a new local scope.
Open with with
Apart from #Rodrigo's correct answer about scopes: if your tmp_file is just that, a temporary file, you can use
with open('../build/' + me_filename + '.js','w') as tmp_file:
# do something
in both cases. It clearly defines where your tmp_file is going to be used.
It is the recommended way of dealing with variables whose scope needs to be clearly bounded.
Error description
Pylint has a built-in description:
pylint --help-msg=redefined-outer-name
gives
:redefined-outer-name (W0621): Redefining name %r from outer scope
(line %s) Used when a variable's name hide a name defined in the
outer scope. This message belongs to the variables checker.
You get this error if you have defined the same variable in multiple places like outside the def and inside the def.
If you are using the single variable define it as global variable_name and use global keyword all the places. Else please rename the other variables.
Related
Just a beginner question about local and global scope in python
X = 100
#is X a global variable?.We defined it outside the function scope
def foo():
print(X)
return X
#it prints 100 and even returns it
def foo():
X = X + 10
#local error
#UnboundLocalError: local variable 'X' referenced before assignment
def foo():
global X
# if X is a global variable why specify again?
X = X + 10
return X
To modify global copy of a variable you need the to use the global keyword, but you don't need global if you are only accessing that.
from the python website:
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.
this means that you can access a global variable inside a function without a global keyword. if you want to change it though, you must use the global keyword beforehand.
global and nonlocal are very strange things when I was a beginner.
Just think about it: why do we need them in Python?
It is because we don't need var, let and such similar things to declare variables.
Think about Javascript, it is dynamic script language too and very alike to python, but it needs var or let or const to declare variables.
The most important thing of declaring variables is to determine scope.
So, in Python, our variables have implicit default scope: current scope where they are defined, and if we want to change scope of some variables, we need use global or nonlocal explicitly .
All names on the left side of = mean to define variables.
Before executing code of some certain scope, Python will pre-compute all local variables, which are those on the left side of =. This is why you got UnboundLocalError: local variable 'X' referenced before assignment in:
def foo():
X = X + 10
So, if we look up those names not in defined current scope, just
follow the rules of scope chain: up, up, up and until built_in.
Remember: scope of any name on the left side of = is default current scope, and you have to assign it(bind something to it) before referring it.
I want to define a Python function doing:
1. Check if a variable already exist.
2. If not, create it as a global variable (because I want to use it outside the function).
def foo():
try:
x
except NameError:
global x
x = 1
else:
pass
foo()
print(x)
Then there is an error:
SyntaxError: name 'x' is used prior to global declaration
How to solve this? Thank you :)
Something like this could work.
def foo():
if not('x' in locals()):
global x
x = 1
foo()
print(x)
just check if the x variable exists.
you could also check if a variable is declared as global
if not('x' in globals()):
Just declaring a variable as global at the top of your function won't create it - so this form works:
def foo():
global x
try:
x
except NameError:
x = 1
The key thing to understand here is that when Python compiles a function, it "bakes" each variable inside the function as either a local, nonlocal, or a global (or builtin) variable - any access to that variable will have either one or the other relevant bytecode. The "global" declaration thus affects the whole function, regardless of were it is - and since tryig to access a variable before the global statement would look ambiguous, the error you saw is forced.
But since you are at it - are you sure you want to do it?
global variables are good for having values that can be shared in functions in a module - but then, even if they are to be initialized in the call to an specific function, they should be declared in the module body, and properly documented. If you can't have the final value at module load time, just assign it to None.
I cannot quite find a good description on how import works when importing your own files.
I was having trouble importing a file with a global variable and managed to get it to work when I put the global variable just before the files main function.
Can someone explain why it works this way?
A quick run down on how import actually works.
It did not work when I did this (pseudocode):
file1:
import file2
file2.main()
file2:
main():
glob_var = 0
def add():
global glob_var
glob_var += 1
add()
But worked if I put the variable first like this:
file1:
import file2
file2.main()
file2:
glob_var = 0
main():
def add():
global glob_var
glob_var += 1
add()
'main' is just a method. Variable inside a method is local by definition. Thats why 2nd way is working.
The reason it didn't work is because you are declaring the global variable inside of main. (you did miss the colon after definition of main which makes it confusing but looking at the indentation I suppose it's a definition). Global variables have to be defined outside the scope of any local function. This is a case of nested function definition.
You can do without global variables as well if that's what you are looking for. If however you want to use the variable defined in main inside a nested function then you can do the following:
In python 3 there is a way to get this thing done however using the nonlocal keyword
def main():
var = 10
def nested_fun():
nonlocal var
var = var + 1
As you see we do not need a global variable here.
Edit: In case of python 2 this does not work. However you can use a list in the main and modify that list inside nested function.
def main():
var = [10]
def nested_fun():
nonlocal var
var[0] = var[0] + 1
If I understand the question correctly, it's regarding the global variable and have nothing to do with importing.
If you want to define a global variable, it has to be defined in module level. The main function is not the global scope, that's why the first code does not work as expected. By moving the variable declaration outside of main, it would be defined in global scope, so the add method can access it using as a global variable.
I think we have to begin with what global statement means. From the docs:
It means that the listed identifiers are to be interpreted as globals.
The important point is it's only about interpretation, i.e. global does not create anything. This is the reason, why your first example does not work. You are trying to add +1 to something not existing. OTOH, global_var = 100 would work there and it would create a new global variable.
I have a directory structure like this:
home/
main.py
lib/
mylib/
Textfile_Class.py
Excelfile_Class.py
globals.py (has all the global variables declared here)
functions.py
I created an object of Textfile_class in main.py using
txt = TEXT(file).
Now, I want to use this variable txt during creating object of Excelfile_Class for some operations (eg, if the value of a variable in txt object is 5, then do certain action in Excelfile_Class )
In Excelfile_Class, I am also importing all the global variables. String variables are accessible there but I dont know why this object txt is not accessible there. Wherever I am refering to txt in Excelfile_Class(self.line_count = txt.count), I am getting below error: AttributeError: 'NoneType' object has no attribute 'count'
Please help me to know why this is happening even though I have defined all the variables in a seperate file and importing those in all the files.
Eg:
main.py
path = os.path.abspath('./lib')
sys.path.insert(0, path)
from mylib.Textfile_class import *
from mylib.Excelfile_Class import *
from mylib.globals import *
from mylib.functions import *
if __name__ == "__main__":
txt = TEXT(file)
xcel = EXCEL(file)
Eg globals.py
global txt, xcel
txt=None
xcel=None
Eg Textfile_class.py
from globals import *
class TEXT:
def __init__(self, filename):
self.count = 0
with open(filename) as fp:
for line in fp:
self.count = self.count + 1`
Eg Excelfile_Class.py
from globals import *
class EXCEL:
def __init__(self, filename):
self.line_count = 0
self.operation(filename)
def operation(self, file):
self.line_count = txt.count
if self.line_count:
self.some_operation()
else:
self.other_operation()
When you assign a value to a variable name inside a function, you're not working with the global version of the variable any more, instead you have a completely new variable.
You have to use global keyword inside the function to indicate you're working with a global variable.
From Python Doc FAQ
What are the rules for local and global variables in Python?
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function’s body, it’s assumed to be a local. If a variable is ever assigned a new value inside the function, the variable is implicitly local, and you need to explicitly declare it as ‘global’.
Read more...
Example:
x = None # x is momdule-level global variable
def local():
x = 5 # assign 5 to x, here x is a new variable, global x is not affected.
def glob():
global x # indicate we'll working with the global x.
x = 5 # this affect the global variable.
def print_global():
print(x) # Just print the global variable.
local()
print_global() # Prints None
glob()
print_global() # Prints 5
So, every time you refer to txt inside a function, you have to tell the context you'll be working with the global version of txt.
Other thing can be happening!
Python is interpreted, that means it execute the code line by line, if in the others modules (not in the main module) you have code trying to access txt before some value be assigned
if __name__ == "__main__":
txt = TEXT(file)
, then you'll get the same error.
A recommendation:
Try to avoid the use of global variables, you already know that isn't a good practice and it leads to unestable code.
If your problem is that you want to txt and xcel to be available at any time anywhere, you could use the pattern Singleton (warning, Singleton is considered an anti-pattern ref)
I will post an example for you, but before I will encorage you to redesign your program, I ensure you it will be a good exercise!
Singleton example: (again this is an anti-pattern, but I preffer it to nude global variables).
class Globals(object):
__instance = None
def __init__(self):
class wrapped_class:
def __init__(self):
self.txt = None
self.excel = None
if (Globals.__instance is None):
Globals.__instance = wrapped_class()
def __getattr__(self, attrname):
return getattr(self.__instance, attrname)
def __setattr__(self, attrname, value):
setattr(self.__instance, attrname, value)
glob = Globals() # Since __instance is None this will instantiate wrapped_class and save the reference in __instance
glob.txt = "Txt example" # Modify the txt attribute of __instance.
glob_1 = Globals() # Since __instance is not None it stays as it is.
print(glob.txt) # Prints "Txt example"
print(glob_1.txt) # Prints "Txt example"
It is quite hard to tell where your problem is without having the code or the stack trace but I would strongly advice that you read some documentation about Python best practices, the use of global variables and naming conventions. This by itself might solve your issues.
Naming conventions might sound silly but those things and other syntax-related choices do matter in python.
Also, you seem to be missing __init__.py file in your module which may or may not be important depending of the python version you are using.
Here are a few links to get you started:
https://www.python.org/dev/peps/pep-0008/#naming-conventions
https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
http://www.python-course.eu/global_vs_local_variables.php
http://gettingstartedwithpython.blogspot.be/2012/05/variable-scope.html
http://c2.com/cgi/wiki?GlobalVariablesAreBad
I dont know why it happened like that. If anyone knows they can tell.
The problem got resolved when I used the method given in Using global variables between files in Python.
So, finally I put all the global variables in a function in globals.py and instantiated that once in main.py. Then, I used from mylib import globals and referenced the global variables inside the classes as globals.txt and it worked fine.
I keep getting an unbound local error with the following code in python:
xml=[]
global currentTok
currentTok=0
def demand(s):
if tokenObjects[currentTok+1].category==s:
currentTok+=1
return tokenObjects[currentTok]
else:
raise Exception("Incorrect type")
def compileExpression():
xml.append("<expression>")
xml.append(compileTerm(currentTok))
print currentTok
while currentTok<len(tokenObjects) and tokenObjects[currentTok].symbol in op:
xml.append(tokenObjects[currentTok].printTok())
currentTok+=1
print currentTok
xml.append(compileTerm(currentTok))
xml.append("</expression>")
def compileTerm():
string="<term>"
category=tokenObjects[currentTok].category
if category=="integerConstant" or category=="stringConstant" or category=="identifier":
string+=tokenObjects[currentTok].printTok()
currentTok+=1
string+="</term>"
return string
compileExpression()
print xml
The following is the exact error that I get:
UnboundLocalError: local variable 'currentTok' referenced before assignment.
This makes no sense to me as I clearly initialize currentTok as one of the first lines of my code, and I even labeled it as global just to be safe and make sure it was within the scope of all my methods.
You need to put the line global currentTok into your function, not the main module.
currentTok=0
def demand(s):
global currentTok
if tokenObjects[currentTok+1].category==s:
# etc.
The global keyword tells your function that it needs to look for that variable in the global scope.
You need to declare it global inside the function definition, not at the global scope.
Otherwise, the Python interpreter sees it used inside the function, assumes it to be a local variable, and then complains when the first thing that you do is reference it, rather than assign to it.