2015-10-20 44 views
0

我有以下几点:Python的GETATTR调用函数

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')

+0

不没有很大的痛苦。你为什么想这样做?字符串从哪里来?这可能是更好的方法(换句话说,这是一个[XY问题](http://xyproblem.info/))。 –

+0

@DanielRoseman我的用例:保存任何模型时,我需要一个用户列表,每个模型都有一组不同的用户可以更改。我曾经将用户作为“queryset”传递给用户,但是现在我正在使用代理,这是在另一台机器上完成的,因此我现在需要每个模型来简单告诉我如何查询数据库以获取其用户基础。 – MrKnotts

+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'} 
+0

对不起,我还没有看到评价是否意味着评价? – MrKnotts

+1

不,“评估”是我在答案中定义的一个函数。使用'eval'(或'exec')是不好的,因为它可以在没有任何控制的情况下执行任意代码,而通过像'evaluate'这样的自定义函数,您可以完全控制您允许的操作以及如何执行它们。 – poke

+0

好吧,对不起,我认为我必须把你的代码包裹一下,让我感到困惑,因为你返回''evaluate(expr.value,ref)''即它本身。 – MrKnotts

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实现让人想起。

+0

有趣的是,在这个例子中,为什么这会很危险?也为什么''.__ dict__''? – MrKnotts