有什么措施可以将Python代码称为基于策略的设计? [英] What are the measures to call a Python code a policy-based design?

查看:79
本文介绍了有什么措施可以将Python代码称为基于策略的设计?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道我显示的代码是否可以视为Python中基于策略的设计的示例.另外,我想知道您是否曾经使用此示例查看过python模块,以便向他们学习?

I wonder if the code I am showing can be considered as an example of policy-based design in Python. Also, I would like to know if have you seen python modules using something like this example so I can learn from them?

我在帖子中撰写了有关此方法的更多详细信息和示例.

最近我需要类似基于策略的设计我正在使用的python模块.

Recently I needed something like policy-based design for a python module I was working on.

我在该论坛中发现了一个类似的问题,但该论坛已关闭,并且我无法添加评论.

I found a similar question in this forum, but it was closed, and I was not able to add a comment.

让我总结一下我在Python中对这种方法的期望.

Let me give a summary of what I expect from this approach in Python.

  • 模块类分为策略类和主机类.
  • 策略类通过继承对主机类的行为或接口进行修改.
  • 用户通过提供一组策略类来实例化宿主类中的新类.

这是我的玩具示例:

class PrintOutput:
    """Implement print output policy."""
    def _output(self, message):
        print(message)

class SaveOutput:
    """Implement save output policy."""
    def set_filename(self, filename):
        self.filename = filename
    def _output(self, message):
        with open(self.filename, 'w') as file:
            file.write(message)

def HelloWorld(Output=PrintOutput):
    """Creates a host class."""
    class _(Output):
        """Implements class affected by the policy."""
        def run(self):
            """Print message."""
            self._output('Hello world!')
    return _

PrintHelloWorld = HelloWorld()
hw = PrintHelloWorld()
hw.run() # print "Hello World!"

SaveHelloWorld = HelloWorld(
    Output=SaveOutput
)
hw = SaveHelloWorld()
hw.set_filename('output.txt')
hw.run() # save "Hello World!" in output.txt

在示例中,我希望所有类都已在模块中定义.用户只需使用适合其要求的输出策略实例化 HelloWorld 类.

In the example, I expect that all the classes are already defined in a module. The user only needs to instantiate the HelloWorld class with the output policy that fits his or her requirements.

基本设计要素是

  • 多重继承:C ++和Python中都存在.

  • Multiple inheritances: that exists in both C++ and Python.

推迟继承:将主机和策略类之间的继承的定义推迟到主机类的用户实例化

Postpone inheritance: postponing the definition of the inheritance between host and policy classes until user instantiation of the host class

// in C++ using templates
template<typename Policy1, typename Policy2, ...>
class HostClass: public Policy1, public Policy2, ... {
    // Implement host class.
};

