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...
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.
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
I'm working on a project where I'm batch generating XML files which can import to the IDE of an industrial touchscreen.
Each XML file represents a screen, and most screens require the same functions and the process for dealing with them is the same, with the exception of the fact that each screen type has a unique configuration function.
I'm using a ScreenType class to hold attributes specific to a screen type, so I decided to write a unique configuration for each type, and pass it as a parameter to the __init__() of this class. This way, when I pass around my ScreenType as it is needed, it's configuration function will stay bundled and can be used whenever needed.
But I'm not sure what will happen if my configuration function itself has a dependency. For example:
def configure_inputdiag(a, b, c):
numerical_formatting = get_numerics(a)
# ...
return configured_object
Then, when it comes time to create an instance of a ScreenType
myscreentype = ScreenType(foo, man, shoe, configure_inputdiag)
get_numerics is a module scoped function, but myscreentype could (and does) get passed within other modules.
Does this create a problem with dependencies? I'd try to test it myself, but it seems like I don't have a fundamental understanding behind what's going on when I pass a function as a parameter. I don't want to draw incorrect conclusions about what's happening.
What I've tried: Googling, Search SO, and I didn't find anything specifically for Python.
Thanks in advance.
There's no problem.
The function configure_inputdiag will always refer to get_numerics in the context where it was defined. So, even if you call configure_inputdiag from some other module which knows nothing about get_numerics, it will work fine.
Passing a function as a parameter produces a reference to that function. Through that reference, you can call the function as if you had called it by name, without actually knowing the name (or the module from which it came). The reference is valid for the lifetime of the program, and will always refer to the same function. If you store the function reference, it basically becomes a different name for the same function.
What you are trying to do works in a very natural form in Python -
In the exampe above, you don't need to have the "get_numerics" function imported in the namespace (module) where the "configure_inputdiag" is - you just pass it as a normal parameter (say, call it "function") and you are going like in this example:
Module A:
def get_numerics(parm):
...
input diag = module_B.configure_inputdiag(get_numerics, a)
Module B:
def configure_inputdiag(function, parm):
result = function(parm)
Oh - I saw your doubt iwas the other waya round - anyway, there is no problem - in Python, functions are first class objects- jsut like ints and strings, and they can be passed around as parametrs to other functions in other modules as you wish. I think the example above clarifies that.
get_numerics is resolved in the scope of the function body, so it does not also need to be in the scope of the caller.
In a function, I need to perform some logic that requires me to call a function inside a function. What I did with this, like:
def dfs(problem):
stack.push(bache)
search(root)
while stack.isEmpty() != 0:
def search(vertex):
closed.add(vertex)
for index in sars:
stack.push(index)
return stack
In the function, dfs, I am using search(root), is this is the correct way to do it?
I am getting an error: local variable 'search' referenced before assignment
There are many mysterious bug-looking aspects in your code. The wrong order of definition (assuming you do need the search function to be a nested one) and the syntax error from the empty while loop have already been observed, but there are more...:
def dfs(problem):
stack.push(bache)
search(root)
what's bache, what's stack, what's root? If they're all global variables, then you're overusing globals -- and apparently nowhere ever using the argument problem (?!).
while stack.isEmpty() != 0:
what's this weird-looking method isEmpty? IOW, what type is stack (clearly not a Python list, and that's weird enough, since they do make excellent LIFO stacks;-)...? And what's ever going to make it empty...?
def search(vertex):
closed.add(vertex)
...don't tell me: closed is yet another global? Presumably a set? (I remember from a few of your Qs back that you absolutely wanted to have a closed dict, not set, even though I suggested that as a possibility...
for index in sars:
...and what's sars?!
stack.push(index)
return stack
what a weird "loop" -- one that executes exactly once, altering a global variable, and then immediately returns that global variable (?) without doing any of the other steps through the loop. Even if this is exactly what you mean (push the first item of sars, period) I don't recommend hiding it in a pseudo-loop -- it seriously looks like a mystery bug just waiting to happen;-).
You need to de-indent your search function. The way you have it set up right now you are defining your search function as a part of the completion of your dfs call. Also, encapsulation in a class would help.
Thats the wrong order. Try this:
def dfs(problem):
def search(vertex):
closed.add(vertex)
for index in sars:
stack.push(index)
return stack
stack.push(bache)
search(root)
while stack.isEmpty() != 0:
Either define search before you call it, or define it outside of dfs.
you have to define the function before using it
root doesn't seem to be available in your scope - make sure it's reachable
You don't have body to your for your while loop. That is probably causing problems parsing the code. I would also suggest putting the local function definition before it is used, so it is easier to follow.