Using global to create a singleton object resulting in multiple initialization - python

I am facing a problem where the global variable within my module keeps on getting initialized multiple times when produce() is called. The module is imported just once but I am still unable to understand why the global variable within the module will become None.
Am I taking the right approach?
Looking to make it work in python 2.7 and upwards.
producer_instance = None
def produce(message):
producer = get_producer()
producer.produce(message)
def get_producer():
global producer_instance
if producer_instance is None:
producer_instance = Producer()
return producer_instance

Related

variable for class defined in __main__ with access in different module

I know I'm being dense and I know what the problem is but I can't seem to figure out how to fix it.
testcode.py
import t2
class t1:
saved = 0
#classmethod
def set_class(cls, number):
t1.saved = number
not_in_main = t1
if __name__ == "__main__":
not_in_main.set_class(6)
used_everywhere = t1
used_everywhere.set_class(4)
t2.f1()
and then in t2.py
import testcode
def f1():
print(f'not_in_main: {testcode.not_in_main.saved}')
print(f'got here: {testcode.used_everywhere.saved}')
Now the output after running python testcode.py will be
not_in_main: 0
AttributeError: module 'testcode' has no attribute 'used_everywhere'
So not_in_main has two different instances one in the main scope and one module scope. Used_everywhere is also in the main scope but another module can't see in instance.
I've looked at many of the scoping issues but I don't see how to fix this. What am I doing wrong?
The fix for this circular issue was to move the class def and creation of the module variable to a file other than where main is. The project now just has main in the a module and most all other code in a separate file.
Breakpoints on the not_in_main show it only being instantiated once as opposed to twice as in the listed code.
When necessary, as in generated code for the UI, that is in a separate module, the import of the module where not_in_main is declared does not cause a circular reference and the fields are properly filled out.
Thanks to #junpa.arrivillaga for the pointers and hints to put me on the right path.

Not able to access object in python while creating object of other class defined in some other file

