How can I share a function variable within a nested function? - python

UPDATED:
How can I use a function variable within nested function? I've simplified my problem in the following example:
def build():
n = 1 # code to parse rpm package minor version from file
f = min_ver(n) # update minor version
return
def min_ver(n):
n = 2 # this is defined by another process, not set intentionally
s = 1 + n # still need the original value from build()
return s
The actual use case is that I'm grabbing a parsed rpm package minor version value in ex1() from disk called 'n'. When ex2() is executed from ex1(), it deletes the old package, builds a new rpm package with a new minor version. So when it calls for ex1()'s value within the nested function, it's not changed to the new version.
How can I maintain the original 'n' value within the nested function, before passing onto a new value of 'n' post nested function?

A simple way to do this would be to pass the variable as an argument to ex2.
def build():
n = int(1)
f = ex2(n) # pass the value to the next function
n = int(5)
return
def min_ver(n_old):
n = 2
s = 1 + n_old # use the n that was passed in
return s

If you make ex2() actually nested then you can access the outer variables.
def ex1():
n = int(1)
def ex2():
s = 1 + n
return(s)
f = ex2()
n = int(5) # done with nested value, rewrite new value
return()
Also, you probably want to return f or n instead of an empty tuple, I would imagine.
And you don't need to say int(1) you can just say 1. Everything, including integers and strings, is implicitly an object in python.

Related

Get returned value of function in function which called it

I am newbie in python, and I build two functions in which, I am calling second function with 1 parameters in first function and I am trying to access second function's returned data in first function.
def second_function(first_param):
final = first_param + 50
return final
def first_function():
second_function(50)
# trying to access second_function's returned data HERE
print(second_function)
But it is not showing any returned data.
Any help would be much Appreciated. Thank You in Advance.
The problem here is that you are using print(second_function), so that will simply output the name of the function. Now, if you want to output the result of the function, you should do:
def second_function(first_param):
final = first_param + 50
return final
def first_function():
output = second_function(50)
print(output)
you could first put the returned value in a variable like this
def second_function(first_param):
final = first_param + 50
return final
def first_function():
value = second_function(60)
print(value )
or print the returned value with out using any variable
def second_function(first_param):
final = first_param + 50
return final
def first_function():
print(second_function(50))
That's because second_function is an object in its own right. Try either of the following:
def first_function():
out = second_function(50)
# trying to access second_function's returned data HERE
print(out)
def first_function_alternate():
print(second_function(50))
What's happening when you do print(second_function) is that the computer is trying to print the value of the function itself, not what it returns. We can store this value to a variable (my first answer) or simply generate it on-the-fly (my second answer).
In Python, the returned data from a function will be assigned to a variable. So you would use:
my_value = second_function(60)
and the returned value would be stored in the variable my_value

Rename a variable each time the code is run (python)?

I have a bit of python code that's set to run on a schedule. (I think my problem is the same as if it were within a loop.)
Let's say that in its most basic form, the code snippet looks something like this:
A = 1
B = 2
renameMe = A + B
Let's say the scheduler runs the same snippet of code every 5 minutes. The values of variables A & B are different each time the code is run, but the operation renameMe = A + B is always the same.
The values for A & B are grabbed out of a dataframe that's updated every 5 minutes, so I don't know what they are in advance, but if I need to do something with them beforehand instead of assigning them to A & B right away, I can.
I recently found out that for other things to work, I need to be able to rename the variable renameMe every time that snippet of code runs. In other words, I want the variable's name to be renameMe1 the first time the code snippet runs, then renameMe2 when it runs 5 minutes later, and so on.
It doesn't really matter in which way the variable's name changes (ints, strs, whatever) as long as I'm able to find out what the new variable name is, and use it elsewhere.
Do NOT use a variable variable name, you will have problems, use a container:
a list:
# first time
container = []
# each loop/run
container.append(A+B)
## last value
container[-1]
a dictionary:
# first time
container = {}
# each loop/run
container['new_id'] = A+B
# access arbitrary value
container['my_previous_id']
If you need persistence, use a flat file or a database.
I think it is suitable to use a class so that setattr can be used:
class newVal:
def __init__(self):
self.n = 1
def addVal(self, a, b):
setattr(self, f”val{self.n}”, a+b)
self.n += 1
Values = newVal()
Values.addVal(a, b)
Values.val1 would now be assigned
I aggree with Mozway when saying variables names are likely to cause problems, but this is also something you could strictly manage.
globals() stores all variables names and values in the form of a collection of 2-tuples, like this one :
dict_items([('__name__', '__main__'), ..., ('thisName', 'renaMe1'), ('renaMe18', 10)])
So you should register your new variable name but not forget to delete the previous one in order to avoid overloading.
If you follow a natural law of equal births and deaths, you will avoid overpopulation.
I propose you this bunch of code (with comments inside) :
basename = 'renaMe'
def varUpdate():
# Get previous variable name
thisName = [i for i, j in globals().items() if i[:len(basename)] == basename][0]
# Define the new variable name
newName = basename + '%d'%sum([int(thisName[len(basename):]), 1])
# Register the new variable name
globals()[newName] = globals()[thisName]
# Delete previous variable name from global
del globals()[thisName]
def process(i):
# Isolate from process content for readibility
varUpdate()
# PROCESS BELOW
# ....
newVar = [i for i, j in globals().items() if i[:len(basename)] == basename][0]
print(newVar, " : ", globals()[newVar])
# With this for` loop we simulate 4 entries in process
for i in range(4):
### we enter in the process
process(i)
Test in the shell
First restart your shell and let's suppose we have at the beginning renaMe12 = 12 :
>>> renaMe12 = 12
>>> Proposed Script ...
Result
Variable increments it's proper name at each iteration.
renaMe13 : 12
renaMe14 : 12
renaMe15 : 12
renaMe16 : 12
If you check in the shell now, you could see at the end of iteration, renaMe12 to renaMe15 no longer exist.
Only the variable renaMe16 exists with value 12.
>>> renaMe16
12
>>>> renaMe15
Retraçage (dernier appel le plus récent) :
Shell Python, prompt 4, line 1
builtins.NameError: name 'renaMe15' is not defined
Conclusion
This discussion is just for the sake of experimentation, but if I were you I would do my possible to avoid such code complexification unless it's necessary.
I agree Mozway when thinking you should avoid pain headaches...

