Python getattr可调用函数
我有以下资料:Python getattr可调用函数,python,python-3.x,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() 使用Python3.x如何使用相同的方法评估以下内容 attr = "members.filter(gender='Male')" 要计算到instance.membe
instance = Service.objects.get(pk=1)
attr = "members.all"
t = functools.reduce(getattr, attr.split("."), instance)()
print(t)
它的计算结果为instance.members.all()
使用Python3.x如何使用相同的方法评估以下内容
attr = "members.filter(gender='Male')"
要计算到
instance.members.filter(gender='Male')
这里有一种可能的方法,使用exec()
:
请记住,将exec
与未经验证的输入一起使用可能会很危险,但在某些地方它可能会很有用
编辑–一些附加说明:
- 调用
时,会传递一个字典,该字典提供执行代码的上下文或命名空间。上面我传递了exec
以便代码将在此命名空间中执行:即实例。\uuuu dict\uuuu
存在的命名空间成员
- 如果字符串来自未知源,则在Python中使用
可能是危险的:这意味着您正在执行任意(可能是恶意)代码。这是经常建议不要使用它的一个原因;然而,在某些地方它得到了有效的使用:Python标准库中的NamedTuple实现浮现在脑海中exec
exec()
:
请记住,将exec
与未经验证的输入一起使用可能会很危险,但在某些地方它可能会很有用
编辑–一些附加说明:
- 调用
时,会传递一个字典,该字典提供执行代码的上下文或命名空间。上面我传递了exec
以便代码将在此命名空间中执行:即实例。\uuuu dict\uuuu
存在的命名空间成员
- 如果字符串来自未知源,则在Python中使用
可能是危险的:这意味着您正在执行任意(可能是恶意)代码。这是经常建议不要使用它的一个原因;然而,在某些地方它得到了有效的使用:Python标准库中的NamedTuple实现浮现在脑海中exec
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'}
您应该解析表达式并使用语法树来解决此问题。下面是一个使用示例表达式的不完整示例。您可以扩展它以支持更多语法构造:
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'}
不是没有很大的痛苦。你为什么要这样做?绳子是从哪里来的?可能有更好的方法(换句话说,这是一个)。@DanielRoseman我的用例:当保存任何模型时,我需要一个用户列表,每个模型都有一组不同的用户,可以更改。我过去常常以
查询集的形式传递用户,但现在我使用的是代理,这是在另一台机器上完成的,因此我现在需要每个模型简单地告诉我如何查询数据库以获得他们的用户群。是否有一组有限的查询?您可以考虑在模型上或在Manager上进行一系列方法。我检查每个模型都有<代码>如果GATTARC(实例,NOTIFYY用户,NONE):<代码> > <代码> PASTHOPTION< /COD>函数。如果是这样,我将该模型方法的字符串,即members.all
传递给一个任务。此任务稍后运行。他们需要许多不同的查找,这些查找可以更改。我现在的问题是,一些模型想要限制查询,即members.al(activate=True)
,因此我的任务需要考虑这一点。发送方法名加上参数字典,而不是发送Python代码字符串,似乎更为简洁。这不是没有很多麻烦的。你为什么要这样做?绳子是从哪里来的?可能有更好的方法(换句话说,这是一个)。@DanielRoseman我的用例:当保存任何模型时,我需要一个用户列表,每个模型都有一组不同的用户,可以更改。我过去常常以查询集的形式传递用户,但现在我使用的是代理,这是在另一台机器上完成的,因此我现在需要每个模型简单地告诉我如何查询数据库以获得他们的用户群。是否有一组有限的查询?您可以考虑在模型上或在Manager上进行一系列方法。我检查每个模型都有<代码>如果GATTARC(实例,NOTIFYY用户,NONE):<代码> > <代码> PASTHOPTION< /COD>函数。如果是这样,我将该模型方法的字符串,即members.all
传递给一个任务。此任务稍后运行。他们需要许多不同的查找,这些查找可以更改。我现在的问题是,一些模型想要限制查询,即members.al(activate=True)
,因此我的任务需要考虑这一点。似乎发送一个方法名加上一个参数字典,而不是发送Python代码字符串可能会更干净。有趣的是,在本例中,这为什么会很危险?还有为什么。\uuuuuu dict\uuuuuuuuuu
?有趣的是,在这个例子中,为什么这会很危险?还有为什么。\uuuuu dict\uuuuuu
?对不起,我没有看到evaluate。你是说eval吗?不,evaluate
是我在回答中定义的一个函数。使用eval
(或exec
)是不好的,因为它可以在没有任何控制的情况下执行任意代码,而使用像这样的自定义函数evaluate
,您可以完全控制允许哪些操作以及如何执行它们。好的,很抱歉,我想我必须对你的代码再多了解一点。我对你返回evaluate(expr.value,ref)
感到困惑,即它本身。它是一个递归函数,用于计算ast.parse
返回的表达式树。它基本上从顶部开始,然后在树中级联,开始评估,