在Python it is easy to create new functions programmatically中。如何将此分配给当前范围中以编程方式确定的名称?
这是我想要做的(在非工作代码中):
obj_types = ('cat', 'dog', 'donkey', 'camel')
for obj_type in obj_types:
'create_'+obj_type = lambda id: id
在上面的示例中,将lambda
分配到待确定的函数名称显然不起作用。在实际代码中,函数本身将由函数工厂创建。
背景是懒惰而且不要重复自己:我有十几个对象类型,我将为其分配生成的函数。所以代码目前看起来像:
create_cat = make_creator('cat')
# ...
create_camel = make_creator('camel')
函数create_cat
等在解析器中使用硬编码。
如果我以编程方式将类创建为新类型,types.new_class()
中的{{1}}似乎就是解决方案。
(误)使用这种方法是我最好的选择吗?
答案 0 :(得分:3)
实现您要做的事情(但不创建具有动态名称的函数)的一种方法是使用名称作为键将lamda存储在dict
中。您可以拨打create_cat()
,而不是致电create['cat']()
。这也很好地与解析器逻辑中的硬编码名称相吻合。
答案 1 :(得分:0)
Vaughn Cato指出,人们可以分配到locals()[object_type] = factory(object_type)
。但是the Python docs prohibit this:“注意:不应修改此字典的内容;更改可能不会影响解释器使用的本地和自由变量的值”
d。 Shawley指出,使用dict()
对象哪些条目可以保存函数会更明智。通过在解析器中使用create['cat']()
来访问很简单。虽然这很有说服力,但我不喜欢括号和所需的刻度的语法开销。
J.F。塞巴斯蒂安指向课堂。这就是我最终的结果:
# Omitting code of these classes for clarity
class Entity:
def __init__(file_name, line_number):
# Store location, good for debug, messages, and general indexing
# The following classes are the real objects to be generated by a parser
# Their constructors must consume whatever data is provided by the tokens
# as well as calling super() to forward the file_name,line_number info.
class Cat(Entity): pass
class Camel(Entity): pass
class Parser:
def parse_file(self, fn):
# ...
# Function factory to wrap object constructor calls
def create_factory(obj_type):
def creator(text, line_number, token):
try:
return obj_type(*token,
file_name=fn, line_number=line_number)
except Exception as e:
# For debug of constructor during development
print(e)
return creator
# Helper class, serving as a 'dictionary' of obj construction functions
class create: pass
for obj_type in (Cat, Camel):
setattr(create,
obj_type.__name__.lower(),
create_factory(obj_type))
# Parsing code now can use (again simplified for clarity):
expression = Keyword('cat').setParseAction(create.cat)
这是用于部署pyparsing parser的帮助程序代码。 D. Shawley是正确的,因为dict实际上更容易允许动态生成解析器语法。