I have a directory structure like this:
home/
main.py
lib/
mylib/
Textfile_Class.py
Excelfile_Class.py
globals.py (has all the global variables declared here)
functions.py
I created an object of Textfile_class in main.py using
txt = TEXT(file).
Now, I want to use this variable txt during creating object of Excelfile_Class for some operations (eg, if the value of a variable in txt object is 5, then do certain action in Excelfile_Class )
In Excelfile_Class, I am also importing all the global variables. String variables are accessible there but I dont know why this object txt is not accessible there. Wherever I am refering to txt in Excelfile_Class(self.line_count = txt.count), I am getting below error: AttributeError: 'NoneType' object has no attribute 'count'
Please help me to know why this is happening even though I have defined all the variables in a seperate file and importing those in all the files.
Eg:
main.py
path = os.path.abspath('./lib')
sys.path.insert(0, path)
from mylib.Textfile_class import *
from mylib.Excelfile_Class import *
from mylib.globals import *
from mylib.functions import *
if __name__ == "__main__":
txt = TEXT(file)
xcel = EXCEL(file)
Eg globals.py
global txt, xcel
txt=None
xcel=None
Eg Textfile_class.py
from globals import *
class TEXT:
def __init__(self, filename):
self.count = 0
with open(filename) as fp:
for line in fp:
self.count = self.count + 1`
Eg Excelfile_Class.py
from globals import *
class EXCEL:
def __init__(self, filename):
self.line_count = 0
self.operation(filename)
def operation(self, file):
self.line_count = txt.count
if self.line_count:
self.some_operation()
else:
self.other_operation()
When you assign a value to a variable name inside a function, you're not working with the global version of the variable any more, instead you have a completely new variable.
You have to use global keyword inside the function to indicate you're working with a global variable.
From Python Doc FAQ
What are the rules for local and global variables in Python?
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function’s body, it’s assumed to be a local. If a variable is ever assigned a new value inside the function, the variable is implicitly local, and you need to explicitly declare it as ‘global’.
Read more...
Example:
x = None # x is momdule-level global variable
def local():
x = 5 # assign 5 to x, here x is a new variable, global x is not affected.
def glob():
global x # indicate we'll working with the global x.
x = 5 # this affect the global variable.
def print_global():
print(x) # Just print the global variable.
local()
print_global() # Prints None
glob()
print_global() # Prints 5
So, every time you refer to txt inside a function, you have to tell the context you'll be working with the global version of txt.
Other thing can be happening!
Python is interpreted, that means it execute the code line by line, if in the others modules (not in the main module) you have code trying to access txt before some value be assigned
if __name__ == "__main__":
txt = TEXT(file)
, then you'll get the same error.
A recommendation:
Try to avoid the use of global variables, you already know that isn't a good practice and it leads to unestable code.
If your problem is that you want to txt and xcel to be available at any time anywhere, you could use the pattern Singleton (warning, Singleton is considered an anti-pattern ref)
I will post an example for you, but before I will encorage you to redesign your program, I ensure you it will be a good exercise!
Singleton example: (again this is an anti-pattern, but I preffer it to nude global variables).
class Globals(object):
__instance = None
def __init__(self):
class wrapped_class:
def __init__(self):
self.txt = None
self.excel = None
if (Globals.__instance is None):
Globals.__instance = wrapped_class()
def __getattr__(self, attrname):
return getattr(self.__instance, attrname)
def __setattr__(self, attrname, value):
setattr(self.__instance, attrname, value)
glob = Globals() # Since __instance is None this will instantiate wrapped_class and save the reference in __instance
glob.txt = "Txt example" # Modify the txt attribute of __instance.
glob_1 = Globals() # Since __instance is not None it stays as it is.
print(glob.txt) # Prints "Txt example"
print(glob_1.txt) # Prints "Txt example"
It is quite hard to tell where your problem is without having the code or the stack trace but I would strongly advice that you read some documentation about Python best practices, the use of global variables and naming conventions. This by itself might solve your issues.
Naming conventions might sound silly but those things and other syntax-related choices do matter in python.
Also, you seem to be missing __init__.py file in your module which may or may not be important depending of the python version you are using.
Here are a few links to get you started:
https://www.python.org/dev/peps/pep-0008/#naming-conventions
https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
http://www.python-course.eu/global_vs_local_variables.php
http://gettingstartedwithpython.blogspot.be/2012/05/variable-scope.html
http://c2.com/cgi/wiki?GlobalVariablesAreBad
I dont know why it happened like that. If anyone knows they can tell.
The problem got resolved when I used the method given in Using global variables between files in Python.
So, finally I put all the global variables in a function in globals.py and instantiated that once in main.py. Then, I used from mylib import globals and referenced the global variables inside the classes as globals.txt and it worked fine.

Why do functions from a dynamically loaded module depend on where the module is stored?

Following this answer, I am using imp.new_module and exec to dynamically load a module and extract functions from it. However, when I store the module in a local variable, functions from it get broken. Here is an example:
import imp
mod = None
func = None
code = """
a = 42
def func():
print a
"""
def main():
#global mod
global func
mod = imp.new_module("modulename")
exec code in mod.__dict__
func = mod.func
main()
func()
Executing this with Python 2.7.3 yields None: codepad. After uncommenting global mod line, making mod global, the function works as expected and prints 42: codepad.
What am I missing? Why does the behaviour change when module is stored in a local variable?
The mod module is a local, and not referenced anywhere else. Like all other objects in Python, that means it is cleaned up when main exits. By making it a global instead, a reference to the module object is kept.
When a module is cleaned up, all the globals are set to None (this is done to break reference cycles early, setting to None is an optimisation to prevent excessive rehashing due to dictionary resizing). The func object still has a reference to the module globals dictionary, and thus sees a bound to None now.
The normal procedure of importing a module adds a reference to the module object in sys.modules, keeping the module alive until interpreter shutdown.
(In Python 3.4, globals are no longer rebound to None (in most cases), as per Safe Object Finalization; see PEP 442).

Global variable causing an error

So I am trying to declare the variable "checks" as a global variable because I get the following issue:
File "C:\Python27\Projects\Automatic Installer\autoinstall.py", line 11, in installFunc
if checks[0] == 1:
NameError: global name 'checks' is not defined
Here's my code, I've tried to add global checks to both the main body of the program as well as the installFunc function. Is there another location I should be adding it/some other way to indicate that checks should contain the information in the program?
import urllib
import subprocess
from Tkinter import *
global checks
def installFunc():
global checks
subprocess.call("md c:\MGInstall", shell=True)
subprocess.call (u"net use w: \\it01\files")
if checks[0] == 1:
subprocess.call(u"w:\\software\\snagitup.exe")
if checks[1] == 1:
subprocess.call(u"w:\\software\\camtasia.exe")
if checks[2] == 1:
urllib.urlretrieve(u"SUPERLONGURLLOLOLOL", u"c:\\MGinstall\\gotomeeting.exe")
subprocess.call (u"c:\\MGinstall\\gotomeeting.exe")
urllib.urlretrieve(u"http://ninite.com/.net-7zip-air-chrome-cutepdf-dropbox-essentials-firefox-flash-flashie-java-klitecodecs-quicktime-reader-safari-shockwave-silverlight-vlc/ninite.exe", u"c:\\MGinstall\\MGinstall.exe")
subprocess.call (u"c:\\MGinstall\\MGinstall.exe")
subprocess.call (u"w:\\printers\\installer\\printer.exe")
app = Tk()
w = Label(app, text="CompanyName IT Automatic Installer")
w.pack()
text = ["Snagit", "Camtasia", "GotoMeeting"]
variables = []
for name in text:
variables.append(IntVar())
Checkbutton(text=name, variable=variables[-1]).pack()
b = Button(text="OK", command=installFunc)
b.pack()
app.mainloop()
checks = [variable.get() for variable in variables]
I think this is because checks gets set after the mainloop (the last line of the posted code). the function installFunc gets called from the mainloop via a button press, but checks hasn't been defined yet.
Using the global data in this case isn't a good idea anyway. You should probably do something like:
def installFunc(checks):
...
checks = [variable.get() for variable in variables]
b = Button(text="OK", command=lambda : installFunc(checks))
Or, even better, wrap all this up in a class... that way you can do:
self.b=Button(..., command=self.installFunc)
Replace the first 'global checks' (the one at the global level) with 'global = ...', initializing it appropriately. Using 'global' is really relevant only within a function/method. Per the Python docs: The global statement is a declaration which holds for the entire current code block. It means that the listed identifiers are to be interpreted as globals. It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global. You may want to read this as well - has lots of relevant info: Using global variables in a function other than the one that created them
The problem is not the first 'global checks'. What causes the error is that checks is accessed before it is initialized.
You must initialize checks before calling the main loop of the application.
First of all, Python is not PHP.
You need to use keyword global if an only if, you're going to assign to global variable within scope of a function.
global checks at top level makes no sense at all, and more importantly does not define that variable.
global checks in your installFunc() does not make sense, as you do not assign anything to that variable, in fact you don't even modify it.
In Python variables from outer scope are visible in local scope, unless of course you try to assign something, which would be interpreted as redefining that variable within local scope.
Problem with your code is that you only define checks after exiting main loop. Correct code would look like this
import urllib
import subprocess
from Tkinter import *
#no global definition here...
def installFunc():
#no global definition here...
subprocess.call("md c:\MGInstall", shell=True)
...
...
#define checks before starting main loop
checks = [variable.get() for variable in variables]
app.mainloop()

python threading with global variables

i encountered a problem when write python threading code, that i wrote some workers threading classes, they all import a global file like sharevar.py, i need a variable like regdevid to keep
tracking the register device id, then when one thread change it's value, then other threads can
get it fresh, but the result is that: when one thread change it's value, the others still get the default value i defined in sharevar.py file, why?
anything wrong with me?
# thread a
from UserShare import RegDevID
import threading
class AddPosClass(threading.Thread):
global commands
# We need a pubic sock, list to store the request
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
data = self.queue.get()
#print data
RegDevID = data
#print data
send_queue.put(data)
self.queue.task_done()
# thread b
import threading
from ShareVar import send_queue, RegDevID
"""
AddPos -- add pos info on the tail of the reply
"""
class GetPosClass(threading.Thread):
global commands
# We need a pubic sock, list to store the request
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
data = self.queue.get()
#print data
data = RegDevID
#print data
send_queue.put(data)
self.queue.task_done()
# ShareVar.py
RegDevID = '100'
That's it, when thread a changed the RegDevID, thread b still get it's default value.
Thanks advanced.
from ShareVar import RegDevID
class Test():
def __init__(self):
pass
def SetVar(self):
RegDevID = 999
def GetVar(self):
print RegDevID
if __name__ == '__main__':
test = Test();
test.SetVar()
test.GetVar()
The ShareVar.py:
RegDevID = 100
The result:
100
why?
My guess is you are trying to access the shared variable without a lock. If you do not acquire a lock and attempt to read a shared variable in one thread, while another thread is writing to it, the value could be indeterminate.
To remedy, make sure you acquire a lock in the thread before reading or writing to it.
import threading
# shared lock: define outside threading class
lock = threading.RLock()
# inside threading classes...
# write with lock
with lock: #(python 2.5+)
shared_var += 1
# or read with lock
with lock:
print shared_var
Read about Python threading.
Answer to your bottom problem with scoping:
In your bottom sample, you are experiencing a problem with scoping. In SetVar(), you are create a label RegDevID local to the function. In GetVar(), you are attempting to read from a label RegDevID but it is not defined. So, it looks higher in scope and finds one defined in the import. The variables need to be in the same scope if you hope to have them reference the same data.
Although scopes are determined statically, they are used dynamically.
At any time during execution, there
are at least three nested scopes whose
namespaces are directly accessible:
the innermost scope, which is searched first, contains the local names
the scopes of any enclosing functions, which are searched starting
with the nearest enclosing scope,
contains non-local, but also
non-global names
the next-to-last scope contains the current module’s global names
the outermost scope (searched last) is the namespace containing
built-in names
If a name is declared global, then all
references and assignments go directly
to the middle scope containing the
module’s global names. Otherwise, all
variables found outside of the
innermost scope are read-only (an
attempt to write to such a variable
will simply create a new local
variable in the innermost scope,
leaving the identically named outer
variable unchanged).
Read about scoping.
Are you sure you posted your actual code? You imported RegDevID from two different modules:
# thread a
from UserShare import RegDevID
vs
# thread b
from ShareVar import send_queue, RegDevID
Either way, your problam has nothing to do with threading. Think of 'from somemodule import somevar' as an assignment statement. Roughly equivalent to some magic to load the module if it isn't already loaded followed by:
somevar = sys.modules['somemodule'].somevar
When you import RegDevID from the other module you are creating a fresh name in the current module. If you mutate the object then other users of the object will see the changes, but if you rebind the name in this module then that only affects the local name it doesn't change anything in the original module.
Instead you need to rebind the variable in another module:
import ShareVar
...
ShareVar.RegDevID = data
Except of course you'll find you get on much better if you create a class to manage your shared state.
Your second bit of code is ejust misunderstanding local and global variables:
def SetVar(self):
RegDevID = 999
inside the function you created a new local variable RegDevID which is nothing to do with the global variable of the same name. Use the global statement if you want to rebind a global variable:
def SetVar(self):
global RegDevID
RegDevID = 999

Categories

Resources