Я возвращаюсь к своим дням 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"))
И, наконец, метод округления (обратите внимание, что этот метод выглядит как декоратор) :
(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 и пытаюсь понять, как вписываются декораторы. Они кажутся немного более свободными в том, что декоратор может быть полностью внешней функцией, которая все же имеет возможность манипулировать информацией внутри вызывающей информации и даже изменять переменные экземпляра и класса вызываемого объекта, и, кроме того, кажется, что он предопределяет роль метода округления, как показано здесь. Но я надеялся, что кто-нибудь сможет объяснить связь между декораторами и методами . Я думал, что кому-то действительно понравится возможность сделать это.
Что делает CLOS мощным для меня, так это то, что вы можете иметь множественное наследование этими методами. Таким образом, класс может состоять из суперклассов, которые содержат различные функциональные возможности и атрибуты, которые обрабатывают сами себя. Таким образом, метод round в одном из суперклассов может завершить поток (если «call-next-method» не выполнен), так же, как, очевидно, может работать декоратор. Так это то же самое, что декоратор, или другое? В методе 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 не будет вызывать основной метод треугольника.
Другими словами, вызывающая цепочка метода рендеринга: (a) рендеринг: вокруг, (b) первичный треугольник, (c) конец рендеринга: вокруг. Если бы у треугольника был метод: after, он был бы вызван после primary, а затем завершился бы метод 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'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, а также рождает идеи о том, как улучшить этот декоратор, или как проклясть меня, даже если я попытаюсь это сделать. :-)