I have following script that works well on it's own, but once I wrap it all into a function does not return data.
The command changes based on input data structure. This is an example of the command I want to feed into the exec():
cross_data=pd.crosstab(src_data['result'],[src_data['c1'],src_data['c2']],normalize='index')
This is my function I want to wrap the code in and call:
def calcct(file_path='src_data.csv', separator = ",", res_col = 'result'):
#define function
src_data = csv_import(file_path, separator) #import data
reorder_cols = reorder_columns(src_data, res_col) #work with data
head_list=list(reorder_cols.columns.values) #get dataframe headers
# create command based on headers and execute that. Should return dataframe called cross_data.
exec(crosstabcmd(head_list))
return cross_data
Results in:
NameError: name 'cross_data' is not defined
I cannot seem to find the correct syntax for calling exec inside a function.
I tried defining and passing the cross_data variable, but I just get an error it doesnt see pandas when I do that.
Or is there some better way? I need to compose the command of 2-x column names, count and names of columns are variable.
First up
You probably don't mean to be using exec - that's a pretty low-level functionality! There isn't really enough context to understand how to fix this yet. Could you write out (in your question) what the crosstabcmd function looks like?
The error
NameError: name 'cross_data' is not defined
is because you've never defined a variable called cross_data in the scope of function calcct, i.e. you have never done cross_data = "something".
I'll give it a go
Assuming you have something like
import pandas as pd
def crosstabcmd(head_list):
# ? I can only guess what your crosstabcmd does, this won't work though
return pd.crosstab(*head_list, normalize='index')
then the solution would look like:
def calcct(file_path = 'src_data.csv', separator = ",", res_col = 'result'):
src_data = csv_import(file_path, separator) #import data
reorder_cols = reorder_columns(src_data, res_col) #work with data
head_list=list(reorder_cols.columns.values) #get dataframe headers
cross_data = crosstabcmd(head_list)
return cross_data
In my case I had main script which called a second script. I needed to use the "c" variable within the second script. Therefore I used locals(),loc as arguments for exec().
loc = {}
a = 10
b = 5
def abc(a,b):
qwerty = "c = %d + %d"%(a,b)
exec(qwerty, locals(), loc)
c = loc['c']
d = c+2
print(d)
abc(a,b)
Related
How convert string to a Python object?
I have for example simple function:
def test_function(name):
str(name) + "insert(1, "test_01")
...
test_function("list1")
I want this to perform "list1.insert(1, "test_01) operation but it doesn't work. I guees there is a problem that it reads name as a string not as an object. How can I solve this out?
locals()"YourFunction"
or
globals()["YourFunction"]()
as an example:
def foo(number):
return number*10
print (globals()["foo"](10))
Output= 100
Thanks
I don't know if it's what you really want. But i think it's because of the quotation mark. See below:
def test_function(name):
print(str(name) + 'insert(1, "test_01")')
...
test_function("list1")
NOTE
By any means don't use eval, it is insecure ("eval is evil").
For more details about eval harmfulness read here.
Solution Requested
Using eval you can evaluate string that contains code and execute it.
The code here that is being evaluated, looks for the variable name in the global scope (outside the function).
The globals() dictionary contains the variables defined outside the function.
def test_function(name):
eval(f'(globals()["{name}"]).insert(1, "test_01")')
name = "list1"
list1 = []
test_function(name)
# Outside function
# eval(str(name) + '.insert(1, "test_01")')
print(list1)
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))
So, the title pretty much says it all.
for instance let's look at the below example code:
## How can I obtain a dict/list (like locals()) of all the variables in second and/or third layer scopes via a command
# coming from the first layer?
## Or another example would be how could I obtain the variables "locals() style" from the thirdlayer via a
# command from the second layer?
# essentially can a parent function/class access a list/dict of a child function
# or class??
def firstLayer():
a = 4.7
q = locals()
print(q)
# local vars of 1st layer
def secondlayer():
b = 7
r = locals()
print(r)
# local vars of 2nd layer
def thirdlayer():
c = False
s = locals()
i = globals()
print('c:\n', c, "\nglobals from 3rd layer:\n\t", i)
# local vars of 3rd layer
thirdlayer()
secondlayer()
firstLayer()
sample_var = globals()
print(sample_var)
# returns the list of global variables
to reiterate what I said in the comments in the code, essentially is their any way I can get a list of all the variables local to a 'child' scope? I know functions are shut off, but if their is no way to do this is their any more complicated code that could achieve this and I could integrate it into a function or class if necessary.
EDIT:
To elaborate further; here's the situation i'm in.
def varsfunc():
font1 = "Harlow Solid"
grey = '#454545'
font2 = 'Mistral'
font3 = 'Italic 35px Times New Roman'
pnk = 'pink'
grn = 'green'
return locals()
Essentially, I am creating a module and the user must create some type of function that they list all of they variables they would like to declare to be used to modify a css file. Essentially, I would like to allow the user to not have to type "return locals()". I want to achieve it by having the end-users wrap the above example function in a decorator that will do the equivalent of returning locals() of the exact scope I want. The decorator does not work for me because it is in an outer scope.
TO BE EVEN MORE CLEAR:
I need a decorator/function that wraps another function(i.e. a decorator), that can access and create a list of a child element.
def module_decorator_func_thing():
r = command_that_acts_like_locals()_but_for_child_scopes
def user_var_list():
font1 = 'green'
font2 = 'pink'
# back in "module_decorator_func_thing"'s scope
print(r) # this variable should contain only a dict/list containing the
# the following:
# r = {'font1': 'green', 'font2': 'pink')
currently users need to do this:
def vars_func_container():
font1 = 'green'
font2 = 'pink'
return locals() # <---- I want the user to not have to type this and for
# a function decorator to take care of it instead possibly.
Info for #aguy and others wishing for more info.
The dictionary/list that I am obtaining via your guys' tips will be sent to this function to do the real job of the program.
(If I were to start using lists, i'd need to convert to a dictionary but that's no problem for me to solve.)
The dict of variables is used with this function to "compile/compyle"(Pun on the word 'Python' + 'compile) and is insert in the "variables" parameter. e.g. you execute the function like this.
compyle("My sample title", return_stylesheet_from_func(*insert .css filename),
return_variables_from_function(*insert function containing variables*), "**True/False to turn on compilation**",
"**True/False to turn on annotations/suggestions**")
def compyle(title, style_sheet, variables, boolean=False, boolean2=True):
"""
:param title: The name you wish your .css file to be named.
:param style_sheet: The name of the multi-line string that will compose your .css file
:param variables: The name of the dictionary containing your .pcss variables
:param boolean: A.K.A the "Compiler Parameter" - Turns the compiler on or off
:param boolean2: A.K.A the "Annotation Parameter" - Turns annotations on or off
:return: returns compiled .pcss text as normal .css style text to be utilized with .html
"""
# -----------------------------------
file_name = title + ".css"
replace_num = len(variables.keys())
counter = replace_num
content = style_sheet
# -----------------------------------
# add theme support with namedtuple's formatted to mimic structs in C/C++
# this will be a major feature update as well as a nice way to allow the future prospect of integrating C/C++ into
# the compiler. Info: https://stackoverflow.com/questions/35988/c-like-structures-in-python
for k, v in variables.items():
counter -= 1
content = content.replace(k, v, replace_num)
if counter == 0:
break
else:
pass
looped_content = str(content)
id_content = looped_content.replace("hash_", "#")
output = id_content.replace("dot_", ".")
if boolean is True:
if boolean2 is True:
output = " /* --- Pyle Sheet --- */\n" + output
with open(file_name, 'w') as writ:
writ.write(output)
writ.close()
print('compiled successfully; The file was saved as ' + "\"" + file_name + "\".")
elif boolean2 is False:
pass
else:
logging.warning("An Error Occurred - see module, documentation, or online Q&A for assistance.")
elif boolean is False:
if boolean2 is True:
print('compiled successfully; The file ' + "\"" + file_name + "\"" + "was not saved/created.")
elif boolean2 is False:
pass
else:
logging.warning("An Error Occurred - see module, documentation, or online Q&A for assistance.")
else:
logging.warning('An Error Occurred with the Compile Parameter (See: boolean in pyle_sheets source file) - \ '
'see module, documentation, or online Q&A for assistance.')
I can't see any way to do this without getting pretty deep; what follows is the simplest solution I've come up with.
how it works
Using the ast module, we go through the code of the given function and find all the assignments. These are evaluated in a given namespace and this namespace is returned.
the code
import ast
import functools
import inspect
def returnAssignments(f):
#functools.wraps(f)
def returner():
assignments = dict()
for node in ast.walk(ast.parse(inspect.getsource(f))):
if isinstance(node, ast.Assign):
exec(compile(ast.Module([node]), '<ast>', 'exec'),
globals(),
assignments)
return assignments
return returner
usage
from ra import returnAssignments
#returnAssignments
def foo():
this = 'something'
that = 37
the_other = object()
print(foo())
output
rat#pandion:~/tmp$ python test.py
{'this': 'something', 'that': 37, 'the_other': <object object at 0x10205b130>}
I wonder if such a crude solution as I provide here might be useful to you. Note that I haven't tested it on all cases, so it might be a bit rough. Also, it returns everything as a string, a behavior which you might want to further change.
Define the function:
def get_local_vars_from_function(f):
import inspect
s = inspect.getsourcelines(f)[0]
d = {}
for l in s:
if '=' in l:
var, val = l.split('=')
var = var.strip()
val = val.strip()
d[var] = val
return d
Then to use it:
In[91]: get_local_vars_from_function(user_var_list)
Out[91]: {'font1': "'green'", 'font2': "'pink'"}
I'm using the below code to assign the content of a csv to a variable:
df = pd.read_csv("Book1.csv", header='infer', encoding="ISO-8859+-1")
I'd like to condense this in a function like so:
def loader(x, y):
x = pd.read_csv(y, header='infer', encoding="ISO-8859+-1")
However, the above function doesn't seem to be assigning the csv to the given value of x?
I'm relatively new to Python and have been searching for a solution for a few hours - no dice.
Python always passes by reference, so what you are trying to do won't work in general. Instead try:
def loader(y):
return pd.read_csv(y, header='infer', encoding="ISO-8859+-1")
x = loader("Book1.csv")
This returns the dataframe from the function and assigns it to a variable named x.
I am trying to do the following in python: I have a list which contains some string values. The list looks like this:
parameters = ['RH', 'WindSp_Avg', 'WindDir']
What I want to do - and I really hope the question is not ridiculous - is to create three lists which each of them have the name of the "parameters" list.
For example:
RH = []
WindSp_Avg = []
WindDir = []
I am new in python and although I had searched a bit online I couldn't find some elegant way to do something like this.
I am trying something like this:
for i in parameters:
parameters[0] = []
But it doesn't seem to work. Any suggestions?
Thanks
Dimitris
What you are trying to do is very unsafe and is against all good practices. Is there a problem in simply creating a dictionary?
myVars = {}
for param in parameters:
myVars[param] = []
WARNING The following code is for educational purposes! DO NOT USE IT IN REAL CODE!
You can do a hard hack to add dynamically a variable to the local variables inside a function. Normally locals() represent all local variables. However simply adding to that dictionary won't solve the problem. There is a hack to force Python to reevaluate locals by using exec, for example:
def test():
for param im parameters:
locals()[param] = []
exec ""
print WindSp_Avg
and result:
>>> test()
[]
parameters = ['RH', 'WindSp_Avg', 'WindDir']
for i in parameters:
vars()[i] = [];
print locals()
To create a variable you can do so:
parameters = ['RH', 'WindSp_Avg', 'WindDir']
for i in parameters:
exec("%s = []" % i);
print vars()
you could something like this:
code = "{0} = []"
for i in parameters:
codeobj = compile(code.format(i), "/dev/null", "single")
eval(codeobj)
but i think tha's very unsafe. Because it could be something in parameters and that will be excuted by the eval. So please only use this if it's only really necessary and security is less important.