将表达式传递给函数

24 投票
7 回答
17366 浏览
提问于 2025-04-15 13:10

在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,否则我会避免使用这种方式。

撰写回答