tcpiper
tcpiper

Reputation: 2554

How to get all methods (including all parents' methods) of a class in its metaclass?

For example:

class Meta(type):
    def __new__(cls, name, parents, attrs):
        new_attrs={}
        for k,v in attrs.items():
            # Here attrs only has methods defined in "name", this is not I want.
            print(k,v)
            new_attrs[k] = v
        return type.__new__(cls, name, parents, new_attrs)

class meta(metaclass=Meta):
    pass

class a(object):
    def a1(self):
        return self.a2()

    def a2(self):
        print('a2 voked')

class b(a):
    def b1(self):
        return self.b2()

    def b2(self):
        return self.a1()

class c(b):
    def c1(self):
        return self.b1()

class d(c,meta):
    def d1(self):
        return self.c1()
x=d()
x.d1()

The result is:

>>> 
__qualname__ meta
__module__ __main__
__qualname__ d
d1 <function d.d1 at 0x0000000002A7B950>
__module__ __main__
a2 voked

As you can see, in __new__ of Meta, except special methods, only d1 is accessible. But I want to get all its parents' methods as well(.i.e a1 a2 b1 b2 and c1 objects) so I can do something useful when class d is creating via metaclass, such as add a decorator to all its methods. so how ?

I know one similar way to get this, but it is a little complicated and in fact, it is after class d is created.:

import inspect

class Print(object):
    @classmethod
    def printize(cls,):
        for name,attr in inspect.getmembers(cls):
            # here all methods are accessible
            # you can do something like:
            # setattr(cls,name, f(attr))

class d(c,Print):
    def d1(self):
        return self.c1()

d.printize()

Upvotes: 2

Views: 100

Answers (2)

glglgl
glglgl

Reputation: 91149

The way you use it, all methods in the parent classes will already be present.

But you could walk through the parent classes provided by parents and use their __dict__ (which you should do recursively, then) or use dir() (which takes care of recursing into parent classes as well).

Another approach could be to apply meta earlier.

Upvotes: 0

perreal
perreal

Reputation: 98118

x=d()
p = type(x)
while p != object:
    print(p.__bases__)
    p = p.__bases__[0]

Gives:

(<class '__main__.c'>, <class '__main__.meta'>)
(<class '__main__.b'>,)
(<class '__main__.a'>,)
(<class 'object'>,)

Or you can do:

import inspect
print(inspect.getmro(type(x)))

To get:

(<class '__main__.d'>, <class '__main__.c'>, <class '__main__.b'>, 
     <class '__main__.a'>, <class '__main__.meta'>, <class 'object'>)

Upvotes: 1

Related Questions