Декораторы Python по сравнению с методом «около» CLOS

I" Я возвращаюсь к моим дням CLOS (Common Lisp Object System) для этого абстрактного вопроса.

Я усиливаю вопрос, чтобы прояснить:

Мне кажется, что декоратор Python похож на метод «вокруг» в CLOS.

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

Все эти методы Этот будет внутри класса:

(defmethod helloworld ()
  (format t "Hello World"))

Могут быть также методы до и после (я добавление для полноты) :

(defmethod helloworld :before ()
  (format t "I'm executing before the primary-method"))

(defmethod helloworld :after ()
  (format t "I'm executing after the primary-method"))

И, наконец, метод around (Обратите внимание, что этот метод выглядел как декоратор) :

(defmethod helloworld :around ()
  (format t "I'm the most specific around method calling next method.")
  (call-next-method)
  (format t "I'm the most specific around method done calling next method."))

Я считаю, что результат будет:

I'm the most specific around method calling next method. 
I'm executing before the primary-method
Hello World
I'm executing after the primary-method
I'm the most specific around method done calling next method.

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

Я новичок в Python и пытаюсь понять, как сюда подходят декораторы. Они кажутся немного более свободными в том смысле, что декоратор может быть полностью внешняя функция, которая, тем не менее, имеет возможность манипулировать информацией в вызывающей информации и даже изменять переменные экземпляра и класса вызываемого объекта, и, кроме того, она, похоже, выполняет роль метода around, как показано здесь. Но я надеялся, что кто-нибудь сможет объяснить связь между декораторами и методами . Я думал, что кому-то действительно понравится такая возможность.

Что делает CLOS мощным для меня, так это то, что с помощью этих методов вы можете иметь множественное наследование. Таким образом, класс может состоять из суперклассов, которые содержат различные функции и атрибуты, которые обрабатывают сами себя. Таким образом, метод around в одном из суперклассов может прервать поток (если "call-next-method" не выполнен), точно так же, как декоратор, очевидно, может работать. Это то же самое, что и декоратор, или другое? В методе round вы передаете те же аргументы, но декоратору вы передаете «функцию» в строгом определении, которое расширяется. Но такой же результат?

Большое спасибо! Может быть, кто-нибудь сможет показать близкое приближение к приведенному выше в Python. Таким образом, класс может состоять из суперклассов, которые содержат различные функции и атрибуты, которые обрабатывают сами себя. Таким образом, метод around в одном из суперклассов может прервать поток (если "call-next-method" не выполнен), точно так же, как декоратор, очевидно, может работать. Это то же самое, что и декоратор, или другое? В методе round вы передаете те же аргументы, но декоратору вы передаете «функцию» в строгом определении, которое расширяется. Но такой же результат?

Большое спасибо! Может быть, кто-нибудь сможет показать близкое приближение к приведенному выше в Python. Таким образом, класс может состоять из суперклассов, которые содержат различные функции и атрибуты, которые обрабатывают сами себя. Таким образом, метод around в одном из суперклассов может прервать поток (если "call-next-method" не выполнен), точно так же, как декоратор, очевидно, может работать. Это то же самое, что и декоратор, или другое? В методе round вы передаете те же аргументы, но декоратору вы передаете «функцию» в строгом определении, которое расширяется. Но такой же результат?

Большое спасибо! Может быть, кто-нибудь сможет показать близкое приближение к приведенному выше в Python. Это то же самое, что и декоратор, или другое? В методе round вы передаете те же аргументы, но декоратору вы передаете «функцию» в строгом определении, которое расширяется. Но такой же результат?

Большое спасибо! Может быть, кто-нибудь сможет показать близкое приближение к приведенному выше в Python. Это то же самое, что и декоратор, или другое? В методе round вы передаете те же аргументы, но декоратору вы передаете «функцию» в строгом определении, которое расширяется. Но такой же результат?

Большое спасибо! Может быть, кто-нибудь сможет показать близкое приближение к приведенному выше в Python. завершен вызов следующего метода.

Таким образом, проблема заключается не в реализации методов CLOS в Python, а в том, чтобы показать, насколько близко Python подходит к этой системе питоническим способом. Или показать, чем Python на самом деле лучше этого.

