Python-鸭子类型

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"(按年龄比较)