so I know this has been asked in several forms before, but I cannot relate to any of those, either I have something different or I just don't understand them.
The problem is I have script A and script B, and in script A I calculate and have all the variables I want to use in script B.
Script A has various functions, let's say for now I just want to pass a simple number from a variable in script A to script B , let's call the variable value .
I used from script_A import value .
Now, I have value initialized in script_A with 0 right at the top to say so, but script_A processes value, and gets a result clearly different from 0, but when I debug, I am getting in script_B value == 0, and not value == calculated_value_that_should_be_there.
I did not know what to do so I tough about scope,so I put it in the return of a function, I tried making variable value a Global variable. Nothing seems to work in the way that I am not passing the calculated 'value' but I am passing to script_B that 0 initialization.
P.S last thing I tried and what I saw from this topic is to import script_A as it was said with no namespaces. This has worked. When I write script_A.value it is calculated_value_that_should_be_there. But, I do not know why anything else that I described did not work.
script_A
from definitions import *
variable_1 = 0
variable_2 = 0
variable_3 = 0
variable_4 = 0
total = 0
respected = 0
time_diff = {}
seconds_all_writes = "write"
class Detect():
def __init__(self, data_manager, component_name, bus_name_list=None):
def __Function_A(self):
"""
global time_diff
global seconds_all_writes
process
script_B:
from script_A import respected
from script_A import total
import script_A
print aln_mon_detector.total
print aln_mon_detector.respected
I also want a dictionary
table_content.append(script_A.time_diff[file[script_A.seconds_all_writes])
I get
KeyError: 'writes'
this sounds a bit confusing without an example, but, in principle, what you're trying to do should work. Have a look at a minimum example below.
ModuleA - defining the variable
# create the variable
someVariable = 1.
# apply modifications to the variable when called
def someFunc(var):
return var + 2
# ask for changes
someVariable = someFunc(someVariable)
ModuleB - using the variable
import moduleA
# retrieve variable
var = moduleA.someVariable
print(var) # returns 3
This probably has to do with immutability. Depends on what value is. If value is a list (that is, a mutable object) and you append to it, the change should be visible. However, if you write
from module import x
x = 5
you are not changing the actual value, so other references to x will still show the original object.
If you have script A like this:
# imports
value = 0
... # some calculations
Re-organize script A as:
# imports
def main():
value = 0
... # some calculations
return value
Now you can import script A in script B and run calculations inside script B:
import script_A
value = script_A.main()
That is how you should organize code pieces in Python.
Related
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...
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)
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))
I'm new to Python and am trying to use a global counter from a module in a package in different modules in different packages. What I want to do is declare a variable in a module and import it to other modules in different packages. I made a simple test for the question and it's happening here too. I made all files in a same directory(they are now in the same package but the problem is the same).
file glbcntmod.py :
glbcnt = 0
file glbfuncmod.py :
from glbcntmod import glbcnt
def glbfunc():
global glbcnt
print 'glbcnt = ',glbcnt
file : test.py
#!/usr/bin/env python
from glbcntmod import glbcnt
from glbfuncmod import glbfunc
loccnt = 0
def localfunc():
print 'loccnt = ',loccnt
if __name__ == '__main__':
glbcnt = 0
for i in xrange(0,4):
glbfunc()
localfunc()
glbcnt += 1
loccnt += 1
When I run test.py, the result is like below. loccnt is incrementing but glbcnt is always 0. What is the problem?
glbcnt = 0
loccnt = 0
glbcnt = 0
loccnt = 1
glbcnt = 0
loccnt = 2
glbcnt = 0
loccnt = 3
The way to do this is to keep the module where the variable is as a reference:
import other_module
other_module.counter += 1
If you do that everywhere you use counter it will have a consitent value across modules.
That happens because each time you do an assignment to a name in Python, the object associated with that name changes -
That is, if you do
from othermodule import counter
counter = 1
Your counter variable will point to a different object from that assignment on. And since numbers are immutable objects, there are even other problems with that.
But f you keep the original module around, you are changing an attribute in that module object - which behaves exactly like any other Python object. As long as other code access the variable as an attribute of the module, you are good.
Note that int is immutable in python. That means doing something like
a = 0
b = a # b = 0
b += 1 # b = 2
will still leave a as 0.
When you do from glbcntmod import glbcnt, this basically equals
import glbcntmod
glbcnt = glbcntmod.glbcnt
So, if you then increment glbcnt, only the local name will be assigned the new value. The original glbcnt is not changed.
If you want to use a global variable, you must use its global name. So what you want to work with and modify is glbcntmod.glbcnt.
If you're trying to update a global variable from another module, check this answer out: https://stackoverflow.com/a/15595447/3224629
In test.py:
if __name__ == '__main__':
glbcnt = 0
for i in xrange(0,4):
...
glbcnt += 1
You make a local glbcnt variable here, which is the one that gets incremented. Your glbfunc() does not see this variable and thus cannot print its value.
Try this:
if __name__ == '__main__':
global glbcnt
glbcnt = 0
...
Also, because of this, your entire glbcntmod.py file becomes pointless.
It's not because a variable is declared global once, that it becomes global everywhere.
"global glbcnt" simply means that from here on, in this scope, any references to glbcnt will refer to the global variable. No effects whatsoever are applied to other scopes, ie. other modules.
So I wrote this function from a book I am reading, and this is how it starts:
def cheese_and_crackers(cheese_count, boxes_of_crackers):
print "You have %d cheeses!" % cheese_count
print "You have %d boxes of crackers!" % boxes_of_crackers
print "Man that's enough for a party!"
print "Get a blanket.\n"
ok, makes sense. and then, this is when this function is run where I got a little confused and wanted to confirm something:
print "OR, we can use variables from our script:"
amount_of_cheese = 10
amount_of_crackers = 50
cheese_and_crackers(amount_of_cheese, amount_of_crackers)
the thing that confused me here is that the amount_of_cheese and amount_of_crackers is changing the variables (verbage? not sure if i am saying the right lingo) from cheese_count and boxes_of_crackers repectively from the first inital variable labels in the function.
so my question is, when you are using a different variable from the one that is used in the initial function you wrote, why would you change the name of the AFTER you wrote out the new variable names? how would the program know what the new variables are if it is shown after it?
i thought python reads programs top to bottom, or does it do it bottom to top?
does that make sense? i'm not sure how to explain it. thank you for any help. :)
(python 2.7)
I think you are just a bit confused on the naming rules for parameter passing.
Consider:
def foo(a, b):
print a
print b
and you can call foo as follows:
x = 1
y = 2
foo(x, y)
and you'll see:
1
2
The variable names of the arguments (a, b) in the function signature (1st line of function definition) do not have to agree with the actual variable names used when you invoke the function.
Think of it as this, when you call:
foo(x, y)
It's saying: "invoke the function foo; pass x in as a, pass y in as b". Furthermore, the arguments here are passed in as copies, so if you were to modify them inside the function, it won't change the values outside of the function, from where it was invoked. Consider the following:
def bar(a, b):
a = a + 1
b = b + 2
print a
x = 0
y = 0
bar(x, y)
print x
print y
and you'll see:
1
2
0
0
The script runs from top to bottom. The function executes when you call it, not when you define it.
I'd suggest trying to understand concepts like variables and function argument passing first.
def change(variable):
print variable
var1 = 1
change(var1)
In the above example, var1 is a variable in the main thread of execution.
When you call a function like change(), the scope changes. Variables you declared outside that function cease to exist so long as you're still in the function's scope. However, if you pass it an argument, such as var1, then you can use that value inside your function, by the name you give it in the function declaration: in this case, variable. But it is entirely separate from var! The value is the same, but it is a different variable!
Your question relates to function parameter transfer.
There are two types of parameter transfer into a function:
By value ------- value changed in function domain but not global domain
By reference ------- value changed in global domain
In python, non-atomic types are transferred by reference; atomic types (like string, integer) is transferred by value.
For example,
Case 1:
x = 20
def foo(x):
x+=10
foo()
print x // 20, rather than 30
Case 2:
d = {}
def foo(x): x['key']=20
foo(d)
print d // {'key': 20}