首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >python的策略模式

python的策略模式
EN

Stack Overflow用户
提问于 2019-06-08 13:44:34
回答 3查看 1.8K关注 0票数 2

我来自C#背景,为了实现策略模式,我们总是使用一个接口,例如: ILoggger。现在,正如我所理解的,在Python这样的鸭子类型语言中,我们可以避免这个基类/契约。

我的问题是,这是利用鸭子类型实现策略模式的最佳方法吗?而且,这种鸭子输入方式是否向代码的下一个用户表明这是一个“扩展点”?另外,我认为最好使用类型提示来帮助下一个人查看您的代码以了解策略的类型,但是对于没有基类/契约的鸭子类型,您使用哪种类型呢?其中一个已经是具体的类?

以下是一些代码:

代码语言:javascript
运行
复制
class FileSystemLogger():
    def log(self, msg):
        pass

class ElasticSearchLogger():
    def log(self, msg):
        pass

# if i wanted to use type hints, which type should logger be here?
class ComponentThatNeedsLogger():
    def __init__(self, logger):
        self._logger = logger

# should it be this?
class ComponentThatNeedsLogger():
    def __init__(self, logger : FileSystemLogger):
        self._logger = logger

请有人建议一下,处理这个问题的最标准的/毕达内式/可读的方法是什么?

我不是在寻找“这里是答案在2行代码”的答案。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-06-08 14:14:42

如果您真的想一直使用类并强制使用基类,那么创建一个ABC:抽象基类/方法并实现它:

属性:用于查找目的的亚历克斯·瓦斯回答

代码语言:javascript
运行
复制
from abc import ABC, abstractmethod

class BaseLogger(ABC):
    """ Base class specifying one abstractmethod log - tbd by subclasses."""
    @abstractmethod
    def log(self, message):
        pass

class ConsoleLogger(BaseLogger):
    """ Console logger implementation."""
    def log(self, message):
        print(message)

class FileLogger(BaseLogger):
    """ Appending FileLogger (date based file names) implementation."""
    def __init__(self):
        import datetime 
        self.fn = datetime.datetime.now().strftime("%Y_%m_%d.log")

    def log(self,message):
        with open(self.fn,"a") as f:
            f.write(f"file: {message}\n")

class NotALogger():
    """ Not a logger implementation."""
    pass

然后使用它们:

代码语言:javascript
运行
复制
# import typing # for other type things

class DoIt:
    def __init__(self, logger: BaseLogger):
        # enforce usage of BaseLogger implementation
        if isinstance(logger, BaseLogger):
            self.logger = logger
        else:
            raise ValueError("logger needs to inherit from " + BaseLogger.__name__)

    def log(self, message):
        # use the assigned logger
        self.logger.log(message)

# provide different logger classes
d1 = DoIt(ConsoleLogger())
d2 = DoIt(FileLogger())

for k in range(5):
    d1.log(str(k))
    d2.log(str(k))

with open(d2.logger.fn) as f:
    print(f.read())

try:
    d3 = DoIt( NotALogger())
except Exception as e:
    print(e)

输出:

代码语言:javascript
运行
复制
0
1
2
3
4 
file: 0
file: 1
file: 2
file: 3
file: 4

logger needs to inherit from BaseLogger

作为一个副词: python已经具有相当复杂的日志记录能力。如果这是你询价的唯一目的,那就调查一下日志记录

票数 4
EN

Stack Overflow用户

发布于 2019-06-08 15:31:01

在Python中,由于运行时安全和优雅的终止,一般不需要具有编译时类型强制执行的全面策略模式。

如果您希望自定义现有代码的某些部分,常见的做法是:

  • 替换适当的方法--无论是子类,还是子类。使用混合赋值(方法和其他对象一样是活动对象的属性,并且可以同样地重新分配;替换甚至可以不是函数,而是__call__对象);。
    • 注意,在Python中,可以动态地创建包含代码(包括函数和类)的对象,方法是将其定义放在函数中。然后在执行封闭函数时计算定义,并且可以使用可访问的变量(也称为闭包)作为临时参数;或

  • 在某个点接受回调(或在适当的时候调用其方法的对象,有效地充当一组回调);或
  • 接受字符串参数,该参数是来自某一组的常量,然后代码在if/else中进行测试,或在某些注册表中查找(无论是全局的,还是类或对象的本地的);
    • 从3.4开始就有了enum,但是对于简单的情况,它被认为有太多的缺点(调试时无法读懂,并且需要样板),因为与C#相比,在灵活性-vs-可伸缩性方面,Python更倾向于灵活性方面。

票数 2
EN

Stack Overflow用户

发布于 2019-06-08 15:38:59

据我所知,在Python中实现策略模式的最常见方法是传递函数(或可调用的函数)。函数是Python中的第一类对象,所以如果使用者所需的都是函数,那么您就不需要给它更多了。当然,如果你想要的话,你可以给它加注释。假设您只想记录字符串:

代码语言:javascript
运行
复制
class ComponentThatNeedsLogger:
    def __init__(self, log_func: Callable[[str], None]):
        self._log_func = log_func

这允许您动态创建一个简单的记录器:

代码语言:javascript
运行
复制
ComponentThatNeedsLogger(
    log_func=print
)

但是,您也可以利用类的所有功能来创建一个复杂的记录器,并只传递相关的方法。

代码语言:javascript
运行
复制
class ComplexLogger:
    def __init__(self, lots_of_dependencies):
        # initialize the logger here

    def log(self, msg: str): None
        # call private methods and the dependencies as you need.

    def _private_method(self, whatever):
        # as many as you need.

ComponentThatNeedsLogger(
    log_func= ComplexLogger(lots_of_dependencies).log
)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56506985

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档