Почему getattr не работает, когда у функции был декоратор

#python #python-decorators

Вопрос:

У меня есть следующий фрагмент кода, в котором есть два метода func_norule() и func_with_rule(). Метод func_with_rule() украшен @rule, где в качестве функции func_norule() нет никакого декоратора.

Когда я использую функцию getattr, fn = getattr(self, ‘func_norule’) возвращает функцию, где как fn = getattr(self, ‘func_with_rule’) не возвращает ничего.

Есть ли причина, по которой поведение при использовании декоратора отличается от того, когда декоратор не используется? Есть какие-нибудь способы решения этой проблемы?

 class Student():
    def __init__(self, name, roll_no):
        self.name = name
        self.roll_no = roll_no
    
    ## Decorator function to decorate all the rules function
    def rule(func):
        print(func.__name__)
    
    def func_norule(self):
        #This method works with getattr
        print("func_norule:"   self.name)
    
    @rule
    def func_with_rule(self):
        #This method returns None  with getattr
        print("func_with_rule:"   self.name)
    
    def myFunc2(self):
        fn = getattr(self, 'func_norule')
        fn()
        fn = getattr(self, 'func_with_rule')
        fn()

student = Student('myName', 8)
student.myFunc2()
 

Комментарии:

1. Это совсем не то, как должен работать декоратор. Он должен возвращать функцию (новую, украшенную функцию), которая заменит не украшенную. Ваш просто ничего не возвращает явно, поэтому он возвращается None .

Ответ №1:

Это потому, что вы не привязываетесь self к своему декоратору. Вы можете изменить свой декоратор, чтобы self параметр был передан вашему методу оформления:

 class Student:
    # ...

    def rule(func):
        def _(self, *args, **kwargs):
            print("Before calling", func.__name__)
            result = func(self, *args, **kwargs)
            print("After calling", func.__name__)
            return result            

        return _

    # ...

    @rule
    def func_with_rule(self):
        #This method returns None  with getattr
        print("func_with_rule:"   self.name)
 

Теперь, когда вы это сделаете

 student = Student('myName', 8)
student.myFunc2()
 

выходы

 func_norule:myName
Before calling func_with_rule
func_with_rule:myName
After calling func_with_rule
 

Комментарии:

1. Спасибо @enzo, это решение сработало для меня!