I often have the following code which either leads to variable shadowing or to a multiplication of local variables
def whenadult(age):
return 18 - age
age = 5
needtowait = whenadult(age)
age has the same logical role both when passed to the function as in the main code so I would like to avoid creating something like l_age in whenadult.
What is the pythonic way to solve the "shadowing vs. variable multiplication" dilemma?
UPDATE: following up on some comments I want to make it clear that I was looking for a Python best practice (as opposed to local vs. global variables scope)
The fact that the local variable (and function parameter) age happens to have the same name as a variable somewhere else in your program is irrelevant. The whole point of local variables is that they only live within the local scope of the function they're defined in.
The fact that the local variable has the same name as the variable used elsewhere as an argument is especially not a problem. In fact, it's very common in real-life code. For example, picking a random stdlib module, the 3.3 version of cmd, the Cmd.onecmd method has a variable named line, and it passes it as an argument to the self.default method, which binds it to a parameter that's also named line.
The fact that the variable used for the argument happens to be a global variable that you could have accessed, if you didn't have a local variable of the same name, is not a problem unless you actually wanted to access that global variable. Which you didn't want to in your existing code, and almost never should want to. In this case, and in most real-world cases, it's simply a coincidence that means nothing and affects nothing, not a problem you have to solve.
The problem you're having is that PyCharm can't guess whether you wanted the global age to be accessible in whenadult. Is it possible (if not in this trivial case, maybe in more complex cases) that a human might be similarly confused, slowing down his comprehension of your code? Or that you'll one day have to write code in some environment where your code reviewers or teacher or whatever will reject your code because it doesn't pass some linter with no warnings? Maybe.
But really, in any such environment, they'd probably complain about you using global variables in the first place. And you really don't need to here. The only reason age is a global is that it has to be accessible to the top-level code. If you move that code into a function, age can become a local in that function. For example:
def whenadult(age):
return 18 - age
def main():
age = 5
needtowait = whenadult(age)
main() # possibly with an if __name__ == '__main__' guard
This will make PyCharm happy, and any linter tools, and any easily-confused or rigidly-minded human readers. It'll even make your code a tiny bit faster. On the other hand, it's more code to read—only three lines and one indent, but then the whole program is only eight lines long. So, it's a tradeoff that you can make on a case-by-case basis.
Whenever I got the warning of shadowing variable in PyCharm. I would try to rename the local variable to use the underscore prefix as the convention. That's another way to consider in addition to wrap global variables into a main() function.
def whenadult(_age):
return 18 - _age
age = 5
needtowait = whenadult(age)
PyCharm is going out of its way to prevent you from accidentally accessing(usually due to typos) a variable from the outer scope because doing so can create really nasty bugs.
Short Answer:
Most executables don't need to access the global state, so follow this structure that makes main a python function:
def helper_function():
# a function that will be used by main()
.
.
.
def main():
# make MAIN a function.
helper_function()
if __name__ == '__main__':
main()
# DONT define any variables here in this GLOBAL scope
Related
when should we actually create a function that has parameters / arguments?
today I made a programming project. Then it occurred to me when should I actually create a function that has parameters .. I usually create it when there is a global value / variable and that value must exist in some function then I make that value the argument of the function .. did I do it right? or wrong? if wrong what are the best practices for doing it?
varGlobal = "test"
def foo():
print(varGlobal)
# or
def foo(parm):
print(parm) # parm -> varGlobal
def foo():
ask = input("ask")
print(ask)
# or
def foo(parm):
print(parm) # parm -> global user input
It's usually a good idea to use parameters. Consider what the purpose of the function is. Parameterized functions are more generally useful than non-parameterized functions.
If the first case, is whatever foo does applicable only to a single value, or could it be useful for arbitrary values, regardless of what variable might refer to them? In the former case, you are stuck using varGlobal. In the latter, the call can always use foo(varGlobal) if that's the necessary argument.
In the second, might foo be useful to someone who already has a value, and doens't need to call input? In the former case, you are stuck calling input. In the latter, the caller can always use foo(input()) or the like if they really need to call input.
I would strongly suggest that you should use parameters and arguments in every function. it simply makes the whole process of design simpler.
You can clear see what data the function uses, and what it returns.
The only use of global values (either module globals, or globals imported from other modules are :
Module or application wide constants
Module or application wide function or classes (which are in Python efectively module level 'globals'.
Your functions should always return values and never change a global value (by definition if you stick to the above list that you wont be changing anything).
In my opinon using the 'global' keyword is never needed (in 8 years of coding I have never needed it, or identified a reason to use it).
Using global variables is bad practice in any language GlobalVariablesAreBad
Global variables can be used if you need to access or modify the variable in several methods/classes in the same module.
Remember you need to point global my_global_variable to modify the variable.
Parameters are variables needed in the method to do the processing. These variables should live locally in the method. If you need to retrieve something from the method, you should add a return statement. Also, if you need to return several variables you can return as tuple.
So, in this way, you're organizing your code, making all variables visible to other people. Also I recommend you to use docstrings to fully document your methods, variables and processing.
When we need to solve the same sort of question but with different arguments. So you don't have to write the same function over and over again. Let's say you want to write a function that will return the square of the provided number as an argument.
So you write
def square(num):
return num*num
So every time you need to have square of a number..you just put that number in place of the argument and not write the whole function again.
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.
In one of my programs ,
def travel():
travel.frate=[]
travel.s=0
in this,the teacher told me to use module name to declare global variables.
like travel.frate and travel.s=0. She didn't tell why it is so.could some one please explain why we are using this?? She told me to use this because global variables couldn't be declared in my computer.
travel.s gives you a variable with identical scope to the function itself -- this is equivalent to a static variable in C. This means that the value of travel.s isn't deleted from memory as soon as travel() exits, as would be the case for s defined within the travel function.
To state it a little differently, the value persists across multiple calls to the function, unlike a local variable which has a new value assigned each time.
By the way -- Python does have module-scoped variables (these are what the "global" keyword refers to in Python); your teacher was thus somewhat inaccurate/misleading in the guidance given.
One could use a module-scoped variable like so:
s = 0
def travel():
global s # this lets the travel function update the value
s = s + 1 # ...so that the change here persists across multiple calls
All that said -- use of module-level variables is often a bad practice and a code smell in Python; hopefully, you'll be learning object-oriented design later in your course.
On a Python assignment, I had to make the following two functions:
move(board, move)
undomove(board, move)
Having an argument with the same name as the function seems like a bad practice to me. I already contacted the professor to change it, but out of curiosity, is it possible to call the move function from inside the undomove, or to use recursion on the move? Inside these functions, move refers to the argument.
(Python 3, if it matters)
You can get a handle on move (the function), however it will require some additional gymnastics.
def move(move):
print(move,"inside move")
def undomove(move):
print (move,"inside undomove")
this_mod =__import__(__name__)
this_mod.move(move)
if __name__ == '__main__':
move(1)
undomove(2)
Generally though, I would definitely avoid naming a local variable with the same name as a function that I will need in that function.
As far as style is concerned, creating a function def move(move): ... is definitely a little weird, and it would make the casual reader think that you're trying to write a recursive function, so I would definitely avoid that. Writing undomove(move) when move is already defined in the module scope as a function is a little less weird, but it still might cause confusion at a quick glance (is it a local variable? is it the function?) so I would probably avoid that one as well.
There are a number of options here, but ruling out the simplest (renaming move), there are a few others.
Firstly, you could create another name for the function, so you can use that when move gets overridden:
def move(...):
...
move_ = move
def undomove(..., move):
move_(...)
This works as functions in Python are objects like any other - so you can just assign them to variables.
Another option would be to place the functions in a class, so they are in a namespace - meaning you access the method as self.move() and the parameter as move. That said, if you assignment requires that the functions be top-level, that isn't an option.
You could reach the function moveby calling globals()['move'] from within undomove (or any other function). Not very elegant...
In python, there is no way to differentiate between arguments, local variables, and global variables. The easy way to do so might be have some coding convention such as
Global variables start with _ and capital letter
arguments end with with _
_Gvariable = 10
def hello(x_, y_):
z = x_ + y_
Is this a Pythonian way to go? I mean, is there well established/agreed coding-standards to differentiate them in python?
=== ADDED ===
I just want to discriminate between arguments and local variables. As arguments are given from outside, and more like a ROM in the sense that it is not assumed to be read only.
C++ provides the const keyword to prevent the arguments from changing, but not for python. I thought appending _ can be one of a way to mimic this feature in python.
I would do all your python programming according to PEP 8 guidelines. Anyone who has to read your code will thank you for it.
http://www.python.org/dev/peps/pep-0008/
Why is there a need to distinguish between arguments and local variables, since one is merely a subset of the other. You can use locals(), globals(), and vars() to view scope if you are having local-global issues. The inspect module can help with that, too. And if possible, avoid using global variables as much as possible.
It is usually obvious in python which variables are local and which are global, since to modify a global variable you have to declare it using the the global keyword at the start of a function. However I sometimes add a global declaration even if it is not necessary for python to compile it, in order to emphasize that an object is global - e.g. modifying a mutable global data-structure.
Arguments should be obvious because they are in the function declaration.
As others have said constants should be in UPPER_CASE_WITH_UNDERSCORES, which is a convention shared by many languages.
If you find that you are having trouble keeping track of which are global, local and parameter variables I suggest that the problem may be your functions are too long and doing too much. Functions & methods should be short and do exactly one thing. I start to get the refactoring itch if my functions go over about 10-20 lines of code.
I recommend reading the book Clean Code by Robert Martin. The examples are in Java, but the principles apply to all languages.
That's absolutly awful. There is no reason whatsoever to use a special naming scheme for global and local objects. Also you should avoid having global objects unless they are functions, classes or constants.
Names for constants should be uppercase and seperated with underscores LIKE_THIS, class names look LikeThis and functions and method names should look like any other name. Names for objects which are implementation specific, can be changed/removed at any time or can not be relied on for any other good reasons should be prefixed with an underscore.
You should also read the Python styleguide PEP 8 which covers these and more style-related rules you should follow as long as it doesn't make your code less readable. Most Python projects follow this or at least a compatible version of this style guide.
Local variables are variables that are declared inside a function.
Global variables are variables that are declared outside a function.
For Example:
global_var = 5 #Global Variable
def add(a,b):
local_var = a+b #Local Variable
print("The sum is",local_var)
print("The global variable is",global_var)
add(10,20)