Найти - Пользователи
Полная версия: класс-декоратор и декорируемый метод, как передать self?
Начало » Python для новичков » класс-декоратор и декорируемый метод, как передать self?
1
Levitanus
Столкнулся с проблемой, что при декорировании метода класса с помощью декоратора вида:

 class Dec:
    def __init__(self, func):
        self.func = func
        # self.__call__ = wraps(self.func)(self.__call__)
    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)
@Dec
def func(arg, kwarg=1):
    print('func. arg =', arg, 'kwarg =', kwarg)
    return
class Test:
    def __init__(self):
        self.attr = 1
    @Dec
    def func(self, arg, kwarg=1):
        print('Test.func. arg =', arg, 'kwarg =',
              kwarg, 'self.attr = ', self.attr)
        return
func(1)
func(1, 3)
obj = Test
obj.func(1)
obj.func(1, 3)

теряется аргумент self.
В то же время, если передавать self вместе с прилетающими аргументами, я передаю не self декорируемого метода, а self декоратора. Так куда пропадает self от декорруемого метода?
Levitanus
нашел магию, которая сработала.
Объясните, пожалуйста, что это и как работает?)
 def __get__(self, instance, instancetype):
        """Implement the descriptor protocol to make decorating instance 
        method possible.
        """
        # Return a partial function with the first argument is the instance 
        #   of the class decorated.
        return functools.partial(self.__call__, instance)
Levitanus
так, в общем чуть-чуть механику я понял, что при вызове функции через инстанцию (self) мы получаем call с добавленным аргументом self.
При этом, можно пользоваться классом декоратора через класс (class.function.attribute). Для этого надо ввести проверку на None:
 if instance is None:
    return self
А чем это все хозяйство отличается от @wraps, и можно ли сделать через него? Чтоб уж докстринги и пр перетаскивать.
py.user.next
Чтобы пользоваться декораторами (создавать их, а потом использовать), нужно освоить паттерн ООП “Декоратор”. А чтобы использовать паттерны ООП, нужно в само ООП углубиться неслабо, чтобы чувствовать его преимущество перед простыми функциями. В ООП есть три кита, на которых оно стоит, - инкапсуляция, наследование, полиморфизм. Вот паттерн декоратор - это одно из средств для реализации полиморфизма в программе.

Так что твои ковыряния в декораторах - это как ковыряния маленького мальчика в компонентах термоядерной бомбы. Оно тебе просто не пригодится в ближайшее время (ближайшие несколько лет изучения программирования).
Rodegast
> нашел магию, которая сработала. Объясните, пожалуйста, что это и как работает?)

Ты на дескрипторы наткнулся. Вот хорошее видео по этой теме
https://www.youtube.com/watch?v=niBn5obLTHw
Levitanus
Возвращаясь к теме:
кто работает в sublime text + anaconda (или использует в каком-то виде jedi), не сталкивались с таким?
 from functools import wraps
def Dec(f):
    @wraps(f)
    def wrapper(*a, inline=None, **kw):
        if inline:
            print(f'inlined {f}')
        return f(*a, **kw)
    return wrapper
class Test:
    @Dec
    def foo(self, arg1, arg2):
        '''class method docstring'''
        print(f'self={self}, arg1={arg1}, arg2={arg2}')
@Dec
def foo(arg1, arg2):
    '''just foo docstring'''
    print(f'arg1={arg1}, arg2={arg2}')
Test().foo(1, 2, inline=True)
foo(1, 2)
print(Test().foo.__doc__)
print(foo.__doc__)
вывод:
inlined <function Test.foo at 0x000001579FBEFC80>
self=<__main__.Test object at 0x000001579FA9D9B0>, arg1=1, arg2=2
arg1=1, arg2=2
class method docstring
just foo docstring



То есть, wraps в интерпретаторе работает как надо, но jedi почему-то в классе не переходит по нему.
А встроенные декораторы отлично работают.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB