Home > Software design >  Implementation of classmethod
Implementation of classmethod

Time:08-20

From the python documentation, the classmethod is roughly equivalent to

class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, klass=None):
        print(klass)
        if klass is None:
            klass = type(obj)
        def newfunc(*args):
            return self.f(klass, *args)
        return newfunc

My question is: In what cases, the klass is None.

I tested with a Test class

class Test(object):
    def __init__(self):
        pass

    @ClassMethod
    def fromstring(cls, s):
        res = cls()
        res.s = s
        return res

t1 = Test.fromstring("a")
t2 = Test()
t3 = t2.fromstring("a")

In those cases, the klass is <class 'main.Test'>.

CodePudding user response:

From the docs:

PEP 252 specifies that __get__() is callable with one or two arguments. Python’s own built-in descriptors support this specification; however, it is likely that some third-party tools have descriptors that require both arguments. Python’s own __getattribute__() implementation always passes in both arguments whether they are required or not.

__get__ is specified to be callable with one argument, as the second argument is redundant when the first argument is non-None. However, object.__getattribute__ and type.__getattribute__ will never call __get__ with a single argument.

Single-argument __get__ calls would have to originate somewhere else - some code other than object.__getattribute__ or type.__getattribute__ calling __get__ manually.

CodePudding user response:

I believe the question why there is a need for these two lines:

if klass is None:
    klass = type(obj)

It is true that when calling either Test.fromstring("a") or t2.fromstring("a"), the klass argument is filled in automatically as in always present.

However, the __get()__ method can be also called directly by the user (or some other tool) with only the obj argument. The classmethod will still work:

>>> vars(Test)['fromstring'].__get__(t2)("a").s
None
'a'
  • Related