Байпас декоратора

User avatar
perasperaadastra
Уже с Приветом
Posts: 20128
Joined: 21 Feb 2009 22:55
Location: Лох Онтарио

Байпас декоратора

Post by perasperaadastra »

Пытаюсь разобраться с декораторами (в Питоне, если это имеет значение). Есть вот такой пример, который создает новую функцию combined из функций hello и howru с помощью декоратора.

Code: Select all

def hello(name):									# generate "Hello, <name>"
    return "Hello, "+name

def decorate(func):								# decorator
    def howru(name):					  		# add ", how are you?"
        return func(name)+", how are you?"
    return howru

combined = decorate(hello)						# new combined function to generate "Hello, <name>, how are you?"
print combined("John") 							# output: "Hello, John, how are you?"
Все работает как надо, и проблем нет. Но что если бы я в некоторых случаях хотел использовать только функцию howru? Прямого доступа к ней у меня нет.

Можно, конечно, добавить функцию, которая ничего не делает

Code: Select all

def pass_thru(arg):
    return arg
и дальше декорировать ее, чтобы получить доступ к функции howru:

Code: Select all

just_howru = decorate(pass_thru)
print just_howru("John")						# output "John, how are you?" 
Но мне кажется, в этом подходе есть что-то неправильное.

PS Можно совсем обойтись без декораторов, но тогда нельзя создавать новые функции "на лету":

Code: Select all

def hello(name):                    		# say "Hello, <name>"
    return "Hello, "+name

def howru(name):                    		# add ", how are you?"
    return name+", how are you?"

print howru(hello("John"))          		# output "Hello, <name>, how are you?"
print howru("John")                 		# output "John, how are you?"
User avatar
perasperaadastra
Уже с Приветом
Posts: 20128
Joined: 21 Feb 2009 22:55
Location: Лох Онтарио

Re: Байпас декоратора

Post by perasperaadastra »

Что-то я совсем тупой стал. Все же элементарно!

Переписал декоратор:

Code: Select all

def decorate(func):
    def howru(name):
        return func(name)+just_howru()
    return howru
Добавил функцию:

Code: Select all

def just_howru(name=""):
    return name+", how are you?"
Теперь можно вызывать декоратор, а можно просто just_howru:

Code: Select all

print decorate(hello)("John")
print just_howru("John")
User avatar
Flash-04
Уже с Приветом
Posts: 63430
Joined: 03 Nov 2004 05:31
Location: RU -> Toronto, ON

Re: Байпас декоратора

Post by Flash-04 »

:D делать нечего?
Not everyone believes what I believe but my beliefs do not require them to.
User avatar
perasperaadastra
Уже с Приветом
Posts: 20128
Joined: 21 Feb 2009 22:55
Location: Лох Онтарио

Re: Байпас декоратора

Post by perasperaadastra »

Нет, просто делаю то, что следовало сделать еще 10 лет назад. ИМХО, пригодится.
User avatar
Flash-04
Уже с Приветом
Posts: 63430
Joined: 03 Nov 2004 05:31
Location: RU -> Toronto, ON

Re: Байпас декоратора

Post by Flash-04 »

nested functions - дело такое что не во всех языках они поддерживаются. на мой взгляд они код только мутят.
Not everyone believes what I believe but my beliefs do not require them to.
User avatar
f_evgeny
Уже с Приветом
Posts: 10367
Joined: 12 Apr 2001 09:01
Location: Lithuania/UK

Re: Байпас декоратора

Post by f_evgeny »

perasperaadastra wrote:Что-то я совсем тупой стал. Все же элементарно!
А если просто, по пролетарски?

Code: Select all

def hello(name):                           # generate "Hello, <name>"
    return "Hello, "+name

def howru(name):                       # add ", how are you?"
    return name + ", how are you?"

def decorate(func):                        # decorator
    return lambda name: func(name) + ", how are you?"
    
combined = decorate(hello)                  # new combined function to generate "Hello, <name>, how are you?"
print combined("John")                      # output: "Hello, John, how are you?"
print howru('John')                         # output: "John, how are you?"

Дальше, все будет только хуже. Оптимист.
User avatar
perasperaadastra
Уже с Приветом
Posts: 20128
Joined: 21 Feb 2009 22:55
Location: Лох Онтарио

