调用print语句中函数的Python顺序?
假设我有调用print语句中函数的Python顺序?,python,Python,假设我有 def foo(n): print("foo",n) def bar(n): print("bar",n) print("Hello",foo(1),bar(1)) 我预计产出为: Hello foo 1 None bar 1 None 但相反,我得到了令我惊讶的东西: foo 1 bar 1 Hello None None 为什么Python在打印“Hello”之前首先调用函数?打印“Hello”,然后调用foo(1),让它打印输出,然后打印“None”作为
def foo(n):
print("foo",n)
def bar(n):
print("bar",n)
print("Hello",foo(1),bar(1))
我预计产出为:
Hello
foo 1 None
bar 1 None
但相反,我得到了令我惊讶的东西:
foo 1
bar 1
Hello None None
为什么Python在打印“Hello”之前首先调用函数?打印“Hello”,然后调用foo(1)
,让它打印输出,然后打印“None”作为返回类型似乎更有意义。然后调用bar(1)
并打印输出,并将“None”作为返回类型打印。Python(或者其他语言)以这种方式调用函数,而不是按照每个参数出现的顺序执行它们,这有什么原因吗
编辑:现在,我接下来的问题是,如果Python从左到右计算表达式,它会以某种方式临时存储每个参数的返回值,那么Python内部会发生什么情况?例如,现在我知道它将从左到右计算每个表达式,但最后一行是Hello None
,因此Python在执行每个函数时是否会记住第二个参数和第三个参数的返回值为None
?例如,当计算foo()
时,它将打印foo1
,然后点击no return语句,那么是否将foo
未返回值的值存储在内存中?答案很简单:
在python中,像print
这样的函数的参数总是首先从左到右求值
看看这个问题:
而
None
只是函数的返回值。它首先执行函数,然后打印其返回值,直到对其所有参数求值后才调用封闭函数。这与数学的基本规则是一致的,即括号内的运算先于括号外的运算。因此,print()
总是发生在foo()
和bar()
引用以下内容之后:
Python从左到右对表达式求值。请注意,求值赋值时,先求值右侧,再求值左侧
我的。因此,首先计算所有表达式,然后将其传递给print
请注意打印调用的字节码:
1 0 LOAD_NAME 0 (print)
3 LOAD_CONST 0 ('Hello')
6 LOAD_NAME 1 (foo)
9 LOAD_CONST 1 (1)
12 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
15 LOAD_NAME 2 (bar)
18 LOAD_CONST 1 (1)
21 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
24 CALL_FUNCTION 3 (3 positional, 0 keyword pair)
27 RETURN_VALUE
首先调用foo
(LINE 12
)和bar
(LINE 21
),然后调用print
(LINE 24
-3个位置参数)
至于这些中间计算值存储在何处的问题,这将是最重要的print
只需将返回值从堆栈中弹出即可访问它们 如中所述:
Python从左到右计算表达式。请注意,在计算赋值时,右侧的求值先于左侧
因此,这意味着如果你写:
print("Hello",foo(1),bar(1))
这相当于:
arg1 = "Hello"
arg2 = foo(1)
arg3 = bar(1)
print(arg1,arg2,arg3)
arg11 = foo('a')
arg12 = foo('b')
arg1 = foo(arg11,arg12)
arg21 = foo('c')
arg22 = foo('d')
arg2 = foo(arg11,arg12)
print(arg1,arg2)
因此,参数在函数调用之前进行计算
例如,当我们有一棵树时,也会发生这种情况:
def foo(*x):
print(x)
return x
print(foo(foo('a'),foo('b')),foo(foo('c'),foo('d')))
此文件打印为:
>>> print(foo(foo('a'),foo('b')),foo(foo('c'),foo('d')))
('a',)
('b',)
(('a',), ('b',))
('c',)
('d',)
(('c',), ('d',))
(('a',), ('b',)) (('c',), ('d',))
因为Python从左到右计算参数。它将首先评估foo(foo('a')、foo('b'))
,但为了评估foo(foo('a')、foo('b'))
,它首先需要评估foo('a')
,然后是foo('b')
。然后它可以使用前面调用的结果将所有的foo(foo('a')、foo('b'))
然后它想计算第二个参数foo(foo('c')、foo('d'))
。但为了做到这一点,它首先计算foo('c')
和foo('d')
。接下来它可以计算foo(foo('c')、foo('d'))
,最后它可以计算最终表达式:print(foo(foo('a')、foo('b'))、foo(foo('c')、foo('d'))
因此,评估相当于:
arg1 = "Hello"
arg2 = foo(1)
arg3 = bar(1)
print(arg1,arg2,arg3)
arg11 = foo('a')
arg12 = foo('b')
arg1 = foo(arg11,arg12)
arg21 = foo('c')
arg22 = foo('d')
arg2 = foo(arg11,arg12)
print(arg1,arg2)
参数总是先从左到右求值…我已经稍微修剪了dupe目标列表。大多数目标讨论的是相对于其他论点的论点评估顺序;其中只有一个讨论了参数的计算顺序与参数传递到的函数的执行有关,这就是这个问题的内容。@user2357112谢谢。我编辑了我的问题,因为还有一部分我不太清楚它是如何工作的。@rb612我的问题回答了这个问题。字节码将帮助您理解。中间值被计算、存储,然后最终传递给函数。此外,默认情况下,不返回值的函数实际上返回
None
。这是有意义的,因此None
的返回值只是存储在foo
和bar
的某个位置,直到调用print
语句为止?分别在执行foo
和bar
之后立即显示None
似乎是有意义的。在数学或Python中,括号内的操作并不总是在括号外的操作之前执行。虽然在早期的数学课上,将优先级作为“操作顺序”进行教学是很常见的,即使在数学课上也是如此,但这只是一种参数分组约定。@rb612:由于print()
还没有被调用,所以什么都不能“出现”。谢谢,这非常有帮助。我对我的问题进行了后续编辑。这太棒了!非常感谢。奇怪的是,字节码中是否有一部分显示Python正在存储foo
和bar
的返回值?@rb612ah。好问题。字节码不太可能显示这一点,因为它是一个实现细节。您可以看到它被传递了(3个位置,0个关键字对)
,所以您知道它必须存储在某个地方。@cᴏʟᴅsᴘᴇᴇᴅ “所以你知道它必须被储存在某个地方。”-是的。明确地在给出的示例中,print
只需将返回值从堆栈中弹出即可访问它们。@cᴏʟᴅsᴘ?