python - 获取虚拟方法引用的惯用方法是什么?
问题描述
我正在使用 Python 为具有多种类型的小块的文件格式构建解析器。虽然我希望我自己的解析就足够了,但我想让客户子类化解析器类以在需要时提供自定义行为。
在 C++ 中,我可以这样写:
enum ChunkTypes {
CHUNK_FOO,
CHUNK_BAR,
CHUNK_BAZ,
};
class Parser {
public:
virtual void parse_foo(size_t offset);
virtual void parse_bar(size_t offset);
virtual void parse_baz(size_t offset);
};
typedef void (Parser::*parse_method[])(size_t);
parse_method methods[] = {
&Parser::parse_foo,
&Parser::parse_bar,
&Parser::parse_baz,
};
Parser& parser = get_parser();
while (has_more_chunks())
{
parse_method method = methods[chunk_type()];
size_t chunk_offset = get_chunk_offset();
(parser.*method)(chunk_offset);
}
因为这对于不写很多 C++ 的人来说可能并不熟悉:parse_method
在这个例子中,它是一个“指向成员”的指针,指向一个Parser
接受size_t
参数的方法。(parser.*method)(chunk_offset)
将方法应用于method
并将参数parser
传递给它chunk_offset
。请注意,这尊重虚拟调度:使用Parser
overridesparse_foo
的子类(parser.*method)(chunk_offset)
(当method
is时parse_foo
),将调用子类的实现。
在 Python 中,我可以这样写:
class Parser:
def parse_foo(self, offset):
# ...
def parse_bar(self, offset):
# ...
def parse_baz(self, offset):
# ...
methods = [
Parser.parse_foo,
Parser.parse_bar,
Parser.parse_baz]
parser = get_parser()
while has_more_chunks():
method = methods[chunk_type()]
offset = get_chunk_offset()
method(parser, offset)
但是,具体来说,是对的实现的Parser.parse_foo
引用。即使我在覆盖它的子类上调用它,所调用的仍然是原始实现。Parser
parse_foo
Parser
有没有办法在 Python 中获得尊重虚拟调度的“方法参考”?我可以制作使用的每个实例表self.parse_foo
,但这似乎很浪费。
解决方案
最接近方法引用的东西基本上只是一个包含方法名称的字符串。您可以使用该名称来查找解析器对象上的方法getattr
,然后调用它:
methods = [
'parse_foo',
'parse_bar',
'parse_baz'
]
parser = get_parser()
while has_more_chunks():
method_name = methods[chunk_type()]
method = getattr(parser, method_name) # get the method
offset = get_chunk_offset()
method(offset) # call the bound method we retrieved earlier
或者,您可以使用调用相应方法的代理函数:
methods = [
lambda parser, offset: parser.parse_foo(offset),
lambda parser, offset: parser.parse_bar(offset),
lambda parser, offset: parser.parse_baz(offset)
]
parser = get_parser()
while has_more_chunks():
method = methods[chunk_type()]
offset = get_chunk_offset()
method(parser, offset)
推荐阅读
- r - 如何更改关于 3 组的列的值
- python-3.x - 使用 PyDictionary 打印出 dictionary.meaning() 输出时遇到问题
- python - 获取用僧伽罗语编写的推文并保存在 csv 文件中
- android - Android Studio AddValueEventListener 不起作用
- java - 如何使用我的代码找到最靠近中间的点(基于询问的点数)
- python - ElementTree 不保留属性顺序
- django - 如何在 django 中为 UserProfile 表单创建测试
- html - 为什么我的视频背景与我的登录框没有响应?
- swift - 如何找出某个 OSX 版本可用的 API 版本?
- amazon-web-services - AWS 声称 RDS 同步复制到备用实例可以防止数据丢失