I have 3 files: main, calc, and settings organized like this:
# main.py
import settings as s
import calc as c
class Main:
def __init__(self):
calc = c.Calc()
self.my_var = user_input
s.changing_variable = self.my_var
def run(self):
calc.do_something()
# calc.py
import settings as s
class Calc:
def __init__(self):
self.test_variable = s.changing_variable
# settings.py
changing_variable = original_value
All code is run from the main file. I have an original value in the settings file that I now want to change based on the user input in my main file. This value should then be changed globally for all files.
The problem is that it is changed for the main file but not for the calc file. I assume this is because I import settings at the beginning of calc.py and therefore override the user input again.
Does anyone have any idea how to solve this without having to pass the user input variable around in the function calls?
First you need to initialize the variable once during the application life and make it in the global scope, so "settings.py" becomes:
# settings.py
def defing_global_variables():
global changing_variable
changing_variable = original_value
and invoke the fuction "defing_global_variables" in the main module to initialize the global variables.
in "main.initi" function, set the value of "changing_variable" to user_input before instantiating the calc object, and make calc object in the class scope by using self.calc instead of calc, so you can invoke this object again in "main.run" function.
Here is the all modifications for your code:
# main.py
import settings as s
import calc as c
# initialize golobal variables # Added lines
s.defing_global_variables() # Added lines
class Main:
def __init__(self):
self.my_var = 500 # user_input
s.changing_variable = self.my_var
self.calc = c.Calc() # instinteat the object after stting the value, and make it in class scope by adding "self."
def run(self):
self.calc.do_something() # adding self.
a = Main()
a.run()
c2 = c.Calc()
s.changing_variable = 123 # new value
c2.print_global_var()
# the results
# 500
# 123
# calc.py
import settings as s
class Calc:
def __init__(self):
self.test_variable = s.changing_variable
def do_something(self):
print(self.test_variable)
def print_global_var(self):
print(s.changing_variable)
# settings.py
def defing_global_variables():
global changing_variable
changing_variable = 0 # original_value
Good Luck :)
Related
I'm pretty sure this has been answered, but I can't seem to locate it.
What I want is a python script for Blender that creates a custom tab that contains a button. When that button is pressed, it prints the value of an integer and increments it, so that when you press the button again, it shows an incremented value. Everything seems to work, except for the incremental part.
Here is the code I am using at the moment:
===
import bpy
from bpy.props import (IntProperty,)
from bpy.types import (Panel, Operator, AddonPreferences, PropertyGroup,)
def main(context):
my_number += 1
print(str(my_number))
class MySettings(PropertyGroup):
my_number = IntProperty(
name="Int property",
description="This is an integer.",
default = 1
)
class AddOne(bpy.types.Operator):
"""This is an operator"""
bl_idname = "op.add_one"
bl_label = "Increment by 1"
def execute(self, context):
main(context)
return {'FINISHED'}
class CreatePanel(bpy.types.Panel):
bl_label = "Render Setup Panel"
bl_idname = "OBJECT_PT_hello"
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
bl_category = "Increment by 1 Tab"
def draw(self, context):
layout = self.layout
obj = context.object
row = layout.row()
row.operator("op.add_one")
def register():
bpy.utils.register_class(AddOne)
bpy.utils.register_class(MySettings)
bpy.utils.register_class(CreatePanel)
def unregister():
bpy.utils.unregister_class(AddOne)
bpy.utils.unregister_class(MySettings)
bpy.utils.unregister_class(CreatePanel)
if __name__ == "__main__":
register()
===
However, when I press the button 'Increment by 1', I get the following error:
"local variable 'my_number' referenced before assignment"
The point of this exercise is just to create an integer variable, store it, then increment it's value and print it out.
EDIT: I added the actual code, rather than an image of it.
The variable my_number is defined in the class MySettings - it can only be accessed through that class, whether that is inside a method that is also part of the class (self.my_number) or directly as a property that is part of an instance of the class (settings_instance.my_number).
You need to find a place outside of the operator and panel to store persistent variables. Adding a custom property to the object or scene types are common options. As you are showing your panel in the node editor, maybe you will want to add it to the material to keep it specific to a material, instead of global to the scene. You define these properties in the addons register() and remove them in unregister().
def register():
bpy.types.Scene.my_settings = bpy.props.PointerProperty(type=MySettings)
def unregister():
del bpy.types.Scene.my_settings
Then in your operator (or main() function) and your panel you can access the variable through the context paramater.
context.scene.my_settings.my_number += 1
Putting that together into your example, with a label to show the value -
import bpy
from bpy.props import (IntProperty,)
from bpy.types import (Panel, Operator, AddonPreferences, PropertyGroup,)
def main(context):
context.scene.my_settings.my_number += 1
print(str(context.scene.my_settings.my_number))
class MySettings(PropertyGroup):
my_number: IntProperty(
name="Int property",
description="This is an integer.",
default = 1
)
class AddOne(Operator):
"""This is an operator"""
bl_idname = "op.add_one"
bl_label = "Increment by 1"
def execute(self, context):
main(context)
return {'FINISHED'}
class CreatePanel(Panel):
bl_label = "Render Setup Panel"
bl_idname = "OBJECT_PT_hello"
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Increment by 1 Tab"
def draw(self, context):
layout = self.layout
obj = context.object
row = layout.row()
row.operator("op.add_one")
row = layout.row()
row.label(text='Value is: '+str(context.scene.my_settings.my_number))
def register():
bpy.utils.register_class(AddOne)
bpy.utils.register_class(MySettings)
bpy.utils.register_class(CreatePanel)
bpy.types.Scene.my_settings = bpy.props.PointerProperty(type=MySettings)
def unregister():
bpy.utils.unregister_class(AddOne)
bpy.utils.unregister_class(MySettings)
bpy.utils.unregister_class(CreatePanel)
del bpy.types.Scene.my_settings
if __name__ == "__main__":
register()
You will find blender.stackexchange a better place to ask for blender specific python help.
Generally this problem "local variable 'my_number' referenced before assignment" comes when you have 'my_number' variable in code and you had not initialized that variable at top of your code or before using that variable do one thing .
Declare my_number=0 and then do your calculation on my_number variable .
I'm running into an issue where a global variable isn't "remembered" after it's modified in 2 different functions. The variable df is supposed to be a data frame, and it doesn't point to anything until the user loads in the right file. This is similar to something I have (using pandas and tkinter):
global df
class World:
def __init__(self, master):
df = None
....
def load(self):
....
df = pd.read_csv(filepath)
def save(self):
....
df = df.append(...)
save() is always called after load(). Thing is, when I call save(), I get the error that "df is not defined." I thought df got its initial assignment in init(), and then got "updated" in load()? What am I doing wrong here?
You have to use global df inside the function that needs to modify the global variable. Otherwise (if writing to it), you are creating a local scoped variable of the same name inside the function and your changes won't be reflected in the global one.
p = "bla"
def func():
print("print from func:", p) # works, readonly access, prints global one
def func1():
try:
print("print from func:", p) # error, python does not know you mean the global one
p = 22 # because function overrides global with local name
except UnboundLocalError as unb:
print(unb)
def func2():
global p
p = "blubb" # modifies the global p
print(p)
func()
func1()
print(p)
func2()
print(p)
Output:
bla # global
print from func: bla # readonly global
local variable 'p' referenced before assignment # same named local var confusion
bla # global
blubb # changed global
for anyone coming here using python3 - try using nonlocal instead of global - a new construct introduced in python3 which allows you to mutate and read global variables in local scope
You have to use the global keyword inside the function rather than outside. All the df that you have defined inside your function are locally scoped. Here is the right way -
df = pd.DataFrame() # No need to use global here
def __init__(self, master):
global df # declare here
df = None
....
def load(self):
global df # declare here
....
df = pd.read_csv(filepath)
def save(self):
global df # declare here
....
df = df.append(...)
The problem I am having now is the user inputs are being called twice. Is there any better way to share self between python scripts more easily and avoid calling input twice. I read about multiprocessing module in python, but couldn't use it.
This is a short example:
script1.py:
class importparam(object):
def dataset1(self):
self.var1=1
self.var2=2
self.var3=3
self.var4=input('enter var4 : ')
def dataset2(self):
self.const1=11
self.const2=22
self.const3=33
self.const4 = input('enter const4 : ')
script2.py:
from main import main_
class reader_(main_):
def __init__(self):
super(reader_, self).__init__()
def addition(self):
self.add1 = self.const1+self.const2
self.add2 = self.const3+self.const4
def multiply(self):
self.mult1 = self.var1+self.var2
self.mult2 = self.var3+self.var4
main.py
from script1 import importparam
class main_(importparam):
def __init__(self):
super(main_, self).dataset1()
super(main_, self).dataset2()
def fun1(self):
from script2 import reader_
r=reader_()
val=1
if val==1:
r.addition()
else:
r.multiply()
if __name__=='__main__':
main_().fun1()
I tried to get array parameters values in another class , where and why i wrong here ?
My second python file => myModule.py :
parameters = ([])
class MyFirstClass():
def __init__(self, params):
global parameters
parameters = params
class MySecondClass():
def __init__(self):
global parameters
print parameters
class MyClassWhereIHaveAProblem(http.HTTPFactory):
proto = .....
global parameters
print parameters **// array is empty here**
class start_server():
def __init__(self, params):
self.x_params = params[0] //ip
self.y_params = int(params[1]) //port
global parameters
parameters = params[2]
def start():
reactor.listenTCP(self.y, MyClassWhereIHaveAProblem(), interface=self.x)
My first python file => Handle.py :
from myModule import MyFisrtClass
from myModule import MySecondClass
from myModule import MyClassWhereIHaveAProblem
from myModule import start_server
class Handle():
def __init__(self):
params = (["vector1", "vector2"])
self.params = (["127.0.0.1","3128", params])
def go_to_another(self):
s = start_server(self.params)
s.start()
if __name__ == '__main__':
H = Handle()
H.go_to_another()
I tried to get array parameters values in another class , where and why i wrong here ?
It looks like you are simply:
forgetting the second set of double underscores for the special method names
making typos in the class names, you had "First" spelled "Fisrt"
you never did anything to use the MySecondClass class, so I initialized one in your main routine with: y = MySecondClass()
Handle.py:
#!/usr/bin/env python
from myModule import MyFirstClass
from myModule import MySecondClass
class Handle():
def __init__(self):
self.params = (["ele1","ele2","ele3"])
def go_to_another(self):
X = MyFirstClass(self.params)
if __name__ == '__main__':
H = Handle()
H.go_to_another()
y = MySecondClass()
myModule.py:
#!/usr/bin/env python
parameters = ([])
class MyFirstClass():
def __init__(self, params):
global parameters
parameters = params
class MySecondClass():
def __init__(self):
global parameters
print 'this should not be empty: %s' % parameters # array is no longer empty here
Output:
this should not be empty: ['ele1', 'ele2', 'ele3']
You have X = MyFisrtClass(self.params) instead of X = MyFirstClass(self.params)! Also __init should be __init__.
You are printing the variable when the class is first defined, but defining the variable when the class is initialized.
In Python, anything here:
class MyClass:
# here
Is evaluated as soon as the interpreter reaches that line-- not when the class is initialized.
Try running this code to get a better idea of what I mean:
my_global_var = 'set initially!'
class MyClass():
# Will print 'set initially', as this
# print statement is run before an instance of the
# class ever gets initialized,
print 'in class defn: %s' % my_global_var
def __init__( self ):
global my_global_var
my_global_var = 'set by the class instance!'
x = MyClass()
# Will print 'set by the class instance', as now
# you are printing it after the class has been initialized
# at least once
print 'after class is initialized: %s' % my_global_var
For your code:
# I have a problem here
class MyClassWhereIHaveAProblem(http.HTTPFactory):
#proto = .....
#global = parameters
print 'not set here, this is static: %s' % parameters #**// array is empty here**
def __init__(self):
print 'now it is set: %s' % parameters
But make sure you actually initialize one of those MyClassWhereIHaveAProblem.
From what I think is the documentation:
listenTCP(port, factory, backlog=50, interface='')
port a port number on which to listen
factory a twisted.internet.protocol.ServerFactory instance
backlog size of the listen queue
interface The local IPv4 or IPv6 address to which to bind; defaults to '', ie all IPv4 addresses. To bind to all IPv4 and IPv6 addresses, you must call this method twice.
So I think you want to simply do:
listenTCP(self.y_params, YourProblemClass(), interface=self.x_params)
Where:
- y_params is what you called the port, and
- x_params is what you called the address.
ok, I'll go to sleep :) I had also itinialise my object (logical), now everything is ok, Thanks for your time Alex.B, solution here:
class MyClassWhereIHaveAProblem(http.HTTPFactory):
proto = .....
def __init__(self):
http.HTTPFactory.__init__(self)
global parameters
print parameters
I'm trying to write some xml by this piece of code
docs = XmlReportGenerator()
docs.AddMatchRow('FC Barcelona','Madryt','5:0')
docs.Save()
and I wrote my own method:
from lxml import etree
class XmlReportGenerator:
""""""
root = etree.Element('results')
doc = etree.ElementTree(root)
#----------------------------------------------------------------------
def __init__(self):
""""""
def AddMatchRow(self,teamA,teamB, score):
pageElement = etree.SubElement(root,'Flight',teamA, teamB, score)
""""""
def Save(self,path = None):
outFile = open('Matches.xml', 'w')
doc.write(outFile)
NameError: global name 'root' is not defined
Process terminated with an exit code of 1
done
NameError: global name 'doc' is not defined
Process terminated with an exit code of 1
done
Am I missing something? I'm a newbie in python (I have more experience in c#).
Python is explicit. Instance variables must be prepended with self.. Class variables must be prepended with then name of the class.
Here's a fixed version. The original SubElement call was incorrect as well:
from lxml import etree
# derive from 'object' if Python 2.X (it is default in Python 3.X)
class XmlReportGenerator(object):
def __init__(self):
# clearer to init instance variables here.
self.root = etree.Element('results')
self.doc = etree.ElementTree(self.root)
def AddMatchRow(self,teamA,teamB, score):
# Need self.root here
pageElement = etree.SubElement(self.root,'Flight')
# Added data elements (or did you want attributes?)
etree.SubElement(pageElement,'teamA').text = teamA
etree.SubElement(pageElement,'teamB').text = teamB
etree.SubElement(pageElement,'score').text = score
def Save(self,path = None):
outFile = open('Matches.xml', 'w')
# Need self.doc here
self.doc.write(outFile)
# This code will run if the script is executed directly,
# but will be skipped if the script is imported by another script.
if __name__ == '__main__':
docs = XmlReportGenerator()
docs.AddMatchRow('FC Barcelona','Madryt','5:0')
docs.Save()
self is there for a reason. Use self.root, not root