Python-鸭子类型
- 前言
- 鸭子类型应用场景
-
- [1. 可迭代对象](#1. 可迭代对象)
- [2. 容器对象](#2. 容器对象)
- [3. 上下文管理器](#3. 上下文管理器)
- [4. 可调用对象](#4. 可调用对象)
- [5. 文件类对象](#5. 文件类对象)
- [6. 序列类型](#6. 序列类型)
- [7. 比较对象](#7. 比较对象)
前言
鸭子类型(Duck Typing)是一种编程风格,它不关注对象的具体类型,而是关注对象是否实现了特定的方法或协议
在 Python 中,鸭子类型是一种动态类型的风格,其核心思想是:"如果它走路像鸭子,叫起来像鸭子,那么它就是鸭子"
鸭子类型应用场景
1. 可迭代对象
是指可以被遍历(迭代)的对象
支持 for 循环和 iter()
字符串,列表,元组,字典,集合都是可迭代对象
方法
iter():返回一个迭代器(Iterator)对象。
getitem():支持通过整数索引访问元素(从 0 开始)
- 循环遍历:for 循环自动将可迭代对象转换为迭代器
- 解包操作:a, b = (1, 2)
- 列表推导式:[x*2 for x in iterable]
- 生成器表达式:(x*2 for x in iterable)
- 内置函数:sum()、max()、min()、sorted() 等
py
for char in "hello":
print(char, end=" ") # h e l l o
for num in [1, 2, 3]:
print(num, end=" ") # 1 2 3
for key in {"a": 1, "b": 2}:
print(key, end=" ") # a b
# 自定义可迭代类
class MyRange:
def __init__(self, n):
self.n = n
def __iter__(self):
i = 0
while i < self.n:
yield i # 使用生成器简化迭代器实现
i += 1
for i in MyRange(3):
print(i, end=" ") # 0 1 2
2. 容器对象
是一种可以包含其他对象的对象,它们实现了特定的方法来支持元素的存储、访问和管理
字符串、列表、集合都是容器
方法
contains(self, item):支持 in 操作符,检查元素是否存在
len(self):支持 len() 函数,返回容器长度
- 成员检查:item in container
- 长度计算:len(container)
- 遍历:for item in container
py
# 判断子串
print("h" in "hello") # True
print(1 in [1, 2, 3]) # True
print(1 in {1, 2, 3}) # True
print("key" in {"key": 1}) # True
# 查看字符串长度
print(len("abc ")) # 4(包含空格)
# 自定义容器类
class MyList:
def __init__(self, items):
self.items = items
def __contains__(self, item):
return item in self.items # 委托给内置列表
def __len__(self):
return len(self.items) # 委托给内置列表
my_list = MyList([10, 20, 30])
print(20 in my_list) # True
print(len(my_list)) # 3
3. 上下文管理器
用于管理资源的对象,确保资源在使用后被正确释放。上下文管理器通过 with 语句使用
方法
enter():进入上下文时调用,返回资源对象。
exit():退出上下文时调用,负责清理资源。
- 资源管理:文件、网络连接、数据库连接等
- 锁管理:线程锁、互斥锁
- 状态恢复:临时修改全局状态,退出时恢复
- 异常处理:集中处理特定代码块的异常
py
# 文件对象是上下文管理器
with open("test.txt", "w") as f:
f.write("hello") # 自动关闭文件
# 线程锁也是上下文管理器
import threading
lock = threading.Lock()
with lock:
# 自动获取和释放锁
print("Locked")
# 自定义上下文管理器
class Timer:
def __enter__(self):
import time
self.start = time.time()
return self # 返回值绑定到 as 后的变量
def __exit__(self, exc_type, exc_val, exc_tb):
import time
elapsed = time.time() - self.start
print(f"耗时: {elapsed:.2f}秒")
with Timer():
sum(i for i in range(10**7)) # 耗时: 0.47秒
4. 可调用对象
可以像函数一样被调用(使用 () 运算符)的对象或实体
函数、方法、类都是可调用对象
py
def add(a, b):
return a + b
print(add(1, 2)) # 3
class Adder:
def __call__(self, a, b):
return a + b
adder = Adder()
print(adder(3, 4)) # 7 (像函数一样调用实例)
# 自定义可调用类
class Counter:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self.count
counter = Counter()
print(counter()) # 1
print(counter()) # 2
5. 文件类对象
是一种实现了文件接口的对象,也称为类文件对象 或流对象这类对象支持文件的基本操作(如读取、写入、关闭),但不一定对应物理文件,可能是内存中的数据、网络连接或其他数据源
方法
- read(size=-1):读取指定字节数(默认读取全部)。
- write(data):写入数据并返回写入的字节数。
- close():关闭对象并释放资源。
- seek(offset[, whence]):移动文件指针位置。
- tell():返回当前文件指针位置。
py
# 标准库中的 StringIO 模拟文件操作
from io import StringIO
f = StringIO()
f.write("hello") # 写入内存
print(f.getvalue()) # hello
f.seek(0) # 移动文件指针到开头
print(f.read()) # hello
# 自定义文件类
class LogFile:
def __init__(self, filename):
self.filename = filename
def write(self, data):
with open(self.filename, "a") as f:
f.write(f"[LOG] {data}\n")
def read(self):
with open(self.filename, "r") as f:
return f.read()
log = LogFile("app.log")
log.write("User logged in")
print(log.read()) # [LOG] User logged in
6. 序列类型
是一种可迭代的容器,支持通过索引访问元素
- 可变序列:列表 、字节数组
- 不可变序列:字符串 、元组 、字节
通用操作:
- 索引访问:seq[index]
- 切片:seq[start:stop:step]
- 长度:len(seq)
- 成员检查:x in seq
- 重复:seq * n
- 拼接:seq1 + seq2
- 遍历:for x in seq
py
s = "hello" # 字符串
print(s[0]) # h
lst = [1, 2, 3] # 列表
print(lst[1]) # 2
t = (4, 5, 6) # 元组
print(t[2]) # 6
# 自定义序列类
class MySequence:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.data[index] # 支持索引和切片
seq = MySequence([10, 20, 30])
print(seq[0]) # 10
print(seq[1:]) # [20, 30]
7. 比较对象
是指实现了比较运算符(如 <、>、== 等)的对象。通过实现这些方法,对象可以用于排序、最大 / 最小值查找、条件判断等操作
常用的比较方法有:
- lt(self, other):小于(<)
- le(self, other):小于等于(<=)
- eq(self, other):等于(==)
- ne(self, other):不等于(!=)
- gt(self, other):大于(>)
- ge(self, other):大于等于(>=)
py
# 列表、元组、字符串都可以用 max()
print(max([3, 1, 4])) # 4(列表)
print(max((5, 2, 9))) # 9(元组)
print(max("hello")) # 'o'(字符串)
# 自定义类实现 __lt__() 也可以用 max()
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __lt__(self, other):
return self.age < other.age
people = [Person("Alice", 25), Person("Bob", 30)]
print(max(people).name) # "Bob"(按年龄比较)