3

I have a singleton implemented like this:

class Test123(object):        
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Test123, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def initialize(self):
        self.attr1 = 500
        self.attr2= 0
        self.attr3= 0.10

    def printit(self):
        print self.attr1
        print self.attr2
        print self.attr3

I don;t implement __init__ because it is called every time I use the singleton, so to get around it, I simply call initialize at the start of my script.

Whenever i run it:

Test123().initialize()
time.sleep(1)
Test123().printit()

I get this error:

Traceback (most recent call last):
  File "Z:\test\test123.py", line 22, in <module>
500
    Test123().printit()
  File "Z:\test\test123.py", line 17, in printit
    print self.attr2
AttributeError: 'Test123' object has no attribute 'attr2'

Any ideas what is going on? I am using another singleton and it's not doing this. Plus, attr1 gets printed fine, I very confused. Might it have something to do with naming, maybe some other singleton has an attribute named attr2?

EDIT: the testcase seems to work fine after I changed repo, so here is the actual code

    import MySQLdb

class DataAccessLayer():
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(DataAccessLayer, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def initialize(self):
        #init local connection
        self.dalConnection = 0
        try:
            self.dalConnection = MySQLdb.connect('localhost', 'root', 'awesomepassword', 'arb');

        except MySQLdb.Error, e:
            print "Error %d: %s" % (e.args[0],e.args[1])

    def __del__(self):
        self.dalConnection.close()


    def addrow(self):
        try:
            cur = self.dalConnection.cursor()


            cur.close()
            self.dalConnection.commit()

        except MySQLdb.Error, e:
            print "Error %d: %s" % (e.args[0],e.args[1])

DataAccessLayer().initialize()
DataAccessLayer().addrow()

Creates this error:

Traceback (most recent call last):
  File "Z:\test\DataAccess.py", line 36, in <module>
    DataAccessLayer().addrow()
  File "Z:\test\DataAccess.py", line 25, in addOption
    cur = self.dalConnection.cursor()
AttributeError: DataAccessLayer instance has no attribute 'dalConnection'
Exception AttributeError: "DataAccessLayer instance has no attribute 'dalConnection'" in <bound method DataAccessLayer.__del__ of <__main__.DataAccessLayer instance at 0x00000000022A2748>> ignored
David Menard
  • 2,261
  • 3
  • 43
  • 67
  • 2
    Works for me. Do you experience a fail with the testcase too, or only in the real program? What Python version? –  Mar 24 '12 at 21:12
  • nvm, just tried the testcase again, seems to work fine (I did launch it from a different repo.) – David Menard Mar 24 '12 at 21:19
  • Python has a design pattern called the [Borg](http://stackoverflow.com/questions/1318406/why-is-the-borg-pattern-better-than-the-singleton-pattern-in-python), which is often considered neater than singletons. – Katriel Mar 24 '12 at 21:59

2 Answers2

3

Your DataAccessLayer is an old-style class. Try class DataAccessLayer(object): ....

Update:

Class Types

Class types, or “new-style classes,” are callable. These objects normally act as factories for new instances of themselves, but variations are possible for class types that override __new__(). The arguments of the call are passed to __new__() and, in the typical case, to __init__() to initialize the new instance.

Classic Classes

Class objects are described below. When a class object is called, a new class instance (also described below) is created and returned. This implies a call to the class’s __init__() method if it has one. Any arguments are passed on to the __init__() method. If there is no __init__() method, the class must be called without arguments.

source: the python reference

mutantacule
  • 6,913
  • 1
  • 25
  • 39
0

Slightly off topic, but... This does not seem pythonic to me at all. I would try to write a decorator class Singleton, so I can do

@Sigleton
class MySingleton(object):
    pass

You can also reuse if quickly any time if you need it again...

Note: It can make small mess in metadata (MySingleton is as instance of Singleton, not MySingleton), but maybe functools.wraps could help somehow...

tchap
  • 1,047
  • 8
  • 10