Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

python

class

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

class A(object):    def __len__(self):     return 7  a = A() len(a) # gives us 7 

And there are plenty of alike methods you can define (__eq__, __str__, __repr__ etc.). I know that Python classes are objects as well.

My question: can I somehow define, for example, __len__ so that the following works:

len(A) # makes sense and gives some predictable result 
like image 843
ikostia Avatar asked Oct 04 '11 01:10

ikostia


People also ask

What is the __ eq __ method?

Summary. Implement the Python __eq__ method to define the equality logic for comparing two objects using the equal operator ( == )

What is __ len __ in Python?

The Python __len__ method returns a positive integer that represents the length of the object on which it is called. It implements the built-in len() function. For example, if you call len(x) an object x , Python internally calls x. __len__() to determine the length of object x .

What does the __ Add__ method do?

The __add__() method in Python specifies what happens when you call + on two objects. When you call obj1 + obj2, you are essentially calling obj1. __add__(obj2). This works, because int implements the __add__() method behind the scenes.


1 Answers

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].

like image 100
Eli Collins Avatar answered Sep 26 '22 07:09

Eli Collins