what exactly does type.__call__ do?

Jason Maldonis jjmaldonis at gmail.com
Thu Nov 2 20:12:40 EDT 2017


Thanks for your response.

I'm confident that my use case for this metaclass is correct for what I'm
trying to do. I've been using them for a few years now, but sparingly
because as you said they are almost always unnecessary. I simplified my
example significantly for discussion -- I'm not actually using a Singleton,
but it's an easy situation to think about.

I'd like to ask a couple follow up questions here:

By using...

@classmethod
def normal_constructor(cls, *args, **kwargs):
    return type.__call__(cls, *args, **kwargs)   # Aside: Yes, the `cls`
does need to be in here

... I'm assuming that there are no inherited metaclasses. I'm explicitly
saying, "No matter what the super() functionality for creating the class
is, always use `type`.__call__'s functionality".  That seems
wrong/unpythonic to me, or at least inconsistent with how non-metaclass
inheritance works in python (ie you are encouraged to use `super()` when
using single inheritance).

Because of that, my guess is...

@classmethod
def normal_constructor(cls, *args, **kwargs):
    return super(cls).__call__(cls, *args, **kwargs)
    # or maybe it should be:
    return super(my_metaclass, cls).__call__(cls, *args, **kwargs)

... is closer to the correct approach because it will properly hit the
`__call__` method of the metaclass's parent class (which will often ey
`type`'s `__call__` method if the metaclass doesn't inherit from any other
metaclass).  However, I've never seen anything like that after years of
working with / reading about metaclasses.

Does that help redefine my question a little bit? You said all three look
"weird and scary", but I don't know why. Can you explain that a bit
please?  The 3rd example I gave (using `cls.__new__` and `self.__init__`) I
agree is a bit weird and scary, and in my opinion that's because I am
assuming what the correct sequence of calls is for how classes are normally
instantiated. So I'm the least thrilled with that one. I feel like using
super is the correct choice -- for the reasons I listed above -- but I
would like a more expert opinion (and I'd like to learn why :)).

Thanks!
Jason

On Thu, Nov 2, 2017 at 12:28 AM, Steve D'Aprano <steve+python at pearwood.info>
wrote:

> On Thu, 2 Nov 2017 10:13 am, Jason Maldonis wrote:
>
> > Hi everyone,
> >
> > I want to use a metaclass to override how class instantiation works. I've
> > done something analogous to using the Singleton metaclass from the
> Python3
> > Cookbook example.
>
> In my opinion, nine times out of ten, using a metaclass for something like
> that is overkill.
>
> (And that's putting aside the fact that 999 out of a thousand, using a
> Singleton is the wrong solution, no matter what the question is.)
>
>
> > However, I want to provide a classmethod that allows for "normal" class
> > instantiation that prevents this metaclass from being used.
>
> To me, that strongly suggests that a metaclass is the wrong solution.
>
>
> > To do that, I think I just make a @classmethod constructor function.
> > However, I can imagine a few different ways of writing this:
> >
> > @classmethod
> > def normal_constructor(cls, *args, **kwargs):
> >     return type.__call__(*args, **kwargs)
>
> Untested, but I think that should be:
>
>     return type.__call__(cls, *args, **kwargs)
>
>
> > @classmethod
> > def normal_constructor(cls, *args, **kwargs):
> >     return super(???).__call__(*args, **kwargs)  # I'm not sure what
> should
> > go in the super here  (I'm using python3)
> >
> > @classmethod
> > def normal_constructor(cls, *args, **kwargs):
> >     self = cls.__new__(cls)
> >     self.__init__(*args, **kwargs)
> >     return self
> >
> > Is one of these correct? Or do they all do the same thing?
>
> None of them look "correct", they all look "weird and scary" :-)
>
> If I had to pick one of these three -- and I hope that I would not -- I'd
> pick
> the first one.
>
>
> > I was looking for documentation for what exactly `type.__call__` does so
> > that I can emulate it,
>
> And then if type.__call__ changes, your emulation will be wrong.
>
>
> > but I wasn't able to find any docs explicitly
> > detailing what that method does. If someone knows where this info is that
> > would be great too.
>
>
>
> --
> Steve
> “Cheer up,” they said, “things could be worse.” So I cheered up, and sure
> enough, things got worse.
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>



More information about the Python-list mailing list