Python-传函数本身”还是“传函数调用(函数())
在 Python 中,“传函数本身”还是“传函数调用(函数())”,核心取决于 “接收方需要的是‘函数这个工具’,还是‘函数运行后的结果’”。我们用 2 个典型场景+对比例子,把这个逻辑讲透:
场景1:需要“重复使用函数”时,传「函数本身」
当接收方需要“自己决定什么时候执行函数”“多次执行函数”,或者“需要函数的元信息(如函数名、参数)”时,就传函数本身(不加括号)。
本质是:把“函数”当成一个“工具”传递,让接收方按需使用。
例子1:多线程/多进程的任务调度(最常见场景)
多线程的 threading.Thread(target=...) 需要的是“一个待执行的任务函数”,它会在新线程中自己调用这个函数(帮你加括号)。如果提前传 函数(),会导致“函数在主线程提前执行,新线程拿到的是执行结果”,完全不符合需求。
import threading
import time
# 定义一个任务函数:打印消息(需要被多线程调用)
def print_msg(msg):
time.sleep(1)
print(f"线程任务结果:{msg}")
# 正确:传「函数本身」(print_msg),让线程自己调用
# threading.Thread 会在新线程中执行 print_msg("hello")
t1 = threading.Thread(target=print_msg, args=("hello",)) # args 是传给函数的参数
t1.start() # 新线程启动后,会自动执行 print_msg("hello")
# 错误:传「函数调用(print_msg("world"))」
# 此时函数会在主线程提前执行(立刻打印“线程任务结果:world”),
# 线程拿到的是函数的返回值(None),新线程啥也不做
t2 = threading.Thread(target=print_msg("world"), args=())
t2.start()
执行结果:
先打印“线程任务结果:world”(主线程提前执行),1秒后打印“线程任务结果:hello”(新线程执行)——显然错误写法不符合多线程需求。
例子2:列表排序的自定义规则(key=函数本身)
list.sort(key=...) 需要的是“一个函数”,用于对列表中的每个元素做“预处理”(比如按元素长度排序)。如果传 函数(),会导致“函数提前执行,key 拿到的是执行结果,而非函数”,排序逻辑失效。
# 定义一个函数:返回字符串的长度(用于排序规则)
def get_str_length(s):
return len(s)
# 待排序的列表
words = ["apple", "banana", "cherry", "date"]
# 正确:传「函数本身(get_str_length)」
# sort 会自动对每个元素调用 get_str_length(元素),按返回的长度排序
words.sort(key=get_str_length)
print("正确排序(按长度):", words) # 输出:['date', 'apple', 'banana', 'cherry']
# 错误:传「函数调用(get_str_length("test"))」
# 此时函数提前执行,返回 4("test" 的长度),key=4 是整数,不是函数,直接报错
try:
words.sort(key=get_str_length("test"))
except TypeError as e:
print("错误原因:", e) # 输出:sort() argument 1 must be function, not int
场景2:需要“函数的执行结果”时,传「函数调用(函数())」
当接收方需要的是“函数运行后产生的数据”(比如计算结果、生成的对象),而不是“函数本身”时,就传函数调用(加括号)。
本质是:先让函数“干活”,把“干活的结果”交给接收方。
例子1:异步任务执行(asyncio.run(协程对象))
这就是你之前遇到的场景:asyncio.run() 需要的是“协程对象”(异步函数调用后的结果),而不是“异步函数本身”。因为它要执行的是“函数运行后的异步任务”,而非“拿着函数对象不动”。
import asyncio
# 定义异步函数
async def async_print():
await asyncio.sleep(1)
print("异步任务执行完成")
# 正确:传「函数调用(async_print())」→ 得到协程对象
# asyncio.run 会执行这个协程对象对应的异步任务
asyncio.run(async_print()) # 1秒后打印“异步任务执行完成”
# 错误:传「函数本身(async_print)」→ 得到函数对象,不是协程对象
try:
asyncio.run(async_print)
except ValueError as e:
print("错误原因:", e) # 输出:a coroutine was expected, got <function async_print at ...>
例子2:计算结果作为参数传递
比如你需要把“计算两数之和的结果”传给 print 函数,就必须传 add(1,2)(函数调用,得到结果 3),而不是 add(函数本身,print 会打印函数的内存地址,毫无意义)。
# 定义计算函数
def add(a, b):
return a + b
# 正确:传「函数调用(add(1,2))」→ 得到结果 3,print 打印 3
print("1+2的结果:", add(1,2)) # 输出:1+2的结果:3
# 错误:传「函数本身(add)」→ 得到函数对象,print 打印函数的内存地址
print("传函数本身的结果:", add) # 输出:传函数本身的结果:<function add at 0x000001CECF2CB380>
总结:核心判断法则
| 传「函数本身」(不加括号) | 传「函数调用(函数())」(加括号) |
|---|---|
| 接收方需要“用这个函数干活”(比如线程执行、排序规则) | 接收方需要“函数干活后的结果”(比如协程对象、计算结果) |
| 函数会在接收方内部被调用(接收方帮你加括号) | 函数在传递前已经被调用(你自己加括号) |
| 典型场景:多线程 target、sort key、回调函数 | 典型场景:asyncio.run、参数传递、结果打印 |
简单记:要“工具”传函数本身,要“结果”传函数调用。
更多推荐



所有评论(0)