Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python装饰器与CLOS的比较;大约;方法_Python_Oop_Lisp_Decorator - Fatal编程技术网

Python装饰器与CLOS的比较;大约;方法

Python装饰器与CLOS的比较;大约;方法,python,oop,lisp,decorator,Python,Oop,Lisp,Decorator,对于这个抽象的问题,我将回到我的CLOS(公共Lisp对象系统)时代 我补充这个问题是为了澄清: 在我看来,Python装饰器有点像CLOS中的“around”方法 据我所知,CLOS中的“around”方法是一种方法/函数,它围绕同名的主方法/函数。它也遍历上下两个子类。这里有一些语法(我刚抓起我的书) 所有这些方法都将在一个类中: (defmethod helloworld () (format t "Hello World")) 也可以有before和after方法(为了完整起见,我

对于这个抽象的问题,我将回到我的CLOS(公共Lisp对象系统)时代

我补充这个问题是为了澄清:

在我看来,Python装饰器有点像CLOS中的“around”方法

据我所知,CLOS中的“around”方法是一种方法/函数,它围绕同名的主方法/函数。它也遍历上下两个子类。这里有一些语法(我刚抓起我的书)

所有这些方法都将在一个类中:

(defmethod helloworld ()
  (format t "Hello World"))
也可以有before和after方法(为了完整起见,我加入了before和after方法):

最后是around方法(注意这里这个方法看起来像一个装饰器):

我相信结果会是:

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非常陌生,正在尝试了解如何适应装饰器。它们看起来有点松散,因为decorator可以是一个完全外部的函数,但它仍然能够处理调用信息中的信息,甚至修改被调用对象的实例和类变量,而且它似乎还预成型了around方法的角色,如图所示。但我希望有人能解释一下装饰师和周围方法之间的关系。我以为有人真的希望有机会这么做

让CLOS对我来说强大的是,您可以使用这些方法进行多重继承。因此,类可以由超类组成,超类包含不同的功能和属性,这些功能和属性可以自行处理。因此,其中一个超类上的around方法可能会终止流(如果“callnextmethod”未完成),就像装饰器的工作方式一样。这和装饰师是一样的,还是不同的?在around方法中,您传递的是相同的参数,但对于decorator,您传递的是严格定义中的“函数”,该定义得到了扩展。但结果是一样的吗?

多谢!也许有人可以在Python中显示与上述内容的近似。 已完成调用下一个方法

因此,问题不在于在Python中实现CLOS方法,而在于展示Python如何以Python的方式接近该系统。或者展示Python实际上是如何比这更好

这更像是我想到的例子:

如果三角形实例的visible=false,则render:around将不会调用三角形的主方法

换句话说,render方法的调用链是(a)renderable:around,(b)triangle primary,(c)finish renderable:around。如果triangle有一个:after方法,它将在primary之后被调用,然后around方法将结束

我理解使用继承与考虑更新的设计模式相比的困难,但在这里,我试图将我的CLOS知识联系起来。如果有一个设计模式与decorator匹配(比“decorator”设计模式更准确),那么理解它也很好

结论 我掌握了装饰师的窍门。但是我想展示一下我在尝试模拟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"  
我希望这能让大家对CLOS的调用有一些了解,也能激发出一些想法,比如如何改进那个装饰师,或者如何抨击我甚至试图这么做。:-)

这里有一个快速而肮脏的实现,使用decorator稍微好一点的实现(现在在正确的位置调用了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!'
调用
fn()
会产生以下结果:

>>> fn()
around
before
Hello World!
after
around
>>> fn2()
around
before
Goodbye World!
after
around
本例中的装饰器可能有点混乱,因为每个装饰器中都有两个嵌套函数,而不是许多装饰器中的一个嵌套函数


它可能没有CLOS版本那么优雅(我可能缺少它的一些功能),但它似乎做了你想做的事情。

我不确定我是否理解
:在
周围,
:在
之前和
:在
之后都很好,但是像这样的东西是你想要的吗

class Base(object):
    def helloworld(self):
        print('Hello World')

class After(object):
    def helloworld(self):
        super(After,self).helloworld()
        print('After')        

class Before(object):
    def helloworld(self):
        print('Before')        
        super(Before,self).helloworld()

class Around(object):
    def helloworld(self):
        print('Enter around')
        super(Around,self).helloworld()        
        print('Exit around around')

class Foo(Around,Before,After,Base):
    def helloworld(self):
        super(Foo,self).helloworld()

foo=Foo()
这是
foo
的MRO()

当你说
super(cls,self).helloworld()
,Python

  • 查看
    self
    的MRO
  • 查找
    cls
  • 调用该类的
    helloworld
    方法
  • 因此:

    屈服

    # Enter around
    # Before
    # Hello World
    # After
    # Exit around around
    

    有关super和MRO的更多信息,请参阅Shalabh Chaturvedi的文章。

    您可以实现类似的功能。Will的思路是正确的,但似乎“调用下一个方法”对于“around”的使用非常关键,可以这样实现:

    def around(callback):
      def decorator(fn):
        return lambda *a, **kw: callback(lambda: fn(*a, **kw))
      return decorator
    
    def hello_before(call_next_method):
      print("I'm executing before the primary-method")
      return call_next_method()
    
    def hello_after(call_next_method):
      value = call_next_method()
      print("I'm executing after the primary-method")
      return value
    
    
    def hello_around(call_next_method):
      print "I'm the most specific around method calling next method."
      value = call_next_method()
      print("I'm the most specific around method done calling next method.")
      return value
    
    
    @around(hello_around)
    @around(hello_after)
    @around(hello_before)
    def helloworld():
      print("Hello world")
    
    helloworld()
    

    这将产生与您完全相同的输出,具有相当相似的结构。只需注意您装饰函数的顺序。

    受原始问题和所有各种草稿的启发,我已经实现了CLOS,比如Abround/before/after辅助方法Python模块

    见:

    我已经使用了一些本地Python特性来实现它:

    • 类和函数装饰器
    • 继承加上
      super()
      内置函数
      >>> fn() around before Hello World! after around >>> fn2() around before Goodbye World! after around
    class Base(object):
        def helloworld(self):
            print('Hello World')
    
    class After(object):
        def helloworld(self):
            super(After,self).helloworld()
            print('After')        
    
    class Before(object):
        def helloworld(self):
            print('Before')        
            super(Before,self).helloworld()
    
    class Around(object):
        def helloworld(self):
            print('Enter around')
            super(Around,self).helloworld()        
            print('Exit around around')
    
    class Foo(Around,Before,After,Base):
        def helloworld(self):
            super(Foo,self).helloworld()
    
    foo=Foo()
    
    print([cls.__name__ for cls in foo.__class__.mro()])
    # ['Foo', 'Around', 'Before', 'After', 'Base', 'object']
    
    foo.helloworld()
    
    # Enter around
    # Before
    # Hello World
    # After
    # Exit around around
    
    def around(callback):
      def decorator(fn):
        return lambda *a, **kw: callback(lambda: fn(*a, **kw))
      return decorator
    
    def hello_before(call_next_method):
      print("I'm executing before the primary-method")
      return call_next_method()
    
    def hello_after(call_next_method):
      value = call_next_method()
      print("I'm executing after the primary-method")
      return value
    
    
    def hello_around(call_next_method):
      print "I'm the most specific around method calling next method."
      value = call_next_method()
      print("I'm the most specific around method done calling next method.")
      return value
    
    
    @around(hello_around)
    @around(hello_after)
    @around(hello_before)
    def helloworld():
      print("Hello world")
    
    helloworld()