Это больше похоже на пример, о котором я думал:

class shape with attributes position and method area
class renderable with attribute visible and methods render, and render :around
class triangle with superclass shape and renderable attributes p1,p2,p3 and method render and method area
class square ...

Если экземпляр треугольника имеет visible = false, то render: around не будет вызывать первичный треугольник метод.

Другими словами, вызывающая цепочка метода рендеринга (а) рендерируемая: вокруг, (б) треугольная первичная, (в) завершающая рендеринг: вокруг. Если бы у треугольника был метод: after, он был бы вызван после primary, а затем завершился бы метод around.

Я понимаю трудности использования наследования по сравнению с рассмотрением новых шаблонов проектирования, но здесь я пытаюсь объединить мои знания CLOS . Если здесь' sa шаблон проектирования, который соответствует декораторам (точнее, чем шаблон проектирования "декоратор"), это тоже было бы здорово понять.

Выводы

Я разбираюсь в декораторах. Но я хотел показать, где я пытаюсь имитировать обход метода CLOS. Все вдохновляли меня попробовать, так как книга у меня есть, и я ее очень хорошо помню. Спасибо всем за прекрасные предложения, все они - кусочки головоломки. Что касается реализации фактической структуры в одном декораторе, Уилл подошел близко, и это помогло продвинуть его вперед с помощью динамического поиска методов (см. Ниже). Я создал единственный декоратор, который делает то, что я ищу, и может работать с любым классом. Я уверен, что это могло бы быть чище, и есть проблема, что он ищет только один суперкласс, и это ' s странно обходится с методами, но это действительно работает.

'''file: cw.py'''
'''This decorator does the job of implementing a CLOS method traversal through superclasses.  It is a very remedial example but it helped me understand the power of decorators.'''
'''Modified based on Richards comments'''
def closwrapper(func): # *args, **kwargs  ?
    def wrapper(self):  #what about superclass traversals???
        name = func.__name__
        # look for the methods of the class 
        before_func = getattr(self, name + "_before", None)
        after_func = getattr(self, name + "_after", None)
        around_func = getattr(self, name + "_around", None)
        sup = super(self.__class__,self)
        #self.__class__.__mro__[1]
        if sup:
            # look for the supermethods of the class (should be recursive)
            super_before_func = getattr(sup,name + "_before", None)
            super_after_func = getattr(sup,name + "_after", None))
            super_around_func = getattr(sup,name + "_around", None))

        ''' This is the wrapper function which upgrades the primary method with any other methods that were found above'''
        ''' The decorator looks up to the superclass for the functions.  Unfortunately, even if the superclass is decorated, it doesn't continue chaining up.  So that's a severe limitation of this implementation.'''
        def newfunc():
            gocontinue = True
            supercontinue = True
            if around_func: 
                gocontinue = around_func() 
                if gocontinue and super_around_func:
                  supercontinue = super_around_func()
            if gocontinue and supercontinue:
                if before_func: before_func()
                if super_before_func: super_before_func()
                result = func(self)
                if super_after_func: super_after_func()   
                if after_func: after_func()              
            else:
                result = None
            if gocontinue:
                if super_around_func: super_around_func(direction="out")
            if around_func: around_func(direction='out')
            return result
        return newfunc()

    return wrapper

# Really, the way to do this is to have the decorator end up decorating
# all the methods, the primary and the before and afters.  Now THAT would be a decorator!

class weeclass(object):

    @closwrapper
    def helloworld(self):
        print "Hello Wee World"

    def helloworld_before(self):
        print "Am I really so wee Before?  This method is not called on subclass but should be"



class baseclass(weeclass):
    fooey = 1

    def __init__(self):
        self.calls = 0

    @closwrapper
    def helloworld(self):
        print "Hello World"

    def helloworld_before(self):
        self.fooey += 2
        print "Baseclass Before"

    def helloworld_after(self):
        self.fooey += 2
        print "Baseclass After Fooey Now",self.fooey

    def helloworld_around(self,direction='in'):
        if direction=='in': 
            print "Aound Start"
            if self.fooey < 10:
                return True
            else:
                print ">>FOOEY IS TOO BIG!!!"
                self.fooey = -10
                return False
        #call-next-method
        if not direction=='in': 
            #self.barrey -= 4  #hello??  This should not work!!!  It should croak?
            print "Around End"  



