Я возвращаюсь к своей CLOS (Common Lisp Object System) дням для этого абстрактного вопроса.
Я уточняю вопрос, чтобы уточнить:
Мне кажется, что декоратор Python похож на метод "around" в CLOS.
Из того, что я помню, метод "around" в 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"))
И, наконец, метод round (Обратите внимание, что этот метод, казалось, был как декоратор):
(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 и пытаюсь понять, как вписываются декораторы. Они кажутся немного более слабыми, поскольку декоратор может быть полностью внешней функцией, которая все же имеет возможность манипулировать информацией в вызывающей информации и даже изменять переменные экземпляра и класса вызываемого объекта и, кроме того, что он, как представляется, выполняет роль метода round, как показано здесь. Но я надеялся, что кто-то может помочь объяснить отношения между декораторами и методами. Я думал, что кому-то действительно понравится возможность сделать это.
Что делает CLOS мощным для меня, так это то, что вы можете иметь множественное наследование с помощью этих методов. Таким образом, класс может состоять из суперклассов, которые содержат различные функциональные возможности и атрибуты, которые обрабатывают себя. Таким образом, метод round на одном из суперклассов может прекратить поток (если "call-next-method" не выполняется), точно так же, как может работать декоратор. Так это то же самое, что и декоратор, или другое? В методе around вы передаете одни и те же аргументы, но для декоратора вы передаете "функцию" в строгом определении, которое будет дополнено. Но результат тот же?
Спасибо большое! Может быть, кто-то может показать приближение к вышеприведенному в Python.
done вызывающий следующий метод.
Таким образом, проблема заключается не в реализации CLOS-методов в Python, а в том, как близко Python добирается до этой системы с помощью pythonic. Или показать, как 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 ...
Если экземпляр треугольника имеет видимый = false, то render: around не будет вызывать первичный метод треугольника.
Другими словами, вызывающая цепочка метода рендеринга (a) визуализируется: вокруг, (b) треугольник первичный, (c) завершает рендеринг: вокруг. Если у треугольника был метод: after, он будет вызываться после первичного, а затем метод round будет завершен.
Я понимаю трудности использования наследования по сравнению с рассмотрением более новых шаблонов проектирования, но здесь я пытаюсь свести свои знания CLOS. Если есть шаблон дизайна, который соответствует декораторам (точнее, чем шаблон дизайна "декоратор" ), это было бы прекрасно также понять.
Заключение
Я получаю украшение декораторов. Но я хотел представить, где я нахожусь, пытаясь подражать обходу метода CLOS. Все вдохновили меня попробовать, так как у меня есть книга, и я очень хорошо ее помню. Спасибо всем за все замечательные предложения, они все часть головоломки. С точки зрения реализации фактической структуры в одном декораторе, Уилл приблизился, и это помогло продвинуть его вперед с помощью динамического поиска методов (см. Ниже). Я создал один декоратор, который делает то, что я ищу, и могу работать на любом классе. Я уверен, что это может быть более чистым, и есть проблема, что он смотрит только на один суперкласс и делает это со странностями, но он работает.
'''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 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, а также искрометные идеи о том, как улучшить этот декоратор, или о том, как заставить меня задуматься, даже пытаясь это сделать.:-)