Re: Байпас декоратора

Post by perasperaadastra »

Ага! Про lambda я не знал, спасибо за наводку. :) Тогда можно сделать так, чтобы дважды не определять howru:

Code: Select all

def decorate(func):
    return lambda name: func(name)+howru()
 
def hello(name):                         
    return "Hello, "+name

def howru(name):
    return name + ", how are you?" 
Теперь я думаю над другой проблемой:

Пусть у меня есть миллион функций, которые я положил в один класс для удобства. И есть старая добрая функция howru.

Code: Select all

class Greet:
    @staticmethod
    def eng(name=""):
        return "Hello, "+name
    @staticmethod
    def fr(name=""):
        return "Bonjour, "+name
    ...    
def just_howru(name=""):
    return name+", how are you?" 
И, допустим, я захотел декорировать все эти миллион функций по тому же принципу, что и выше. Как бы мне организовать итерацию по методам класса Greet?

PS функции eng, fr в данном случае исключительно для примера. Меня интересует общий случай декорирования всех методов класса (за исключением __init__ и т.п.)
User avatar
perasperaadastra
Уже с Приветом
Posts: 20128
Joined: 21 Feb 2009 22:55
Location: Лох Онтарио

Re: Байпас декоратора

Post by perasperaadastra »

Со статическими методами ничего не получилось, пришлось обращаться к обычным. Как я понял, синглтонов в питоне нет, поэтому получается только так:

Code: Select all

def class_Decorator(cls):
    def decorator(func):
        def howru(instance, name):
            return func(instance,name)+just_howru()
        return howru
    for attr, val in cls.__dict__.iteritems():
        if callable(val) and not attr.startswith("__"):
            setattr(cls, attr, decorator(val))
    return cls

@class_Decorator
class Greet:
    def eng(self, name=""):
        return "Hello, "+name
    def fr(self, name=""):
        return "Bonjour, "+name

def just_howru(name=""):
    return name+", how are you?"

G = Greet()
print G.eng("Peter")
print G.fr("Pascal")
Теперь осталось научиться копировать класс, чтобы иметь и исходные методы, и декорированные.
User avatar
f_evgeny
Уже с Приветом
Posts: 10367
Joined: 12 Apr 2001 09:01
Location: Lithuania/UK

Re: Байпас декоратора

Post by f_evgeny »

perasperaadastra wrote:Со статическими методами ничего не получилось, пришлось обращаться к обычным. Как я понял, синглтонов в питоне нет, поэтому получается только так:
Синглтон в Питоне пишется за 1 секунду. Простейший - переменная уровня модуля.
А про задачу о декорировании миллиона методов скажу следующее. Если бы у меня была бы такая задача, я бы сильно подумал, правильна ли вообще постановка задачи, или что-то не так в самой постановке.
Динамическое декорирование - что-то тут не так.
Дальше, все будет только хуже. Оптимист.
User avatar
perasperaadastra
Уже с Приветом
Posts: 20128
Joined: 21 Feb 2009 22:55
Location: Лох Онтарио

Re: Байпас декоратора

Post by perasperaadastra »

Согласен, что задача — извращение. Просто интересно было, насколько далеко можно толкать Питон в этом направлении.
Deckel
Ник закрыт за хамство.
Posts: 357
Joined: 16 Feb 2014 18:34

Re: Байпас декоратора

Post by Deckel »

perasperaadastra wrote:Согласен, что задача — извращение. Просто интересно было, насколько далеко можно толкать Питон в этом направлении.
Байпас декоратора - хорошее название для рассказа Пелевина.
User avatar
Мальчик-Одуванчик
Уже с Приветом
Posts: 15526
Joined: 27 Sep 2007 22:53

Re: Байпас декоратора

Post by Мальчик-Одуванчик »

Deckel wrote:
perasperaadastra wrote:Согласен, что задача — извращение. Просто интересно было, насколько далеко можно толкать Питон в этом направлении.
Байпас декоратора - хорошее название для рассказа Пелевина.
Или может послужить названием нового увлечения в среде либералов, толерантных к половым извращением.

Return to “Вопросы и новости IT”