staticmethod not callable? (trying to make a Singleton metaclass..)
Gabriel Genellina
gagsl-py2 at yahoo.com.ar
Sun Nov 29 12:58:14 EST 2009
En Sun, 29 Nov 2009 10:25:21 -0300, inhahe <inhahe at gmail.com> escribió:
> I'm trying to come up with a system for singletons, where I don't have to
> modify anything for an individual class except to define __metaclass__
> or,
> if possible, to inherit another class.
>
> I want it to raise an error if making a duplicate instance of a class is
> attempted, rather than to return the same object,
(I won't comment on the usefulness of such approach...)
> class Singleton(type):
> def __new__(meta, classname, bases, classDict):
> @staticmethod
> def nonewinst(*args, **kwargs):
> raise ValueError("Can't make duplicate instance of singleton " +
> classname)
> @staticmethod
> def newoldnew(obj):
> return obj
> oldnew = classDict.get("__new__", newoldnew)
> @staticmethod
> def newnew(obj, *args, **kwargs):
> o = oldnew(obj, *args, **kwargs)
> obj.__new__ = nonewinst
> return o
> classDict["__new__"] = newnew
> return type.__new__(meta, classname, bases, classDict)
__new__ is a classmethod, not a staticmethod.
> a little bit of experimentation revealed that apparently even functions
> defined within a method become class methods,
????????
> so i tried making them all
> static methods.
????????
Why do you insist on static methods?
> however, python is strange to me when it comes to methods
> and the self parameter. i mean i understand a function being free of the
> class so that the 'self' parameter doesn't mean anything in particular
> unless you explicitly pass it an instance. and i understand the method
> being bound to an object so that when it's called its self parameter is
> automatically sent the instance. but python seems to have this
> in-between
> mode where sometimes a function isn't particularly bound to an instance
> but
> if you try to pass the wrong kind of instance to 'self' it'll complain,
> which gets annoying, and i don't understand how its binding works.
Do you mean this error?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with X instan
ce as first argument (got Y instance instead)
This kind of check was removed in Python 3; ClassName.method_name yields a
plain function, not an unbound method as in 2.x
> but
> anyway, the problem i'm currently having with the code might not even be
> related to that..because here's the error I'm getting:
>
>>>> from funcs import Singleton
>>>> class A:
> ... __metaclass__ = Singleton
> ...
>>>> b = A()
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "c:\python25\funcs.py", line 68, in newnew
> o = oldnew(obj, *args, **kwargs)
> TypeError: 'staticmethod' object is not callable
That's true: instances of the staticmethod type are not callable.
> i'm not that experienced with metaclasses, but it seems to me that
> something's obviously going fubar here because at that point oldnew
> should
> be the function newoldnew (since class A doesn't have a __new__ defined)
> which is clearly defined right there with a staticmethod decorator, and
> first of all, functions *should* be callable, and secondly, why is my
> object
> a 'staticmethod' object just because I used a decorator on it? it would
> seem it should be a function, so i tested it like this:
>
>>>> class A:
> ... @staticmethod
> ... def b(): pass
> ...
>>>> type(A.b)
> <type 'function'>
>
> in that case, using @staticmethod returns a function. i have nfi why
> it's
> different in my Singleton class.
>
> oh, and thirdly, staticmethod is a decorator and decorators are
> callables so
> even given that for some mysterious reason it's a staticmethod object i
> don't know why it's not callable. so that's pretty confusing. can
> anyone
> clear this up for me? thanks..
staticmethod is a type:
py> staticmethod
<type 'staticmethod'>
Used as a decorator, it's like this:
def b(): pass
b = staticmethod(b)
so b is an staticmethod instance. You can confirm this looking into the
class:
py> A.__dict__['b']
<staticmethod object at 0x00BBCF70>
py> A.b
<function b at 0x00BE7970>
A staticmethod instance is a descriptor; its __get__ method is invoked to
resolve A.b (or getattr(A, "b")). If you retrieve it directly, you get the
staticmethod object which is not callable:
py> A.__dict__['b']()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
Going back to your original goal, your code at the top is really a mess. I
would not even use a metaclass. If you want to avoid creating more than
one instance, just record the fact that you created it in the class
constructor, __new__:
class HardSingleton(object):
"Only one instance of its subclasses may be created ever"
_created = False
def __new__(cls, *args, **kw):
if cls._created:
raise ValueError("Can't make duplicate instance of singleton
%s" % cls.__name__)
result = super(HardSingleton, cls).__new__(cls, *args, **kw)
cls._created = True
return result
class A(HardSingleton):
def __init__(self):
print "A"
s1 = A()
s2 = A()
--
Gabriel Genellina
More information about the Python-list
mailing list