Python getattr可调用函数

时间:2015-10-20 16:50:56

标签: python python-3.x

我有以下内容:

instance = Service.objects.get(pk=1)
attr = "members.all"
t = functools.reduce(getattr, attr.split("."), instance)()
print(t)

评估为instance.members.all()

使用Python 3.x如何使用相同的方法评估以下内容?

attr = "members.filter(gender='Male')"

评估为instance.members.filter(gender='Male')

2 个答案:

答案 0 :(得分:4)

您应解析表达式并使用语法树来解决此问题。以下是与示例表达式一起使用的不完整示例。您可以将其展开以支持更多语法结构:

import ast
def evaluate (expr, ref):
    if isinstance(expr, ast.Module):
        return evaluate(expr.body[0], ref)
    elif isinstance(expr, ast.Expr):
        return evaluate(expr.value, ref)
    elif isinstance(expr, ast.Call):
        args = [evaluate(x, ref) for x in expr.args]
        kwargs = {kw.arg: evaluate(kw.value, ref) for kw in expr.keywords}
        return evaluate(expr.func, ref)(*args, **kwargs)
    elif isinstance(expr, ast.Attribute):
        return getattr(evaluate(expr.value, ref), expr.attr)
    elif isinstance(expr, (ast.Str, ast.Num)):
        return ast.literal_eval(expr)

    # special case; look up names on the reference object
    elif isinstance(expr, ast.Name):
        return getattr(ref, expr.id)
    else:
        print('Unknown type', type(expr))

你可以像这样使用它:

expr = "members.filter(gender='Male')"
evaluate(ast.parse(expr), referenceObject)

举个例子,我创建了以下虚拟对象:

>>> def debug (*args, **kwargs):
        print(args, kwargs)

>>> from types import SimpleNamespace
>>> ref = SimpleNamespace()
>>> ref.members = SimpleNamespace()
>>> ref.members.filter = debug
>>> evaluate(ast.parse("members.filter(gender='Male')"), ref)
() {'gender': 'Male'}

答案 1 :(得分:1)

以下是一种可能的方法,使用exec()

class Members():
    def filter(self, gender):
        print("Gender is", gender)

class Foo():
    def __init__(self):
        self.members = Members()

>>> instance = Foo()
>>> exec("members.filter(gender='Male')", instance.__dict__)
Gender is Male

请注意,将exec与未经验证的输入结合使用会很危险,但有些地方可能会有用。

编辑 - 一些额外的解释:

  • 当您调用exec时,您传递一个字典,该字典提供将在其中执行代码的上下文或命名空间。上面我传递instance.__dict__,以便代码将在此命名空间中执行:即members存在的命名空间

  • 如果字符串来自未知来源,则在Python中使用exec会很危险:这意味着您正在执行任意(可能是恶意的)代码。这是经常建议不要使用它的一个原因;但是有些地方可以有效地使用它:想到Python标准库中的NamedTuple实现。