Dealing with non-callable classmethod objects

Weatherby,Gerard gweatherby at uchc.edu
Sat Nov 12 13:44:32 EST 2022


Use the inspect module as Cameron suggested.


import inspect


def analyze_class(clzz):
    """Analyze a class proof of concept"""
    assert inspect.isclass(clzz)
    for k, v in inspect.getmembers(clzz, lambda v: inspect.isfunction(v) or inspect.ismethod(v)):
        if inspect.ismethod(v):
            print(f"{v.__qualname__} -> class method ")
        if inspect.isfunction(v):
            sig = inspect.signature(v)
            names = [n for n, _ in sig.parameters.items()]
            if len(names) > 0 and str(names[0]) == 'self':
                print(f"{v.__qualname__}->  probably a bound method ")
            else:
                print(f"{v.__qualname__}->  probably a static method ")


class Demo:

    @classmethod
    def us(cls):
        print(cls.__name__)

    @staticmethod
    def double(x):
        return x + x

    def triple(self, y):
        return 3 * y


analyze_class(Demo)

output:

Demo.double->  probably a static method
Demo.triple->  probably a bound method
Demo.us -> class method



From: Python-list <python-list-bounces+gweatherby=uchc.edu at python.org> on behalf of Ian Pilcher <arequipeno at gmail.com>
Date: Saturday, November 12, 2022 at 11:36 AM
To: python-list at python.org <python-list at python.org>
Subject: Re: Dealing with non-callable classmethod objects
*** Attention: This is an external email. Use caution responding, opening attachments or clicking on links. ***

On 11/11/22 16:47, Cameron Simpson wrote:
> On 11Nov2022 15:29, Ian Pilcher <arequipeno at gmail.com> wrote:
>> * Can I improve the 'if callable(factory):' test above?  This treats
>>  all non-callable objects as classmethods, which is obviously not
>>  correct.  Ideally, I would check specifically for a classmethod, but
>>  there doesn't seem to be any literal against which I could check the
>>  factory's type.
>
> Yeah, it does feel a bit touchy feely.
>
> You could see if the `inspect` module tells you more precise things
> about the `factory`.
>
> The other suggestion I have is to put the method name in `_attrs`; if
> that's a `str` you could special case it as a well known type for the
> factory and look it up with `getattr(cls,factory)`.

So I've done this.

     class _HasUnboundClassMethod(object):
         @classmethod
         def _classmethod(cls):
             pass  # pragma: no cover
         _methods = [ _classmethod ]

     _ClassMethodType = type(_HasUnboundClassMethod._methods[0])

Which allows me to do this:

     def __init__(self, d):
         for attr, factory in self._attrs.items():
             if callable(factory):
                 value = factory(d[attr])
             else:
                 assert type(factory) is self._ClassMethodType
                 value = factory.__func__(type(self), d[attr])
             setattr(self, attr, value)

It's a bit cleaner, although I'm not thrilled about having a throwaway
class, just to define a literal that ought to be provided by the
runtime.

--
========================================================================
Google                                      Where SkyNet meets Idiocracy
========================================================================

--
https://urldefense.com/v3/__https://mail.python.org/mailman/listinfo/python-list__;!!Cn_UX_p3!nx6jxVGHt4Gj1WplLAV4uuhaMyS7Ry0qTCGvZm7jLCj9GbK4vto49sfmP12TTgcAT6Akjz5hJWw9JoylO_FrgQ$<https://urldefense.com/v3/__https:/mail.python.org/mailman/listinfo/python-list__;!!Cn_UX_p3!nx6jxVGHt4Gj1WplLAV4uuhaMyS7Ry0qTCGvZm7jLCj9GbK4vto49sfmP12TTgcAT6Akjz5hJWw9JoylO_FrgQ$>


More information about the Python-list mailing list