Уведомления

Группа в Telegram: @pythonsu

#1 Июль 17, 2018 00:02:16

Levitanus
Зарегистрирован: 2018-05-01
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

класс-декоратор и декорируемый метод, как передать self?

Столкнулся с проблемой, что при декорировании метода класса с помощью декоратора вида:

 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 от декорруемого метода?

Офлайн

#2 Июль 17, 2018 00:16:22

Levitanus
Зарегистрирован: 2018-05-01
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

класс-декоратор и декорируемый метод, как передать self?

нашел магию, которая сработала.
Объясните, пожалуйста, что это и как работает?)

 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)

Офлайн

#3 Июль 17, 2018 01:14:38

Levitanus
Зарегистрирован: 2018-05-01
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

класс-декоратор и декорируемый метод, как передать self?

так, в общем чуть-чуть механику я понял, что при вызове функции через инстанцию (self) мы получаем call с добавленным аргументом self.
При этом, можно пользоваться классом декоратора через класс (class.function.attribute). Для этого надо ввести проверку на None:

 if instance is None:
    return self
А чем это все хозяйство отличается от @wraps, и можно ли сделать через него? Чтоб уж докстринги и пр перетаскивать.

Отредактировано Levitanus (Июль 17, 2018 01:16:44)

Офлайн

#4 Июль 17, 2018 02:07:16

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9716
Репутация: +  842  -
Профиль   Отправить e-mail  

класс-декоратор и декорируемый метод, как передать self?

Чтобы пользоваться декораторами (создавать их, а потом использовать), нужно освоить паттерн ООП “Декоратор”. А чтобы использовать паттерны ООП, нужно в само ООП углубиться неслабо, чтобы чувствовать его преимущество перед простыми функциями. В ООП есть три кита, на которых оно стоит, - инкапсуляция, наследование, полиморфизм. Вот паттерн декоратор - это одно из средств для реализации полиморфизма в программе.

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



Отредактировано py.user.next (Июль 17, 2018 02:13:04)

Офлайн

#5 Июль 17, 2018 10:50:36

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2679
Репутация: +  182  -
Профиль   Отправить e-mail  

класс-декоратор и декорируемый метод, как передать self?

> нашел магию, которая сработала. Объясните, пожалуйста, что это и как работает?)

Ты на дескрипторы наткнулся. Вот хорошее видео по этой теме
https://www.youtube.com/watch?v=niBn5obLTHw



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#6 Авг. 19, 2018 00:30:08

Levitanus
Зарегистрирован: 2018-05-01
Сообщения: 46
Репутация: +  0  -
Профиль   Отправить e-mail  

класс-декоратор и декорируемый метод, как передать self?

Возвращаясь к теме:
кто работает в 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 почему-то в классе не переходит по нему.
А встроенные декораторы отлично работают.

Прикреплённый файлы:
attachment 2018-08-19_04-11-48.png (9,5 KБ)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version