Is there a way to implement methods like __len__ or __eq__ as classmethods?

前端 未结 3 1647
傲寒
傲寒 2020-12-03 00:56

It is pretty easy to implement __len__(self) method in Python so that it handles len(inst) calls like this one:

class A(object):

          


        
相关标签:
3条回答
  • 2020-12-03 01:25

    Since a class is an instance of a metaclass, one way is to use a custom metaclass:

    >>> Meta = type('Meta', (type,), {'__repr__': lambda cls: 'class A'})
    >>> A = Meta('A', (object,), {'__repr__': lambda self: 'instance of class A'})
    >>> A
    class A
    >>> A()
    instance of class A
    
    0 讨论(0)
  • 2020-12-03 01:29

    What you're looking for is called a "metaclass"... just like a is an instance of class A, A is an instance of class as well, referred to as a metaclass. By default, Python classes are instances of the type class (the only exception is under Python 2, which has some legacy "old style" classes, which are those which don't inherit from object). You can check this by doing type(A)... it should return type itself (yes, that object has been overloaded a little bit).

    Metaclasses are powerful and brain-twisting enough to deserve more than the quick explanation I was about to write... a good starting point would be this stackoverflow question: What is a Metaclass.

    For your particular question, for Python 3, the following creates a metaclass which aliases len(A) to invoke a class method on A:

    class LengthMetaclass(type):
    
        def __len__(self):
            return self.clslength()
    
    class A(object, metaclass=LengthMetaclass):
    
        @classmethod
        def clslength(cls):
            return 7
    
    print(len(A))
    

    (Note: Example above is for Python 3. The syntax is slightly different for Python 2: you would use class A(object):\n __metaclass__=LengthMetaclass instead of passing it as a parameter.)

    The reason LengthMetaclass.__len__ doesn't affect instances of A is that attribute resolution in Python first checks the instance dict, then walks the class hierarchy [A, object], but it never consults the metaclasses. Whereas accessing A.__len__ first consults the instance A, then walks it's class hierarchy, which consists of [LengthMetaclass, type].

    0 讨论(0)
  • 2020-12-03 01:31

    try this:

    class Lengthy:
        x = 5
        @classmethod
        def __len__(cls):
            return cls.x
    

    The @classmethod allows you to call it directly on the class, but your len implementation won't be able to depend on any instance variables:

    a = Lengthy()
    len(a)
    
    0 讨论(0)
提交回复
热议问题