大家好,我是正在实战各种 AI 项目的程序员晚枫。
🎬 开篇:让类的实例像函数一样调用 你有没有想过,为什么这样写是合法的?
1 2 3 4 5 6 7 8 9 10 11 12 class Counter : def __init__ (self ): self.count = 0 def __call__ (self ): self.count += 1 return self.count counter = Counter() print (counter()) print (counter()) print (counter())
这就是 __call__ 方法 的魔力:让对象实例可以像函数一样被调用。
今天我们就深入理解 Python 的可调用对象,以及它如何让设计模式更优雅。
🎯 什么是可调用对象? callable() 函数 Python 提供了 callable() 函数来判断一个对象是否可调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 print (callable (int )) print (callable (str )) print (callable (len )) print (callable ('hello' )) print (callable ([1 , 2 , 3 ])) def my_func (): pass class MyClass : pass class CallableClass : def __call__ (self ): pass print (callable (my_func)) print (callable (MyClass)) print (callable (MyClass())) print (callable (CallableClass()))
Python 中有哪些可调用对象? 类型 示例 说明 函数 def func(): pass普通函数 内置函数 len, printPython 内置 方法 obj.method绑定方法 类 int, str, MyClass调用创建实例 类型 list[int]Python 3.9+ 泛型 生成器函数 def gen(): yield返回生成器 协程函数 async def coro(): pass返回协程 实现了 __call__ 的实例 CallableClass()自定义可调用对象
🔧 call 方法详解 基础语法 1 2 3 4 5 6 7 8 9 10 class CallableObject : def __call__ (self, *args, **kwargs ): """定义实例被调用时的行为""" print (f"被调用,参数: args={args} , kwargs={kwargs} " ) return "result" obj = CallableObject() result = obj(1 , 2 , name="Alice" ) print (result)
实际应用场景 1. 带状态的函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Counter : """计数器 - 保存状态的函数""" def __init__ (self, start=0 ): self.count = start def __call__ (self, step=1 ): self.count += step return self.count def reset (self ): self.count = 0 counter = Counter(10 ) print (counter()) print (counter()) print (counter(5 )) counter.reset() print (counter())
2. 可配置的函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Formatter : """可配置的格式化器""" def __init__ (self, prefix="" , suffix="" , uppercase=False ): self.prefix = prefix self.suffix = suffix self.uppercase = uppercase def __call__ (self, text ): result = f"{self.prefix} {text} {self.suffix} " if self.uppercase: result = result.upper() return result quote = Formatter('"' , '"' ) shout = Formatter(suffix="!" , uppercase=True ) code = Formatter("`" , "`" ) print (quote("Hello" )) print (shout("hello" )) print (code("print" ))
3. 缓存/记忆化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Memoize : """记忆化装饰器(类实现)""" def __init__ (self, func ): self.func = func self.cache = {} def __call__ (self, *args ): if args in self.cache: print (f"缓存命中: {args} " ) return self.cache[args] result = self.func(*args) self.cache[args] = result return result @Memoize def fibonacci (n ): if n < 2 : return n return fibonacci(n-1 ) + fibonacci(n-2 ) print (fibonacci(10 ))print (fibonacci(10 ))
4. 验证器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Validator : """可配置的验证器""" def __init__ (self, min_val=None , max_val=None , min_length=None , max_length=None , required_type=None ): self.min_val = min_val self.max_val = max_val self.min_length = min_length self.max_length = max_length self.required_type = required_type def __call__ (self, value ): errors = [] if self.required_type and not isinstance (value, self.required_type): errors.append(f"类型错误: 期望 {self.required_type} , 实际 {type (value)} " ) if self.min_val is not None and value < self.min_val: errors.append(f"值过小: 最小 {self.min_val} , 实际 {value} " ) if self.max_val is not None and value > self.max_val: errors.append(f"值过大: 最大 {self.max_val} , 实际 {value} " ) if self.min_length is not None and len (value) < self.min_length: errors.append(f"长度过短: 最小 {self.min_length} , 实际 {len (value)} " ) if self.max_length is not None and len (value) > self.max_length: errors.append(f"长度过长: 最大 {self.max_length} , 实际 {len (value)} " ) return len (errors) == 0 , errors age_validator = Validator(min_val=0 , max_val=150 , required_type=int ) password_validator = Validator(min_length=8 , max_length=32 ) print (age_validator(25 )) print (age_validator(-5 )) print (password_validator("abc" ))
🎨 设计模式实现 策略模式 策略模式 定义了一系列算法,让它们可以互换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 from abc import ABC, abstractmethodfrom typing import List class SortStrategy (ABC ): @abstractmethod def sort (self, data: List [int ] ) -> List [int ]: pass class BubbleSort (SortStrategy ): def sort (self, data: List [int ] ) -> List [int ]: arr = data.copy() n = len (arr) for i in range (n): for j in range (0 , n-i-1 ): if arr[j] > arr[j+1 ]: arr[j], arr[j+1 ] = arr[j+1 ], arr[j] return arr class QuickSort (SortStrategy ): def sort (self, data: List [int ] ) -> List [int ]: if len (data) <= 1 : return data pivot = data[len (data) // 2 ] left = [x for x in data if x < pivot] middle = [x for x in data if x == pivot] right = [x for x in data if x > pivot] return self.sort(left) + middle + self.sort(right) class PythonSort (SortStrategy ): def sort (self, data: List [int ] ) -> List [int ]: return sorted (data) class Sorter : def __init__ (self, strategy: SortStrategy ): self.strategy = strategy def set_strategy (self, strategy: SortStrategy ): self.strategy = strategy def sort (self, data: List [int ] ) -> List [int ]: return self.strategy.sort(data) data = [64 , 34 , 25 , 12 , 22 , 11 , 90 ] sorter = Sorter(BubbleSort()) print ("冒泡排序:" , sorter.sort(data))sorter.set_strategy(QuickSort()) print ("快速排序:" , sorter.sort(data))sorter.set_strategy(PythonSort()) print ("内置排序:" , sorter.sort(data))
命令模式 命令模式 将请求封装为对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 from typing import Callable , List import timeclass Command : """命令接口""" def execute (self ): raise NotImplementedError def undo (self ): raise NotImplementedError class Light : """接收者:电灯""" def on (self ): print ("电灯打开" ) def off (self ): print ("电灯关闭" ) class LightOnCommand (Command ): """具体命令:开灯""" def __init__ (self, light: Light ): self.light = light def execute (self ): self.light.on() def undo (self ): self.light.off() class LightOffCommand (Command ): """具体命令:关灯""" def __init__ (self, light: Light ): self.light = light def execute (self ): self.light.off() def undo (self ): self.light.on() class RemoteControl : """调用者:遥控器""" def __init__ (self ): self.history: List [Command] = [] def execute (self, command: Command ): command.execute() self.history.append(command) def undo (self ): if self.history: command = self.history.pop() command.undo() light = Light() remote = RemoteControl() on_cmd = LightOnCommand(light) off_cmd = LightOffCommand(light) remote.execute(on_cmd) remote.execute(off_cmd) remote.undo()
函数式策略模式 Python 的函数是一等公民,可以更简洁地实现策略模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 from typing import Callable , List def bubble_sort (data: List [int ] ) -> List [int ]: arr = data.copy() n = len (arr) for i in range (n): for j in range (0 , n-i-1 ): if arr[j] > arr[j+1 ]: arr[j], arr[j+1 ] = arr[j+1 ], arr[j] return arr def quick_sort (data: List [int ] ) -> List [int ]: if len (data) <= 1 : return data pivot = data[len (data) // 2 ] left = [x for x in data if x < pivot] middle = [x for x in data if x == pivot] right = [x for x in data if x > pivot] return quick_sort(left) + middle + quick_sort(right) def python_sort (data: List [int ] ) -> List [int ]: return sorted (data) strategies = { 'bubble' : bubble_sort, 'quick' : quick_sort, 'python' : python_sort, } def sort_data (data: List [int ], strategy: str = 'python' ) -> List [int ]: sort_func = strategies.get(strategy, python_sort) return sort_func(data) data = [64 , 34 , 25 , 12 , 22 , 11 , 90 ] print (sort_data(data, 'bubble' ))print (sort_data(data, 'quick' ))print (sort_data(data, 'python' ))
📊 性能对比 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import timefrom functools import wrapsdef timer_func (): count = 0 def inner (): nonlocal count count += 1 return count return inner class TimerClass : def __init__ (self ): self.count = 0 def __call__ (self ): self.count += 1 return self.count import timeitfunc_timer = timer_func() class_timer = TimerClass() func_time = timeit.timeit('func_timer()' , globals =globals (), number=1000000 ) class_time = timeit.timeit('class_timer()' , globals =globals (), number=1000000 ) print (f"闭包实现: {func_time:.4 f} s" )print (f"类实现: {class_time:.4 f} s" )
⚠️ 避坑指南 陷阱 1:混淆 call 和 init 1 2 3 4 5 6 7 class BadExample : def __call__ (self, value ): """这是被调用时执行,不是初始化时""" print (f"Called with {value} " ) obj = BadExample() obj("hello" )
陷阱 2:忘记返回值 1 2 3 4 5 6 7 8 9 10 11 class Counter : def __init__ (self ): self.count = 0 def __call__ (self ): self.count += 1 counter = Counter() result = counter() print (result)
陷阱 3:在 call 中递归调用 1 2 3 4 5 6 7 8 9 10 11 12 13 class Recursive : def __init__ (self ): self.count = 0 def __call__ (self, n ): self.count += 1 if n > 0 : return self(n - 1 ) r = Recursive() r(5 ) print (r.count)
🎯 本讲总结 通过本讲,我们掌握了:
知识点 核心要点 callable() 判断对象是否可调用 call 让实例可以像函数一样调用 可调用对象优势 保存状态、继承、可扩展 策略模式 用函数或类实现可互换算法 命令模式 封装请求为对象,支持撤销
记住这句话 :
可调用对象结合了函数和类的优点,让代码既灵活又可维护。
📚 推荐教材 《Python 编程从入门到实践(第 3 版)》 | 《流畅的 Python(第 2 版)》 | 《CPython 设计与实现》
学习路线: 零基础 → 《从入门到实践》 → 《流畅的 Python》 → 本门课程 → 《CPython 设计与实现》
🎓 加入《流畅的 Python》直播共读营 学到这里,如果你想系统吃透这本书——欢迎加入我的直播共读课。
每周直播精讲,逐章拆解核心知识点 专属学习群,随时答疑交流 试运营特惠:499 元 → 299 元 👉 【立即报名《流畅的 Python》共读课】 :https://mp.weixin.qq.com/s/ivHJwn1nNx5ug4TFrapvGg
🔗 课程导航 ← 上一讲:生成器与协程 | 下一讲:对象引用与可变性 →
💬 联系我 主营业务 :AI 编程培训、企业内训、技术咨询
🎓 AI 编程实战课程 想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!