function in python - python

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.

Related

Why the print statement is being executed from the function if the function is not called?

def enumerator(fruits):
for index, fruit in enumerate(fruits):
print(f"Fruit: {fruit}, under the index: {index}.")
just_a_variable = enumerator(["apple", "banana", "lemon"]) # Im just assigning function call
# to the variable "just_a_variable"
# and boom, when I run the program the function is called. Makes no sense (it shouldn't work this way, does it?)
I assume this is happening because there is a print statement in the function but it still doesn't make sense. if I change the print statement to "return" it suddenly doesn't compile, that is what I was expecting from just using print. I'm I missing something here?
In general if you add parenthesis after a function (like one of the two examples below), it is called.
function_name(arguments)
variable = function_name(arguments)
 
If you just want a variable to point to a function:
variable = function
Then the following two statements will become identical:
variable(arguments)
function(arguments)
Having said so, this seems a bit useless to me. With you function defined the way it currently is, there isn't a way I know to "assign" it to a variable and pass arguments at the same time.
This does change the structure of your code, but you can perhaps use yield instead of return.
The line just_a_variable = enumerator(["apple", "banana", "lemon"]) is calling function enumerator. Technically, that is what the parenthesis after enumerator do.
Perhaps you noticed that simply running the file is running that line (and calling enumerator). As a scripting language, this is how Python works (in contrast to Java or other compiled languages).

Setting a variable to a parameter value inline when calling a function

In other languages, like Java, you can do something like this:
String path;
if (exists(path = "/some/path"))
my_path = path;
the point being that path is being set as part of specifying a parameter to a method call. I know that this doesn't work in Python. It is something that I've always wished Python had.
Is there any way to accomplish this in Python? What I mean here by "accomplish" is to be able to write both the call to exists and the assignment to path, as a single statement with no prior supporting code being necessary.
I'll be OK with it if a way of doing this requires the use of an additional call to a function or method, including anything I might write myself. I spent a little time trying to come up with such a module, but failed to come up with anything that was less ugly than just doing the assignment before calling the function.
UPDATE: #BrokenBenchmark's answer is perfect if one can assume Python 3.8 or better. Unfortunately, I can't yet do that, so I'm still searching for a solution to this problem that will work with Python 3.7 and earlier.
Yes, you can use the walrus operator if you're using Python 3.8 or above:
import os
if os.path.isdir((path := "/some/path")):
my_path = path
I've come up with something that has some issues, but does technically get me where I was looking to be. Maybe someone else will have ideas for improving this to make it fully cool. Here's what I have:
# In a utility module somewhere
def v(varname, arg=None):
if arg is not None:
if not hasattr(v, 'vals'):
v.vals = {}
v.vals[varname] = arg
return v.vals[varname]
# At point of use
if os.path.exists(v('path1', os.path.expanduser('~/.harmony/mnt/fetch_devqa'))):
fetch_devqa_path = v('path1')
As you can see, this fits my requirement of no extra lines of code. The "variable" involved, path1 in this example, is stored on the function that implements all of this, on a per-variable-name basis.
One can question if this is concise and readable enough to be worth the bother. For me, the verdict is still out. If not for the need to call the v() function a second time, I think I'd be good with it structurally.
The only functional problem I see with this is that it isn't thread-safe. Two copies of the code could run concurrently and run into a race condition between the two calls to v(). The same problem is greatly magnified if one fails to choose unique variable names every time this is used. That's probably the deal killer here.
Can anyone see how to use this to get to a similar solution without the drawbacks?

when should I make a function that has parameters / arguments?

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.

Function calls in a sequence

I am writing a program that must solve a task and the task has many points, so I made one function for each point.
In the main function, I am calling the functions (which all return a value) in the following way:
result = funcD(funcC(funcB(funcA(parameter))))
Is this way of setting function calls right and optimal or there is a better way?
First, as everyone else said, your implementation is totally valid, and separate into multiple lines is good idea to improve readability.
However, if there are even more that 4 functions, I have a better way to make your code more simple.
def chain_func(parameter, *functions):
for func in functions:
parameter = func(parameter)
return parameter
This is based on python can pass function as a variable and call it in other function.
To use it, just simple chain_func(parameter, funcA, funcB, funcC, funcD)
There's nothing really wrong with that way. You could improve readability by instead calling them like this:
resultA = funcA(parameter)
resultB = funcB(resultA)
resultC = funcC(resultB)
resultD = funcD(resultC)
But that's really just a matter of personal preference and style.
If what they do and what they return is fixed, then also the dependency between them is fixed. So you have no other way then call them in this order. Otherwise there is no way of telling without knowing what do they do exactly.
Whether you pin a reference to the partial results:
result1 = funcA(parameter)
#...
result = funcD(result3)
or call them as you've presented in your question doesn't make a significant difference.

Parameter and Function with the same name

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...

Categories

Resources