# in Python with a factory with arguments
def HostClass(Policy1, Policy2=Default2, ...):
    class _(Policy1, Policy2, ...):
        """Implements class affected by the policies."""
    return _

  • 类实例化
  • // in C++
    typedef HostClass<Policy1Class, Policy2Class, ...> NewClass;
    

    # in Python
    NewClass = HostClass(Policy1Class, Policy2Class, ...)
    

    使用mixins作为替代

    我刚刚从评论中获悉,可以使用 Python mixins 作为创建新类的替代方法.在这种方法下,模块的代码分为基础类和混合类.然后,您可以从基类中创建新类,并使用mixin类对基类提供的行为或接口进行修改.

    Using mixins as alternative

    I just learned from one of the comments, that it is possible to use Python mixins as an alternative approach to creating new classes. Under this approach module's code is divided between based and mixin classes. You can then create new classes from the base classes, and using mixin classes to implement modifications to the behavior or interface provided by the base classes.

    遵循此 answer ,我能够用mixins编写我的第一个示例.

    Following this answer, I was able to write my first example using mixins.

    class PrintOutput:
        """Implement print output mixin."""
        def _output(self, message):
            print(message)
    
    class SaveOutput:
        """Implement save output mixin."""
        def set_filename(self, filename):
            self.filename = filename
        def _output(self, message):
            with open(self.filename, 'w') as file:
                file.write(message)
    
    class HelloWorld:
        """Creates a host class."""
        def run(self):
            """Print message."""
            self._output('Hello world!')
    
    class PrintHelloWorld(PrintOutput, HelloWorld):
        pass
    
    hw = PrintHelloWorld()
    hw.run() # print "Hello World!"
    
    class SaveHelloWorld(SaveOutput, HelloWorld):
        pass
    
    hw = SaveHelloWorld()
    hw.set_filename('output.txt')
    hw.run() # save "Hello World!" in output.txt
    

    方法之间的区别

    mixin和我之前的示例之间的主要区别是类之间的继承层次结构. mixin或基类都不能推断哪个是mixin或基类.这是因为他们都是新班级的父母,例如 PrintHelloWorld SaveHelloWorld .

    在我尝试进行基于策略的设计时,主机类总是有可能知道哪些类是其策略,因为它们是其父级.此功能使我可以利用Python的方法解析顺序(MRO)在主机和策略类之间创建组合.这些组合是使用实例化的宿主类作为策略来实例化另一个宿主类的结果,请参见下面的示例.

    In my attempt to do a policy-based design, it is always possible for a host class to know which classes are their policy because they are its parents. This feature allows me to exploit the Python's Method Resolution Order (MRO) to create compositions between host and policy classes. These compositions are the result of using instantiated host classes as a policy to instantiate another host class, see the example below.

    class InputMessage:
        """Generate the message."""
        def run(self):
            return 'hello world'
    
    def AddPrefix(Input):
        """Add a prefix."""
        class _(Input):
            def set_prefix(self, prefix):
                self._prefix = prefix
            def run(self):
                return self._prefix + super().run()
        return _
    
    def AddSuffix(Input):
        """Add a suffix."""
        class _(Input):
            def set_suffix(self, suffix):
                self._suffix = suffix
            def run(self):
                return super().run() + self._suffix
        return _
    
    def PrintOutput(Input):
        """Print message."""
        class _(Input):
            def run(self):
                print(super().run())
        return _
    
    PrintPrefixSuffixMessage = PrintOutput(
        AddSuffix(AddPrefix(InputMessage))
    )
    message = PrintPrefixSuffixMessage()
    message.set_prefix('Victor says: ')
    message.set_suffix(' and goodbye!')
    message.run()
    

    我不确定这两种方法之间的区别是否有实际意义.目前,我只是想学习可以用它们表达什么.

    I am not sure if this difference has any practical implications between these two approaches. At the moment I am just trying to learn what can be expressed with them.

    我想指出,可以将递归添加到组合中.这使人想起了C ++中使用的一些元编程技术,这些技术在编译时启用了计算.原则上,这在解释语言的Python中没有应用程序. 请耐心等待下一个不切实际的例子.

    I would like to point out that it is possible to add recursion to the mix. This is reminiscent of some metaprogramming techniques used in C++ that enable computation at compile-time. This has in principle no application in Python that is an interpreted language. Please bear with me for a moment the next impractical example below.

    class Identity:
        def run(self, z):
            return z
    
    def MandelbrotSeq(Base, n):
        def Mandelbrot(Base, n):
            if n == 0:
                return Base
            class _(Base):
                def run(self, z):
                    z = super().run(z)
                    return z**2 + self.c
            return Mandelbrot(_, n-1)
        return Mandelbrot(Base, n).__mro__
    
    M = MandelbrotSeq(Identity, 5)
    
    m = M[0]()
    m.c = 1
    # print 677 the value at 5th iteration for c=1
    print(m.run(0))
    
    m = M[1]()
    m.c = 1
    # print 26 the value at 4th iteration for c=1
    print(m.run(0))
    
    m = M[2]()
    m.c = 1
    # print 5 the value at 3th iteration for c=1
    print(m.run(0))
    

    工厂 MandelbrotSeq 递归映射 Mandelbrot序列作为层次结构连接的类的列表. M 的第一个元素是 Identity 类的第五代后代.这意味着调用 M [0]实例的 run(.)成员函数将返回序列的第5个值.同样,我调用 M [1]实例的 run(.)成员函数将返回序列的第4个值.

    The factory MandelbrotSeq maps recursively the Mandelbrot sequence as a list of hierarchically connected classes. The first element of M refers to the fifth-generation descendant of the Identity class. This means a call to the run(.) member function of an instance of M[0] will return the 5th value of the sequence. In the same way, I call to run(.) member function of an instance of M[1] will return the 4th value of the sequence.

    这只是如上一节所述的如何利用Python MRO的极端示例.它只是一个玩具示例,我无法提出比分形等更好的主意,只是因为涉及到递归.请不要在家中这样做!

    This is just an extreme example of how to exploit the Python MRO as shown in the earlier section. It is only a toy example, and I was not able to come up with a better idea than something like a fractal just because a recursion was involved. Please do not do this at home!

    推荐答案

    答案是根据我的研究结果和StackOverflow的一些评论得出的结果.

    The answer is the product of what I learn based on my research and some comments from StackOverflow.

    我写了一篇关于这些方法的详细博客,称为

    I wrote a detail blog about these approaches called Mixin and policy-based design in python. In that post, I also discuss several extensions like implementations using decorators, adding default classes with mixins, and more ...

    设计一个Python模块,以便用户可以通过从一组预定义的类继承而创建具有新行为和接口的类.这种方法根据用户可以将其组合为新类的所有可能方式,为用户提供了大量可用的类.

    Design a Python module such users can create classes with new behavior and interfaces by inheriting from a predefined set of classes. This approach provides a large number of classes available to the users based on all possible ways they can be combined into new ones.

    可以使用混合和基于策略的实现来实现此要求.

    This requirement can be implemented using mixin and policy-based implementations.

    Mixin的实现定义如下:

    Mixin implementation is defined as follow:

    • 模块类在mixin和基类之间划分.
    • Mixin类对基类的行为或接口进行了修改.
    • 用户通过继承将一个或多个mixin与基类组合在一起来创建新类.
    class Mixin1Class:
        """Implementation of some Mixin1 class."""
    class Mixin2Class:
        """Implementation of some Mixin2 class."""
    ...
    class BasedClass:
        """Implementation of based class."""
    
    # End user creating new class
    class NewClass(Mixin1Class, [Mixin2Class, ...], BasedClass):
        pass
    

    参考:

    • Wikipedia: Mixin.
    • StackOverflow answer about mixin.

    基于策略的实现定义如下:

    Policy-based implementation is defined as follow:

    • 模块类分为策略类和主机类.
    • 策略类对主机的行为或接口进行修改.
    • 主机类是通过类工厂定义的,即返回类型对象的函数.
    • 用户使用类工厂调用新类的创建.
    • 策略类作为参数传递给类工厂.
    • 对于类工厂,将以所有策略类作为其父级来创建宿主类.
    • Module classes are divided between policy and host classes.
    • Policy classes implement modifications to the behavior or interface of the host.
    • Host classes are defined withing class factories i.e., a function that returns type objects.
    • Users invoke the creation of new class using class factories.
    • Policy classes are passed as arguments to the class factory.
    • Withing the class factory, the host class is created with all the policy classes as its parents.
    class Policy1Class:
        """Implementation of some Policy1 class."""
    class Policy2Class:
        """Implementation of some Policy2 class."""
    ...
    def HostClassFactory(Policy1, Policy2=Policy2Class, ...):
        """Create a HostClass and return it."""
        class HostClass(Policy1, Policy2, ...):
            """Concrete implementation of the host class."""
        return HostClass
    
    # End user invoking new class
    NewClass = HostClassFactory(Policy1Class, [Policy2Class,...])
    

    参考:

    • Wikipedia: Modern C++ Design, Policy-based design.
    • My question in stackoverflow.
    • My technical blog: Policy-based design in python

    以下是方法之间的区别的列表:

    Here a list of the differences between approaches:

    • 类之间的关系不同,这会影响Python的方法解析顺序"或MRO,请参见下图.
    • 在用户创建新类时定义或实例化mixin的基类.
    • 但是,基于策略的主机类定义会延迟到用户调用工厂函数之前.
    • 可以提供默认策略类,但不能混合使用默认类.

    这篇关于有什么措施可以将Python代码称为基于策略的设计?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