Frage

I was messing around with metaclasses a little bit trying to figure out how I may use one to create a singleton data structure when I came across something that's stumped me:

Also, I have done my homework and looked at this page and this one too, but I wanted to see if I could do it on my own and the problem that arose is less about how to implement a singleton and more about the functionality of something in my version of a singleton metaclass.

class SingletonError(Exception):
    pass

class Singleton(type):

    def __new__(metacls, name, parents, kwargs):
        cls = super(Singleton, metacls).__new__(metacls, name, parents, kwargs)
        cls._instance = None
        return cls

    def __call__(cls, *args, **kwargs): #cls is the class being called, in this case
                                        #when Quux is called, the Quux class is sent
                                        #as the cls argument.
        if not cls._instance:
            inst = cls.__new__(cls, *args, **kwargs)
            cls._instance = inst
        else:
            raise SingletonError("Cannot initialize multiple singletons")
        print('returning', cls._instance)
        return cls._instance

class Quux(metaclass = Singleton):
    pass

Most of it works, like it does indeed raise a SingletonError when trying to initialize multiple instances of Quux, but watch what happens when I try to create an instance of Quux:

>>> q = Quux()
returning <__main__.Quux object at 0x02BE7E90>
>>> type(q)
<class '__main__.Quux'>

Does this mean that the __call__ method in the Singleton metaclass is returning the class object as opposed to the instance created in the __call__ method? If so, how may I fix it with the current setup I have?

(I realize there are better ways of creating a singleton but for the sake of this exercise and learning about metaclasses I would like to solve it with this setup).


EDIT: Okay, so BrenBarn just pointed out that I made a major derp and thought that when it type returned it was returning the class when really if it were returning the class object it would say . Sorry about the confusion.

But now I have a new problem: lets assume I have a __new__ method for the Quux class.

class Quux(metaclass = Singleton):

    def __new__(cls, thing):
        name = cls.__name__
        parents = cls.__bases__
        kwargs = {'thing' : thing}
        return super(Quux, cls).__new__(cls, thing)

It raises a TypeError saying that object.__new__() takes no parameters. How can I fix this __new__ method to return an instance of the Quux class?

War es hilfreich?

Lösung

No, it is returning an instance of Quux. The type of an instance is its class. So the type of your Quux instance is Quux.

This doesn't really have anything to do with your metaclass. It's the normal behavior for any old user-defined class:

>>> class Foo(object):
...     pass
>>> f = Foo()
>>> type(f)
<class '__main__.Foo'>

Foo is a class. f is an instance of Foo, so type(f) is Foo.

To answer your second question: just don't pass thing to the superclass. Just do return super(Quux, cls).__new__(cls).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top