问题
I'm learning Python and i've been trying to implement a Singleton-type class as a test. The code i have is as follows:
_Singleton__instance = None
class Singleton:
def __init__(self):
global __instance
if __instance == None:
self.name = "The one"
__instance = self
else:
self = __instance
This works in part but the self = __instance part seems to be failing. I've included some output from the interpretor to demonstrate (the code above is saved in singleton.py):
>>> import singleton
>>> x = singleton.Singleton()
>>> x.name
'The one'
>>> singleton._Singleton__instance.name
'The one'
>>> y = singleton.Singleton()
>>> y.name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Singleton instance has no attribute 'name'
>>> type(y)
<type 'instance'>
>>> dir(y)
['__doc__', '__init__', '__module__']
Is it possible to do what i'm trying? If not is there another way of doing this?
Any suggestions welcome.
Cheers.
回答1:
Assigning to an argument or any other local variable (barename) cannot ever, possibly have ANY effect outside the function; that applies to your self = whatever
as it would to ANY other assignment to a (barename) argument or other local variable.
Rather, override __new__
:
class Singleton(object):
__instance = None
def __new__(cls):
if cls.__instance == None:
cls.__instance = object.__new__(cls)
cls.__instance.name = "The one"
return cls.__instance
I've done other enhancements here, such as uprooting the global, the old-style class, etc.
MUCH better is to use Borg (aka monostate) instead of your chosen Highlander (aka singleton), but that's a different issue from the one you're asking about;-).
回答2:
Bruce Eckel's code snippet from Design Pattern: I'm confused on how it works
class Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
class MySingleton(Borg):
def __init__(self, arg):
Borg.__init__(self)
self.val = arg
def __str__(self): return self.val
x = MySingleton('sausage')
print x
y = MySingleton('eggs')
print y
z = MySingleton('spam')
print z
print x
print y
print ´x´
print ´y´
print ´z´
output = '''
sausage
eggs
spam
spam
spam
<__main__. MySingleton instance at 0079EF2C>
<__main__. MySingleton instance at 0079E10C>
<__main__. MySingleton instance at 00798F9C>
'''
回答3:
From Singleton Pattern (Python):
class Singleton(type):
def __init__(self, name, bases, dict):
super(Singleton, self).__init__(name, bases, dict)
self.instance = None
def __call__(self, *args, **kw):
if self.instance is None:
self.instance = super(Singleton, self).__call__(*args, **kw)
return self.instance
class MyClass(object):
__metaclass__ = Singleton
print MyClass()
print MyClass()
回答4:
This is about the most basic Singleton you can make. It uses a class method to check whether the singleton has been created and makes a new one if it hasn't. There are more advanced ways of going about this, such as overriding the __new__ method.
class Singleton:
instance = None
@classmethod
def get(cls):
if cls.instance is None:
cls.instance = cls()
return cls.instance
def __init__(self):
self.x = 5 # or whatever you want to do
sing = Singleton.get()
print sing.x # prints 5
As for why your code fails, there are several reasons. First, by the time __init__
is called, a new object has already been created, defeating the purpose of the singleton pattern. Second, when you say self = __instance
, that simply resets the local variable self; this would be akin to saying
def f(x):
x = 7 # changes the value of our local variable
y = 5
f(y)
print y # this is still 5
Since variables in Python are passed by value and not reference, you can't say self = blah
and have it be meaningful in the way you want. The above Singleton class is more what you want, unless you want to get fancy and look into overriding the __new__
operator.
回答5:
self = _instance
This wont do what you are expecting it to do. Read about how Python treats names.
来源:https://stackoverflow.com/questions/1363839/python-singleton-object-instantiation