class subclass(baseclass): 
    barrey = 2

    @closwrapper
    def helloworld(self):
        print "Hello Sub World Fooey",self.fooey,"barrey",self.barrey

    def helloworld_before(self):
        self.fooey -= 1
        self.barrey += 5
        print "  Sub Before"

    def helloworld_after(self):
        print "Sub After"

    def helloworld_around(self,direction='in'):
        if direction=='in': 
            print "Sub Around Start"
            if self.barrey > 4:
                print ">>Hey Barrey too big!"
                self.barrey -= 8
                return False
            else:
                return True
        #call-next-method
        if not direction=='in': 
            self.barrey -= 4
            print "Sub Around End"  

Вот результат, чтобы вы могли видеть, что я пытаюсь сделать.

Python 2.6.4 (r264:75706, Mar  1 2010, 12:29:19)  
[GCC 4.2.1 (Apple Inc. build 5646) (dot 1)] on darwin  
Type "help", "copyright", "credits" or "license" for more information.  
>>> import cw  
>>> s= cw.subclass()  
>>> s.helloworld()  
Sub Around Start  
Aound Start  
Sub Before  
Baseclass Before  
Hello Sub World Fooey 2 barrey 7  
Baseclass After Fooey Now 4  
Sub After  
Around End  
Sub Around End  
>>> s.helloworld()  
Sub Around Start
Aound Start  
Sub Before  
Baseclass Before  
Hello Sub World Fooey 5 barrey 8  
Baseclass After Fooey Now 7  
Sub After  
Around End  
Sub Around End  
>>> s.helloworld()  
Sub Around Start  
Aound Start  
Sub Before  
Baseclass Before  
Hello Sub World Fooey 8 barrey 9  
Baseclass After Fooey Now 10  
Sub After  
Around End  
Sub Around End  
>>> s.helloworld()  
Sub Around Start  
>>Hey Barrey too big!  
Sub Around End  
>>> s.helloworld()  
Sub Around Start  
Aound Start  
>>FOOEY IS TOO BIG!!!  
Around End  
Sub Around End  
>>> s.helloworld()  
Sub Around Start  
Aound Start  
Sub Before  
Baseclass Before  
Hello Sub World Fooey -9 barrey -6  
Baseclass After Fooey Now -7  
Sub After  
Around End  
Sub Around End  
>>> s.helloworld()  
Sub Around Start  
Aound Start  
Sub Before  
Baseclass Before  
Hello Sub World Fooey -6 barrey -5  
Baseclass After Fooey Now -4  
Sub After  
Around End  
Sub Around End  
>>> s.helloworld()  
Sub Around Start  
Aound Start  
Sub Before  
Baseclass Before  
Hello Sub World Fooey -3 barrey -4  
Baseclass After Fooey Now -1  
Sub After  
Around End  
Sub Around End  
>>> b = cw.baseclass()  
>>> b.helloworld()  
Aound Start  
Baseclass Before  
Am I really so wee Before?  This method is not called on subclass but should be  
Hello World  
Baseclass After Fooey Now 5  
Around End  
>>> b.helloworld()  
Aound Start  
Baseclass Before  
Am I really so wee Before?  This method is not called on subclass but should be  
Hello World  
Baseclass After Fooey Now 9  
Around End  
>>> b.helloworld()  
Aound Start  
Baseclass Before  
Am I really so wee Before?  This method is not called on subclass but should be  
Hello World  
Baseclass After Fooey Now 13  
Around End  
>>> b.helloworld()  
Aound Start  
>>FOOEY IS TOO BIG!!!  
Around End  
>>> b.helloworld()  
Aound Start  
Baseclass Before  
Am I really so wee Before?  This method is not called on subclass but should be  
Hello World  
Baseclass After Fooey Now -6  
Around End  

Я надеюсь, что это дает некоторое представление о вызове CLOS, а также пробуждает идеи о том, как улучшить этот декоратор или как критиковать меня за попытку сделать это. :-)

10
задан iJames 20 September 2010 в 23:30
поделиться