简体   繁体   中英

Save all class methods with decorator

i have a class and i want to all its methods in a list inside the class, i want it to work even if i have two methods with the same name, my problem is i can't access the class to put the methods there. lets say i have the decorator

def dec(func):
    class = ????
    class.methods.append(func)
    return func

and i have the class

class A(object):
    methods = []
    @dec
    def a(self):
       print 2
    @dec
    def a(self):
       print 3

i want to be able to do

A.methods[0](A())
A.methods[1](A())
(A() becuase those methods need self)

or something like that

I already read a lot of problems like this and it looks like what i want is not really possible since A is not exist when the decorator is called, but maybe there is a way to access its variables since the decorator runs inside it?

The class object itself is only constructed after the body statements (all the statements inside the class <classname>(<bases,>): block have been executed. Decorators on the other hand are executed together with the function they are decorating.

You could just in the list you want methods to be added to, to your decorator:

class A(object):
    methods = []
    @dec(methods)
    def a(self):
        print 2
    @dec(methods)
    def a(self):
        print 3

and have the decorator use that list to append your methods:

def dec(methodslist):
    def decorator(f):
        methodslist.append(f)
        return f
    return decorator

If you are using Python 3, then another option is for you to use a metaclass with a custom metaclass.__prepare__ class method that uses collections.defaultdict() to collect all attributes into lists first so you can still access them even if named the same. Your decorator then only needs to 'mark' each function object with an extra attribute or something. This is a little more involved.

When you then want to call those functions, you are right that they are not bound and won't have self passed in for you. Either manually pass in self , or bind the manually. Functions are descriptor objects , call their __get__ method to bind them to an instance:

for func in self.methods:
    method = func.__get__(self)
    method()

Demo:

>>> def dec(methodslist):
...     def decorator(f):
...         methodslist.append(f)
...         return f
...     return decorator
...
>>> class A(object):
...     methods = []
...     @dec(methods)
...     def a(self):
...         print 2
...     @dec(methods)
...     def a(self):
...         print 3
...     def call_all(self):
...         for func in self.methods:
...             method = func.__get__(self)
...             method()
...
>>> A().call_all()
2
3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM