pythonic方法公开用户覆盖钩子
注:虽然我的特殊用途与烧瓶有关,但我认为问题更一般 我正在构建一个由用户定制的Flask web应用程序。例如,用户需要提供DatabaseInterface的一个具体子类,并可以将其添加到应用程序知道如何处理的某些ModelObject的列表中 向用户公开各种钩子并指示必需和可选状态的最佳方式是什么?”这里的“最佳”主要是指最“pythonic”的,或者“python用户最容易掌握的”,但是其他的标准,比如不会引起麻烦,当然值得一提 我考虑过的一些方法:pythonic方法公开用户覆盖钩子,python,flask,Python,Flask,注:虽然我的特殊用途与烧瓶有关,但我认为问题更一般 我正在构建一个由用户定制的Flask web应用程序。例如,用户需要提供DatabaseInterface的一个具体子类,并可以将其添加到应用程序知道如何处理的某些ModelObject的列表中 向用户公开各种钩子并指示必需和可选状态的最佳方式是什么?”这里的“最佳”主要是指最“pythonic”的,或者“python用户最容易掌握的”,但是其他的标准,比如不会引起麻烦,当然值得一提 我考虑过的一些方法: 完全依赖文件 创建一个带有文档覆盖的
- 完全依赖文件
- 创建一个带有文档覆盖的模板文件,就像许多服务器的默认配置文件一样。例如
app = mycode.get_app() ##Add your list of extra foo classes here #app.extra_foos = []
- 为每个钩子创建一个带有attr/方法的UserOverrides类;可能分为所需的覆盖和可选覆盖
- 使用未实现的方法创建空类,用户必须将其子类化为具体实例
- 一种方法是使用。例如,您可以使用抽象方法定义ABC,这些抽象方法必须由以下子类覆盖:
from abc import ABC
class MyClass(ABC): # inherit from ABC
def __init__(self):
pass
@abstractmethod
def some_method(self, args):
# must be overridden by child class
pass
然后,您将实现一个子类,如:
class MyChild(MyClass):
# uses parent's __init__ by default
def some_method(self, args):
# overrides the abstract method
您可以使用文档指定在重写的方法中需要执行的所有操作。还有用于抽象属性、类方法和静态方法的装饰器。尝试实例化未覆盖其所有抽象方法/属性的ABC将导致错误。一个方法是使用。例如,您可以使用抽象方法定义ABC,这些抽象方法必须由以下子类覆盖:
from abc import ABC
class MyClass(ABC): # inherit from ABC
def __init__(self):
pass
@abstractmethod
def some_method(self, args):
# must be overridden by child class
pass
然后,您将实现一个子类,如:
class MyChild(MyClass):
# uses parent's __init__ by default
def some_method(self, args):
# overrides the abstract method
您可以使用文档指定在重写的方法中需要执行的所有操作。还有用于抽象属性、类方法和静态方法的装饰器。试图实例化未覆盖其所有抽象方法/属性的ABC将导致错误。
在Python中尤其如此,这为您提供了一个避免该问题的良好先例。考虑下面的代码:
len({1,2,3}) # set with length 3
len([1,2,3]) # list with length 3
len((1,2,3)) # tuple with length 3
这对于内置的数据结构来说很酷,但是如果您想创建自己的数据结构并让它与Python的len
配合使用,该怎么办?简单:
class Duple(object):
def __init__(self, fst, snd):
super(Duple, self).__init__()
self.fst = fst
self.snd = snd
def __len__():
return 2
Duple
是一种两元素(仅限)数据结构(使用更多或更少的参数调用),现在可用于len
:
len(Duple(1,2)) # 2
这正是你应该做的:
def foo(arg):
return arg.__foo__()
任何想要使用foo
函数的类都只需实现\uuuuuuuuuuuuuuuuuu
魔术方法,这就是len
在引擎盖下的工作方式。
在Python中尤其如此,这为您提供了一个避免该问题的良好先例。考虑下面的代码:
len({1,2,3}) # set with length 3
len([1,2,3]) # list with length 3
len((1,2,3)) # tuple with length 3
这对于内置的数据结构来说很酷,但是如果您想创建自己的数据结构并让它与Python的len
配合使用,该怎么办?简单:
class Duple(object):
def __init__(self, fst, snd):
super(Duple, self).__init__()
self.fst = fst
self.snd = snd
def __len__():
return 2
Duple
是一种两元素(仅限)数据结构(使用更多或更少的参数调用),现在可用于len
:
len(Duple(1,2)) # 2
这正是你应该做的:
def foo(arg):
return arg.__foo__()
任何想要使用
foo
函数的类都只实现了\uuuufoo\uuucode>魔术方法,这就是len
在后台工作的方式。继承是一种蹩脚的扩展机制。使用对其参数调用魔术方法的函数,并让扩展类实现适当的dunder方法。@JaredSmith我恐怕大部分是希腊语。你愿意把它扩展成一个答案吗?因为现在唯一的答案是相反的?完成了。看看我下面的答案。继承是一种糟糕的扩展机制。使用对其参数调用魔术方法的函数,并让扩展类实现适当的dunder方法。@JaredSmith我恐怕大部分是希腊语。你愿意把它扩展成一个答案吗?因为现在唯一的答案是相反的?完成了。查看我下面的答案。2个问题:(1)定义新的双下划线方法不被认为是不可以的吗?(2)我可能遗漏了一些东西,但这似乎只是部分回答了我的问题。我说“传递一个实现这些方法的对象”,而不是告诉我的用户“将这个ABC子类化并传递你的具体实例”。但特别是如果某些方法是允许的默认值,拥有一个可重载的基类似乎比从头创建对象要省工。它并没有回答“我如何才能最好地传达哪些方法是可重载的?”@thegreatemu首先:与什么相比?遗产当互联网上到处都是关于遗产的罪恶的无数和五篇文章时?第二:看到第一个问题的答案,重新思考你的设计。遗传天生脆弱。在您的情况下,您可能可以不受影响(在这种情况下,另一个答案很好),但Python为您提供了其他工具。或者把你的问题转过来:为什么你认为Guido以这种方式实现len
,而不是简单地将其作为这些对象上的一种方法呢?PEP 8明确地说“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu“位于用户控制的命名空间中的对象或属性。例如,“初始化”、
“导入”、“文件”
。永远不要捏造这样的名字;只在文档中使用它们。“@thegreatemu对相关但不重复的问题可能会有所帮助。对于PEP 8,很好,不要使用双下划线。但同样的原则也适用:使用duck类型,而不是继承。2个问题:(1)定义新的双下划线方法不被认为是不可以的吗?(2)我可能遗漏了一些东西,但这似乎只是部分回答了我的问题,而不是告诉我的用户“将这个ABC和pas子类化”