在Python中,使用括号和不使用括号调用函数有什么区别?

5

我有一个问题。假设我们有一个函数hello()。用括号和不用括号调用它有什么区别?当我调用hello()时,它是指一个值等于这个函数的对象。或者我错了吗?如果我没有使用括号调用它会发生什么?

我想知道为什么。

def hello():
    pass

print(id(hello))
print(id(hello()))

返回不同的结果

4400606744
4398942536

2
你不能在没有括号的情况下“调用”函数。hello()是一个函数调用,而hello不是。hello只是函数本身,而不是对它的调用。 - Zinki
@ASMackay,我已经更新了我的问题。现在看起来不像是一个重复的问题了,对吧? - user7304253
4
区别在于,第一种情况下你获取的是函数对象本身的 id,而第二种情况下你获取的是函数返回值的 id(这里是 None)。 - deceze
@deceze,你是对的。当我写print(id(None))时,我得到的数字和print(id(hello()))是相同的。 - Hrvoje T
5个回答

4

简短回答:请参考https://nedbatchelder.com/text/names.html,更好地理解对象和用于引用对象的名称之间的区别。


只有使用括号时才会调用函数。 hello() 调用函数;hello只是绑定到函数的名称,并可用于将函数对象作为参数传递给另一个函数。

def caller(f):
    f()

def hello():
    print("hi")

def goodbye():
    print("bye")

caller(hello)  # Prints "hi"
caller(goodbye)  # Prints "bye"

关于您的更新,id返回不同的值,因为每次对id的调用都会接收到一个完全独立的对象作为其参数。使用id(hello)id获得函数本身。使用id(hello())id获取由调用hello返回的对象;这与以下内容相同:
x = hello()
print(id(x))

@Wahtdbogh,Python 中的所有东西都是对象,包括你提到的函数。 - 0decimal0
@Wahtdbogh,这种情况下的括号是一个运算符,就像一元否定运算符一样:hello相当于hello(),就像x相当于-x一样。Hello是存储函数的变量,括号意味着你想尝试将存储在该变量中的对象作为函数调用。 - zstewart
1
是的,hello 是由 def 语句定义的匿名 function 对象的名称。如果您编写了 foo = hello,那么 foo()hello() 都将调用相同的基础函数。同样,如果您编写了 hello = 3,则会失去对该函数的引用;hello 现在指的是整数 3,而 hello() 将产生类型错误,因为 int 对象不可调用。请参见 https://nedbatchelder.com/text/names.html 以更好地理解名称和对象之间的关系。 - chepner
不。hello 指的是一个函数对象;hello() 是一个表达式,通过 调用 函数来进行求值;表达式的值是函数调用的返回值。 - chepner
那么hello()既不是对象,也不是变量,也不是值? - user7304253
显示剩余10条评论

4

简而言之: 括号执行函数本身;没有括号时,你处理的是一个变量而不是一个函数。

在Python中,只有当你想要调用函数时,才会将括号(可带参数)附加到函数名后面。

但是,使用函数名的另一种方法也存在。实际上,在Python中,函数是一等对象,这意味着函数可以像变量名一样传递。为此,您不应在函数名的末尾附加括号 ()。

请查看以下示例:

def f():
    return 'f'

print( type(f) ) # result: <class 'function'>
print( type(f()) ) # result: <class 'str'>

正如您所看到的,在第一个示例中,我们打印了f的类型(不带括号),它是一个函数

在第二个示例中,我们打印了f()的类型(带有括号),它是一个字符串,也就是当调用f时返回的类型。

这种行为对于将函数作为其他函数的参数传递等非常有用。

id()和id(function-invoked>)返回不同的id的事实:

print(id(hello))   # here it returns the id of the function name

print(id(hello())) # here it returns the id 
                   # of the object returned by the function itself

2
简而言之,带有括号()的函数实际上是调用(invoke)该函数,而没有括号()的函数是该函数的对象,可以作为参数传递,并在其后附加()后稍后调用。
最初的回答:带有括号的函数是调用该函数,而没有括号的函数是一个函数对象,可以作为参数传递并稍后通过附加括号进行调用。
def hello():
    return 1

最初的回答是指: 当你输入hello时,它会返回一个对象。 但如果你输入hello()时,它会输出1。

1

hello指的是函数对象,hello()调用函数本身。

例如:

>>> def hello():
...     print "hello"
... 
>>> hello
<function hello at 0x106c91398>
>>> hello()
hello

我假设hello()是一个变量,它引用一个值等于此函数的对象? - user7304253
当你输入hello时,Python会显示函数的表示形式。hello()调用该函数。括号中包含在调用函数时提供给函数的参数。在这个例子中,hello()不需要任何参数。 - The Stupid Engineer
好的,但是当我有一个变量a=2时,变量a指向值等于2的对象。当我打印a时,它返回2。同样,在这种情况下,hello是一个变量,指向值等于函数的对象。因此,当我打印hello时,它应该返回字符串“hello”,而不是这个函数的地址。 - user7304253
当你打印“hello”时,你会看到表达式所在的内存地址。当你调用“hello()”时,你会看到调用函数的输出结果。当你打印“hello”时,你并没有调用该函数。 - The Stupid Engineer

1

函数就像Python中的任何其他对象一样。如果你定义了一个新函数,就会创建一个新的函数对象,并将其分配给该函数的名称。

def spam():
    print('The knights who say Ni!')

print(spam) # => <function spam at 0x7fc64efc6f28>

spam() # => output: 'The knights who say Ni!

如您所见,在定义函数之后,它被赋值给了 spam 的名称。这本质上类似于运行赋值语句。现在该名称将为您提供对该函数的访问权限,但是要实际使用它,您需要使用括号调用它,例如 spam()。如果您不使用括号调用它,它将仅返回已分配给名称 spam 的函数对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接