如何以编程方式将新函数添加到Python中的当前作用域?

时间:2013-04-24 13:46:49

标签: python function dynamic python-3.x scope

在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}}似乎就是解决方案。 (误)使用这种方法是我最好的选择吗?

2 个答案:

答案 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实际上更容易允许动态生成解析器语法。