I am learning python and have one question about how to save a dictionary value via a python function.
import copy
def func():
b = {'1':'d'}
a = copy.deepcopy(b)
global a
a = {}
func()
print a
The printout is still {}, how to make it be {'1':'d'}?
You need to say that you are accessing the global variable a, inside the function, like this
def func():
global a
b = {'1': 'd'}
a = copy.deepcopy(b)
But, prefer not doing something like that. Instead, return the copy and then store it in the calling place, like this
import copy
a = {}
def func():
b = {'1': 'd'}
return copy.deepcopy(b)
a = func()
print a
i moved the global a into the function definition.
#! /usr/bin/python
import copy
def func():
global a
b = {'1':'d'}
a = copy.deepcopy(b)
a = {}
func()
print a
You are defining 'a' in two different scopes, one in the "global" scope, one in the function scope. You will need to return copy.deepcopy(b) and set that to the value of the outer defined 'a'.
import copy
def func():
b = {'1':'d'}
return copy.deepcopy(b)
global a
a = func()
print a
Related
Not sure if this makes sense at all, but here's an example:
Let's say I have a script. In this script, I create a list
list = [1,2,3,4]
Maybe I just don't have the technical vocabulary to find what I'm looking for, but is there any way I could set some logging up so that any time I created a variable I could store information in a log file? Given the above example, maybe I'd want to see how many elements are in the list?
I understand that I could simply write a function and call that over and over again, but let's say I might want to know information about a ton of different data types, not just lists. It wouldn't be clean to call a function repeatedly.
this is hackery but what the heck
class _LoggeryType(type):
def __setattr__(cls,attr,value):
print("SET VAR: {0} = {1}".format(attr,value))
globals().update({attr:value})
# Python3
class Loggery(metaclass=_LoggeryType):
pass
# python2
class Loggery:
__metaclass__=_LoggeryType
Loggery.x = 5
print("OK set X={0}".format(x))
note i wouldn't really recommend using this
One method would be to use the powerful sys.settrace. I've written up a small (but somewhat incomplete) example:
tracer.py:
import inspect
import sys
import os
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('tracing-logger')
FILES_TO_TRACE = [os.path.basename(__file__), 'tracee.py']
print(FILES_TO_TRACE)
def new_var(name, value, context):
logger.debug(f"New {context} variable called {name} = {value}")
# do some analysis here, for example
if type(value) == list:
logger.debug(f"\tNumber of elements: {len(value)}")
def changed_var(name, value, context):
logger.debug(f"{context} variable called {name} of was changed to: {value}")
def make_tracing_func():
current_locals = {}
current_globals = {}
first_line_executed = False
def tracing_func(frame, event, arg):
nonlocal first_line_executed
frame_info = inspect.getframeinfo(frame)
filename = os.path.basename(frame_info.filename)
line_num = frame_info.lineno
if event == 'line':
# check for difference with locals
for var_name in frame.f_code.co_varnames:
if var_name in frame.f_locals:
var_value = frame.f_locals[var_name]
if var_name not in current_locals:
current_locals[var_name] = var_value
new_var(var_name, var_value, 'local')
elif current_locals[var_name] != var_value:
current_locals[var_name] = var_value
changed_var(var_name, var_value, 'local')
for var_name, var_value in frame.f_globals.items():
if var_name not in current_globals:
current_globals[var_name] = var_value
if first_line_executed:
new_var(var_name, var_value, 'global')
elif current_globals[var_name] != var_value:
current_globals[var_name] = var_value
changed_var(var_name, var_value, 'global')
first_line_executed = True
return tracing_func
elif event == 'call':
if os.path.basename(filename) in FILES_TO_TRACE:
return make_tracing_func()
return None
return tracing_func
sys.settrace(make_tracing_func())
import tracee
tracee.py
my_list = [1, 2, 3, 4]
a = 3
print("tracee: I have a list!", my_list)
c = a + sum(my_list)
print("tracee: A number:", c)
c = 12
print("tracee: I changed it:", c)
Output:
DEBUG:tracing-logger:New global variable called my_list = [1, 2, 3, 4]
DEBUG:tracing-logger: Number of elements: 4
DEBUG:tracing-logger:New global variable called a = 3
tracee: I have a list! [1, 2, 3, 4]
DEBUG:tracing-logger:New global variable called c = 13
tracee: A number: 13
DEBUG:tracing-logger:global variable called c was changed to: 12
tracee: I changed it: 12
There are some additional cases you may want to handle (duplicated changes to globals due to function calls, closure variables, etc.). You can also use linecache to find the contents of the lines, or use the line_num variable in the logging.
So what I'm trying to do is I need to assign a variable to use in several functions. But that variable should not be a global variable. How can I do that if it is possible?
Edit: I did forgot one thing. This is for my project and most of it is finished but this. My code needs to be non-repeated as much as it can. I have 5 variables and 15 functions to use some or all of that variables.
Edit2: Let me just post a function here.
def draw_stairs(top_stair_wide, stair_height, stair_count, character):
for o in range(stair_count):
for b in range(stair_height):
draw_straight_line(top_stair_wide, character)
print("")
top_stair_wide += 3
What I need to do is when I use that function, I need to fill "top_stair_wide", "stair_height", "stair_count" with a variable that is not global. I can't just put numbers because I will use those variables in 14 different functions again with maths.
I have a function that draws straight line and before, it inputs and returns character so those are not the problem.
Create a class, make the variables instance variables and turn the functions into methods. Then you can access the instance variables in each method without the explicit need to pass them around.
class C:
def __init__(self, var1, var2, var3):
self.var1 = var1
self.var2 = var2
self.var3 = var3
def add_them(self):
return self.var1 + self.var2 + self.var3
def multiply_them(self):
return self.var1 * self.var2 * self.var3
And so on.
You need parameter(s) in your function definition and then pass your variable(s) as argument(s) when you call it.
Using a main function as you told me in a comment, you could write it like this:
def main():
# Here are your NOT GLOBAL variables:
top_stair_wide = 1
stair_height = 2
stair_count = 3
character = "O"
def draw_stairs(top_stair_wide, stair_height, stair_count, character):
for o in range(stair_count):
for b in range(stair_height):
draw_straight_line(top_stair_wide, character)
print("")
top_stair_wide += 3
# ... more definitions follow
# Then call the functions...
# Job done when you execute the program:
main()
Alternatively:
def main(top_stair_wide, stair_height, stair_count, character): # <-- cram all the expected arguments there
def draw_stairs(top_stair_wide, stair_height, stair_count, character):
for o in range(stair_count):
for b in range(stair_height):
draw_straight_line(top_stair_wide, character)
print("")
top_stair_wide += 3
# ... more definitions follow
# Then call the functions...
# Job done when you execute the program:
main(1, 2, 3, "O")
It's also possible using kwargs, because then you have to know the arguments when you call main() and not when you define it:
def main(**kwargs):
def draw_stairs(**kwargs):
for o in range(kwargs["stair_count"]):
for b in range(kwargs["stair_height"]):
draw_straight_line(kwargs["top_stair_wide"], kwargs["character"])
print("")
kwargs["top_stair_wide"] += 3
# ... more definitions follow
# Then call the functions...
function1(**kwargs)
function2(**kwargs)
function3(**kwargs)
# Job done when you execute the program:
main(top_stair_wide = 1,
stair_height = 2,
stair_count = 3,
character = "O")
You can pass it to your functions like:
def func1(variable):
# your logic here with variable
return 'something'
def func2(variable):
# your logic here with variable
return 'something'
Or you can set it as constant in current file as:
VARIABLE = 'variable'
def func1():
# your logic here with VARIABLE
return 'something'
def func2():
# your logic here with VARIABLE
return 'something'
Another option is using a dictionary storing the shared parameters and only passing this dictionary (rather than all variables separately) as an argument:
def add_params(params):
return params['var1'] + params['var2'] + params['var3']
def multiply_params(params):
return params['var1'] * params['var2'] * params['var3']
>>> params = {'var1': 1, 'var2', 2, 'var3': 3}
>>> add_params(params)
6
>>> multiply_params(params)
6
I have tried to search this but I don't quite understand. I am coming across this error so I formed a quick easy example.
def test():
global a
a = 0
a+=1
def test2():
a+=1
print (a)
inp = input('a?')
if inp == 'a':
test()
test2()
When I input a. I expected the code to output 2. However, I get this error UnboundLocalError: local variable 'a' referenced before assignment. When I searched around about this, I found that you need to use global, but I already am using it.
So I don't understand. Can someone briefly explain what I'm doing wrong?
Thanks.
A global declaration only applies within that function. So the declaration in test() means that uses of the variable a in that function will refer to the global variable. It doesn't have any effect on other functions, so if test2 also wants to access the global variable, you need the same declaration there as well.
def test2():
global a
a += 1
print(a)
1) You can return the modified value like:
def test():
a = 0
a+=1
return a
def test2(a):
a+=1
print (a)
inp = input('a?')
if inp == 'a':
a = test()
test2(a)
2) Or you can use a class:
class TestClass:
a = 0
def test(self):
self.a = 0
self.a+=1
def test2(self):
self.a+=1
print (self.a)
Usage of option 2:
>>> example = TestClass()
>>> example.test()
>>> example.test2()
2
For example I have code like this:
def test():
v = tf.get_variable('test') # => foo/test
with tf.variable_scope('foo'):
test()
Now I want to make a variable outside of scope 'foo':
def test():
with tf.variable_scope('bar'):
v = tf.get_variable('test') # foo/bar/test
But it is placed as 'foo/bar/test'. What should I do in test() body to place it as 'bar/test' without 'foo' root?
You can clear the current variable scope by providing an instance of an existing scope. So in order to pull this off, just make a reference to the top-level variable scope and use it:
top_scope = tf.get_variable_scope() # top-level scope
def test():
v = tf.get_variable('test', [1], dtype=tf.float32)
print(v.name)
with tf.variable_scope(top_scope): # resets the current scope!
# Can nest the scopes further, if needed
w = tf.get_variable('test', [1], dtype=tf.float32)
print(w.name)
with tf.variable_scope('foo'):
test()
Output:
foo/test:0
test:0
tf.get_variable() ignores the name_scopebut not variable_scope. If you want to obtain 'bar/test', you can try the following:
def test():
with tf.variable_scope('bar'):
v = tf.get_variable('test', [1], dtype=tf.float32)
print(v.name)
with tf.name_scope('foo'):
test()
Refer to this answer for a complete explanation: https://stackoverflow.com/a/37534656/8107620
A workaround would be to set the scope name directly:
def test():
tf.get_variable_scope()._name = ''
with tf.variable_scope('bar'):
v = tf.get_variable('test', [1])
Say I have some code that creates several variables:
# Some code
# Beginning of the block to memoize
a = foo()
b = bar()
...
c =
# End of the block to memoize
# ... some more code
I would like to memoize the entire block above without having to be explicit about every variable created/changed in the block or pickle them manually. How can I do this in Python?
Ideally I would like to be able to wrap it with something (if/else or with statement) and have a flag that forces a refresh if I want.
Conceptually speaking, it woul dbe like:
# Some code
# Flag that I can set from outside to save or force a reset of the chache
refresh_cache = True
if refresh_cache == False
load_cache_of_block()
else:
# Beginning of the block to memoize
a = foo()
b = bar()
...
c = stuff()
# End of the block to memoize
save_cache_of_block()
# ... some more code
Is there any way to do this without having to explicitly pickle each variable defined or changed in the code? (i.e. at the end of the first run we save, and we later just reuse the values)
How about using locals() to get a list of the local variables, storing them in a dict in pickle, then using (below is more conceptual):
for k,v in vars_from_pickle:
run_string = '%s=%s' % (k,v)
exec(run_string)
to restore your local stack. Maybe its better to use a list instead of a dict to preserve stack ordering.
There are a lot of ways to go about this but I think the way that's closest to what you're describing would be to use pythons module scope as your memoized and import or reload as needed. Something like this:
# a.py
import b
print b.a, b.b
b.func(5)
b.b = 'world'
print b.a, b.b
if b.needs_refresh():
reload(b)
print b.a, b.b
With your "variable scope" being the module b:
# b.py
a = 0
b = 'hello'
def func(i):
global a
a += i
def needs_refresh():
return a >= 5
Executing this results in what you'd expect:
0 hello
5 world
0 hello
Edit: to be allow you to copy and save the entire scope you could just use a class scope:
memo_stack = list()
class MemoScope(object):
def __init__(self):
self.a = 0
self.b = 'hello'
memo = MemoScope()
memo.a = 2
memo.b = 3
memo_stack.append(memo)
memo_stack.append(MemoScope())
for i, o in enumerate(memo_stack):
print "memo t%i.a = %s" % (i, o.a)
print "memo t%i.b = %s" % (i, o.b)
if o.a == 2:
memo_stack[i] = MemoScope()
print "refreshed"
# memo t0.a = 2
# memo t0.b = 3
# refreshed
# memo t1.a = 0
# memo t1.b = hello