我来自C#背景,为了实现策略模式,我们总是使用一个接口,例如: ILoggger。现在,正如我所理解的,在Python这样的鸭子类型语言中,我们可以避免这个基类/契约。
我的问题是,这是利用鸭子类型实现策略模式的最佳方法吗?而且,这种鸭子输入方式是否向代码的下一个用户表明这是一个“扩展点”?另外,我认为最好使用类型提示来帮助下一个人查看您的代码以了解策略的类型,但是对于没有基类/契约的鸭子类型,您使用哪种类型呢?其中一个已经是具体的类?
以下是一些代码:
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行代码”的答案。
发布于 2019-06-08 14:14:42
如果您真的想一直使用类并强制使用基类,那么创建一个ABC:抽象基类/方法并实现它:
属性:用于查找目的的亚历克斯·瓦斯回答
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然后使用它们:
# 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)输出:
0
1
2
3
4
file: 0
file: 1
file: 2
file: 3
file: 4
logger needs to inherit from BaseLogger作为一个副词: python已经具有相当复杂的日志记录能力。如果这是你询价的唯一目的,那就调查一下日志记录。
发布于 2019-06-08 15:31:01
在Python中,由于运行时安全和优雅的终止,一般不需要具有编译时类型强制执行的全面策略模式。
如果您希望自定义现有代码的某些部分,常见的做法是:
__call__对象);。
if/else中进行测试,或在某些注册表中查找(无论是全局的,还是类或对象的本地的);enum,但是对于简单的情况,它被认为有太多的缺点(调试时无法读懂,并且需要样板),因为与C#相比,在灵活性-vs-可伸缩性方面,Python更倾向于灵活性方面。
发布于 2019-06-08 15:38:59
据我所知,在Python中实现策略模式的最常见方法是传递函数(或可调用的函数)。函数是Python中的第一类对象,所以如果使用者所需的都是函数,那么您就不需要给它更多了。当然,如果你想要的话,你可以给它加注释。假设您只想记录字符串:
class ComponentThatNeedsLogger:
def __init__(self, log_func: Callable[[str], None]):
self._log_func = log_func这允许您动态创建一个简单的记录器:
ComponentThatNeedsLogger(
log_func=print
)但是,您也可以利用类的所有功能来创建一个复杂的记录器,并只传递相关的方法。
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
)https://stackoverflow.com/questions/56506985
复制相似问题