Call many python functions from a module by looping through a list of function names and making them variables

I have three similar functions in tld_list.py. I am working out of mainBase.py file.
I am trying to create a variable string which will call the appropriate function by looping through the list of all functions. My code reads from a list of function names, iterates through the list and running the function on each iteration. Each function returns 10 pieces of information from separate websites
I have tried 2 variations annotated as Option A and Option B below
# This is mainBase.py
import tld_list # I use this in conjunction with Option A
from tld_list import * # I use this with Option B
functionList = ["functionA", "functionB", "functionC"]
tldIterator = 0
while tldIterator < len(functionList):
# This will determine which function is called first
# In the first case, the function is functionA
currentFunction = str(functionList[tldIterator])
Option A
currentFunction = "tld_list." + currentFunction
websiteName = currentFunction(x, y)
print(websiteName[1]
print(websiteName[2]
...
print(websiteName[10]
Option B
websiteName = currentFunction(x, y)
print(websiteName[1]
print(websiteName[2]
...
print(websiteName[10]
Even though it is not seen, I continue to loop through the iteration by ending each loop with tldIterator += 1
Both options fail for the same reason stating TypeError: 'str' object is not callable
I am wondering what I am doing wrong, or if it is even possible to call a function in a loop with a variable
You have the function names but what you really want are the function objects bound to those names in tld_list. Since function names are attributes of the module, getattr does the job. Also, it seems like list iteration rather than keeping track of your own tldIterator index would suffice.
import tld_list
function_names = ["functionA", "functionB", "functionC"]
functions = [getattr(tld_list, name) for name in function_names]
for fctn in functions:
website_name = fctn(x,y)
You can create a dictionary to provide a name to function conversion:
def funcA(...): pass
def funcB(...): pass
def funcC(...): pass
func_find = {"Huey": funcA, "Dewey": funcB, "Louie": FuncC}
Then you can call them, e.g.
result = func_find["Huey"](...)
You should avoid this type of code. Try using if's, or references instead. But you can try:
websiteName = exec('{}(x, y)'.format(currentFunction))

Using an argument from one Function in a separate function

I have a function:
def create_discs(noDiscs):
which when called creates a specified number of discs, so for example:
create_discs(5)
will create 5 discs.
I then want to use the integer inputted into the create_discs function in a separate function:
def hanoi(disc_int):
In other words I would like disc_int to equal 5 (or whatever number is inputted)
Can anyone help me?
If you want two functions to share state like this, they should be defined as methods of a class.
class Hanoi(object):
def __init__(self, num_discs):
self.num_discs = num_discs
def create_discs(self):
# use value of self.num_discs
def hanoi(self):
# use value of self.num_discs
h = Hanoi(5)
h.create_discs()
h.hanoi()
If you're passing 5 to create_discs, can you do:
num = 5
create_discs(num)
hanoi(num)
You could make a closure:
def create_discs(num):
# create some discs
def hanoi_closure():
# now num is available within this function
# do hanoi stuff
return
return hanoi_closure
hanoi = create_discs(5)
hanoi()
In this case, create_discs defined your hanoi function within itself so that num was within its scope (automatically, no need to store anything in a global or a class!) and it returned the inner function so you could call it later.
If create_discs was already supposed to return something, then you could just return a tuple with what it was returning plus the inner function:
def create_discs(num):
# ...
return what_it_normally_returns, hanoi_closure
create_discs_result, hanoi = create_discs(5)
hanoi()

Python 3.0 - Dynamic Class Instance Naming

I want to use a while loop to initialize class objects with a simple incremented naming convention. The goal is to be able to scale the number of class objects at will and have the program generate the names automatically. (ex. h1...h100...h1000...) Each h1,h2,h3... being its own instance.
Here is my first attempt... have been unable to find a good example.
class Korker(object):
def __init__(self,ident,roo):
self.ident = ident
self.roo = roo
b = 1
hwinit = 'h'
hwstart = 0
while b <= 10:
showit = 'h' + str(b)
print(showit) #showit seems to generate just fine as demonstrated by print
str(showit) == Korker("test",2) #this is the line that fails
b += 1
The errors I get range from a string error to a cannot use function type error.... Any help would be greatly appreciated.
If you want to generate a number of objects, why not simply put them in an array / hash where they can be looked up later on:
objects = {}
for b in range(1,11):
objects['h'+str(b)] = Korker("test", 2)
# then access like this:
objects['h3']
Of course there are ways to make the names available locally, but that's not a very good idea unless you know why you need it (via globals() and locals()).
Variables are names that point to objects that hold data. You are attempting to stick data into the variable names. That's the wrong way around.
instead of h1 to h1000, just call the variable h, and make it a list. Then you get h[0] to h[999].
Slightly different solution to viraptor's: use a list.
h = []
for i in range(10):
h.append(Korker("test",2))
In fact, you can even do it on one line with a list comprehension:
h = [Korker("test", 2) for i in range(10)]
Then you can get at them with h[0], h[1] etc.

Categories

Resources