将表达式传递给函数
在SQLAlchemy中,有时候我需要把一个表达式传给filter()
。当我尝试自己实现这样的功能时,结果却是:
>>> def someFunc(value):
... print(value)
>>> someFunc(5 == 5)
True
我该如何从函数内部获取传给==
的值呢?
我想实现的效果大概是这样的:
>>> def magic(left, op, right):
... print(left + " " + op + " " + right)
>>> magic(5 == 5)
5 == 5
如果其中一个参数是一个对象,那该怎么办呢?
7 个回答
3
你不能这样做。表达式 5 == 5
会先被计算,然后结果才会传给 someFunc 函数。这个函数只会得到 True
(准确来说,是 True
对象),无论最开始的表达式是什么。
补充说明:关于你的修改,这个问题 有点相关。
补充说明 2:你可以把表达式当作字符串传递,然后使用 eval,像这样:
>>> def someFunc(expression_string):
... print(expression_string, "evaluates to", eval(expression_string))
>>> someFunc("5 == 5")
5 == 5 evaluates to True
不知道这是否对你有帮助。要记住,eval
是一个强大的工具,所以把任意(甚至可能是用户输入的)内容传给它是有风险的。
10
一种更符合Python风格的做法是使用标准库中的operator模块里的操作符函数,这样就不需要自己去写那些小函数(也就是lambda函数)了。
>>> from operator import eq
>>> def magic(left, op, right):
... return op(left, right)
...
>>> magic(5, eq, 5)
True
37
如果你把“op”变成一个函数,就可以实现你的例子:
>>> def magic(left, op, right):
... return op(left, right)
...
>>> magic(5, (lambda a, b: a == b), 5)
True
>>> magic(5, (lambda a, b: a == b), 4)
False
这样做比传一个字符串更符合Python的风格。这也是像 sort()
这样的函数的工作方式。
那些关于SQLAlchemy的例子,使用 filter()
的地方让我有点困惑。我对SQLAlchemy的内部工作原理不太了解,但我猜在像 query.filter(User.name == 'ed')
这样的例子中,发生的事情是 User.name
是一种特定于SQLAlchemy的类型,它的 __eq()
函数实现得有点奇怪,生成SQL代码给 filter()
函数,而不是直接进行比较。也就是说,他们创建了特殊的类,让你可以输入Python表达式,然后输出SQL代码。这是一种不太常见的技术,除非你在构建一个连接两种语言的东西,比如ORM,否则我会避免使用这种方式。