iJa*_*mes 10 lisp python oop decorator
对于这个抽象的问题,我回到了我的CLOS(Common Lisp对象系统)时代.
我正在扩大问题以澄清:
在我看来,Python装饰器有点像CLOS中的"around"方法.
根据我的记忆,CLOS中的"around"方法是一个包装同名主要方法/函数的方法/函数. 它也会遍历子类. 这是一些语法(我抓住了我的书).
所有这些方法 这将是一个类中:
(defmethod helloworld ()
(format t "Hello World"))
Run Code Online (Sandbox Code Playgroud)
也可以在方法之前和之后(我为了完整而投入):
(defmethod helloworld :before ()
(format t "I'm executing before the primary-method"))
(defmethod helloworld :after ()
(format t "I'm executing after the primary-method"))
Run Code Online (Sandbox Code Playgroud)
最后是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."))
Run Code Online (Sandbox Code Playgroud)
我相信输出将是:
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.
Run Code Online (Sandbox Code Playgroud)
我一直使用这种对类及其方法的理解作为开发代码的参考点.不幸的是,很少有语言似乎通过它们的方法参数化和功能来实现这一目标.
我是Python的新手,我正试图看看装饰器是如何适应的.它们看起来有点宽松,因为装饰器可以是一个完全外部的函数,它能够在调用信息中操纵信息,甚至修改实例和调用对象的类变量,并且它似乎预先形成了around方法的作用,如此处所示.但我希望有人可以帮助解释装饰器和周围方法之间的关系.我以为有人真的希望有机会这样做.
让CLOS强大的原因是你可以使用这些方法进行多重继承.因此,一个类可以由超类组成,这些超类包含处理自身的不同功能和属性.因此,其中一个超类的around方法可能会终止flow(如果没有"call-next-method"),就像装饰器显然可以工作一样.那么它和装饰者一样,还是不同?在around方法中,你传递的是相同的参数,但是对于装饰器,你在一个严格的定义中传入"函数",它会得到增强.但结果是一样的吗?
非常感谢!也许有人可以在Python中显示上述近似值.
完成调用下一个方法.
因此,问题不在于在Python中实现CLOS方法,而是显示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 ...
Run Code Online (Sandbox Code Playgroud)
如果三角形的实例具有visible = false,则render:around将不会调用三角形的主要方法.
换句话说,render方法的调用链是(a)可渲染的:around,(b)三角形primary,(c)完成可渲染:around.如果三角形有一个:after方法,它将在primary之后调用,然后around方法将完成.
我理解使用继承与考虑更新的设计模式的困难,但在这里我试图弥合我的CLOS知识.如果有一个与装饰器匹配的设计模式(比"装饰器"设计模式更准确),那么理解也是很好的.
我正在掌握装饰者.但我想提出我试图模仿CLOS方法遍历的地方.自从我拿到这本书以来,每个人都激励我去尝试它,我记得很清楚.感谢所有伟大的建议,他们都是一个难题.在单个装饰器中实现实际结构方面,Will得到了接近,这就是通过动态方法查找推动它前进的方法(见下文).我已经创建了一个装饰器,可以完成我正在寻找的任务并可以在任何类上运行.我敢肯定它可能更干净,并且有一个问题,它只查找一个超类,并且它正在做奇怪的方法,但它确实有效.
'''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"
Run Code Online (Sandbox Code Playgroud)
这是输出,所以你可以看到我正在尝试做什么.
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
Run Code Online (Sandbox Code Playgroud)
我希望能够创造一些对CLOS调用的理解,并激发关于如何改进装饰器的想法,或者如何在我试图去做的时候骂我.:-)
这是一个快速而肮脏的实现,稍微好一点的实现(现在希望在正确的位置调用 around 方法),使用装饰器
def hints(before=None, after=None, around=None):
"""A decorator that implements function hints to be run before, after or
around another function, sort of like in the CLOS."""
# Make sure all of our hints are callable
default = lambda *args, **kwargs: None
before = before if callable(before) else default
after = after if callable(after) else default
around = around if callable(around) else default
# The actual decorator function. The "real" function to be called will be
# pased to this as `fn`
def decorator(fn):
# The decorated function. This is where the work is done. The before
# and around functions are called, then the "real" function is called
# and its results are stored, then the around and after functions are
# called.
def decorated(*args, **kwargs):
around(*args, **kwargs)
before(*args, **kwargs)
result = fn(*args, **kwargs)
after(*args, **kwargs)
around(*args, **kwargs)
return result
return decorated
return decorator
# Shortcuts for defining just one kind of hint
def before(hint):
return hints(before=hint)
def after(hint):
return hints(after=hint)
def around(hint):
return hints(around=hint)
# The actual functions to run before, after, around
def beforefn():
print 'before'
def afterfn():
print 'after'
def aroundfn():
print 'around'
# The function around which the other functions should run
@before(beforefn)
@after(afterfn)
@around(aroundfn)
def fn():
print 'Hello World!'
# Or use the single @hints decorator
@hints(before=beforefn, after=afterfn, around=aroundfn)
def fn2():
print 'Goodbye World!'
Run Code Online (Sandbox Code Playgroud)
调用fn()结果如下:
>>> fn()
around
before
Hello World!
after
around
>>> fn2()
around
before
Goodbye World!
after
around
Run Code Online (Sandbox Code Playgroud)
这种情况下的装饰器可能有点令人困惑,因为每个装饰器都涉及两个嵌套函数,而不是许多装饰器中看到的一个嵌套函数。
它可能不像 CLOS 版本那么优雅(而且我可能会缺少它的一些功能),但它似乎可以满足您的需求。