En Sun, 29 Nov 2009 10:25:21 -0300, inhahe <inh...@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

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to