Методы и декораторы Python - PullRequest
0 голосов
/ 24 июня 2011

У меня следующая проблема:

Мне нужно написать декоратор, который мог бы обнаружить ситуацию, когда он используется вокруг метода и обычной функции.

Итак, давайте рассмотрим следующий код:

def somedecorator(fn):
    print "decorating function:", fn
    print "function class:", fn.__class__
    return fn

@somedecorator
def regular_func():
    print "I'm a regular function"

class SomeClass(object):

    @somedecorator
    def class_method(self):
        print "I'm a class method"

Вывод гласит:

decorating function: <function regular_func at 0x181d398>
function class: <type 'function'>
decorating function: <function class_method at 0x181d410>
function class: <type 'function'>

Однако пишу:

print regular_func
print SomeClass.class_method
print SomeClass().class_method

Производит продукцию:

<function regular_func at 0x181d398>
<unbound method SomeClass.class_method>
<bound method SomeClass.class_method of <__main__.SomeClass object at 0x16d9e50>>

Так что (как это не удивительно) оказывается, что декораторы применяются к функциям до того, как они превращаются в методы.

Вопрос: Что бы вы предложили отличить эти два приложения от точки зрения декоратора?

EDIT Для любопытных - мне нужно описанное различие из-за травления. Я действительно не хочу вдаваться в подробности об этом.

Ответы [ 2 ]

2 голосов
/ 24 июня 2011

Может быть, смотрит на стек?

def somedecorator(fn):
    import traceback
    print "decorating function:", fn
    print "function class:", fn.__class__
    print traceback.extract_stack()[-2][2]
    return fn

Если декоратор был вызван из модуля, выводит 'module' и из метода выводит 'SomeClass'.Если вызывается изнутри, функция возвращает также имя функции, поэтому, чтобы различить оба случая, вы могли бы искать locals () и globals (), чтобы узнать, что, черт возьми, эти имена: функции или классы.

Что делатьВы думаете?

Редактировать: Объекты могут быть вне области видимости, так что глобальные () и локальные () вещи не будут работать ...

1 голос
/ 24 июня 2011

Вы не можете. Метод является функцией. Внутри класса есть только обычная функция. Магия дескриптора метода-экземпляра происходит только тогда, когда создается экземпляр объекта, а дескрипторы являются частью объекта, а не частью класса. «Несвязанные методы» (которые, кстати, исчезли в Python 3 по уважительным причинам - они бесполезны, являются бессмысленным понятием и требуют дополнительных затрат) - это только временные объекты-обертки вокруг этих функций, генерируемые всякий раз, когда функция будет доступна как атрибут класс.

Самый разумный способ провести различие между методом и функцией - это предоставить два декоратора и позволить программистам решить, какой из них применить. Или, что еще лучше, покончите с этим странным разделением - методы - это функции, ничего особенного, вы должны относиться к ним как к таковым.

...