马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一. 什么是数据模子?
Python数据模子是Python对象体系的抽象,通过一组特别方法(如__init__、__len__等)和协议(如迭代协议、上下文管理协议),界说了对象怎样与语言的内置功能(如len()、for循环等)交互。
焦点头脑
- 同一性:全部对象(如列表、字典、自界说类)的活动都通过雷同的特别方法实现。
- 机动性:通过实现特别方法,可以让自界说对象支持内置使用(如+、in、切片等)。
例子
- import collections
- Card = collections.namedtuple('Card', ['rank', 'suit'])
- class FrenchDeck:
- ranks = [str(n) for n in range(2, 11)] + list('JQKA')
- suits = 'spades diamonds clubs hearts'.split()
- def __init__(self):
- self._cards = [Card(rank, suit) for suit in self.suits
- for rank in self.ranks]
- def __len__(self):
- return len(self._cards)
- def __getitem__(self, position):
- return self._cards[position]
复制代码 表明
- 模块导入:
import collections
导入了 Python 尺度库中的 collections 模块。
- 定名元组界说:Card:
Card = collections.namedtuple('Card', ['rank', 'suit'])
使用 namedtuple 创建了一个名为 Card 的简朴类,体现扑克牌的一张牌。每个 Card 对象有两个属性:
- rank:体现牌的点数(如 '2', 'J', 'A' 等)。
- suit:体现牌的花色(如 'spades', 'diamonds' 等)。
- 类界说:FrenchDeck:
- 界说了一个名为 FrenchDeck 的类,体现一副尺度的 52 张扑克牌。
- 类属性: ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split()
- ranks:体现牌的全部点数,包罗数字牌('2' 到 '10')和字母牌('J', 'Q', 'K', 'A')。
- suits:体现牌的全部花色('spades' 黑桃、'diamonds' 方片、'clubs' 梅花、'hearts' 红心)。
- 构造函数 __init__: def __init__(self): self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]
初始化时创建了一副完备的扑克牌,存储在 _cards 列表中。通过列表推导式天生全部大概的牌组合。
- 方法 __len__: def __len__(self): return len(self._cards)
实现了特别方法 __len__,使得可以通过 len(deck) 获取扑克牌的数量。
- 方法 __getitem__: def __getitem__(self, position): return self._cards[position]
实现了特别方法 __getitem__,使得可以通过索引访问扑克牌,比方 deck[0]。
常用特别方法:
方法对应使用__init__对象初始化__repr__ / __str__字符串体现__len__len(obj)__getitem__obj[key](支持索引和切片)__iter__for x in obj(迭代)__enter__ / __exit__with语句(上下文管理)迭代协议
实现__iter__和__next__方法,让对象支持for循环:- class CountDown:
- def __init__(self, start):
- self.current = start
- def __iter__(self):
- return self
- def __next__(self):
- if self.current <= 0:
- raise StopIteration
- else:
- self.current -= 1
- return self.current + 1
- for num in CountDown(3):
- print(num) # 输出: 3 2 1
复制代码
表明
- 类界说:CountDown:
- 界说了一个名为 CountDown 的类,用于实现倒计时功能。
- 构造函数 __init__:
def __init__(self, start): self.current = start
初始化时吸取一个参数 start,体现倒计时的起始值,并将其赋值给实例属性 self.current。
- 方法 __iter__:
def __iter__(self): return self
实现了可迭代协议,使得该类的实例可以作为迭代器使用。返回自身(self)。
- 方法 __next__:
def __next__(self): if self.current <= 0: raise StopIteration else: self.current -= 1 return self.current + 1
实现了迭代器协议中的 __next__ 方法:
- 假如当前值 self.current 小于或便是 0,则抛出 StopIteration 非常,体现迭代竣事。
- 否则,将 self.current 减 1,并返回减 1 前的值(即当前值)。
- 使用场景:
- 该类可以通过 for 循环或手动调用 next() 方法举行倒计时。
- 示例:
- countdown = CountDown(5)
- for value in countdown:
- print(value)
复制代码 输出结果: 5 4 3 2 1
上下文管理协议
实现__enter__和__exit__方法,支持with语句:- class Timer:
- def __enter__(self):
- self.start = time.time()
- return self
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.end = time.time()
- print(f"耗时: {self.end - self.start:.2f}秒")
- with Timer():
- time.sleep(1) # 输出: 耗时: 1.00秒
复制代码 表明
- 类界说:Timer:
- 界说了一个名为 Timer 的类,用于丈量代码块的实行时间。
- 方法 __enter__:
def __enter__(self): self.start = time.time() return self
- 实现了上下文管理协议中的 __enter__ 方法。
- 在进入 with 语句块时,记载当前时间(以秒为单元)并存储在实例属性 self.start 中。
- 返回自身(self),以便在 with 语句块中可以访问该对象。
- 方法 __exit__:
def __exit__(self, exc_type, exc_val, exc_tb): self.end = time.time() print(f"耗时: {self.end - self.start:.2f}秒")
- 实现了上下文管理协议中的 __exit__ 方法。
- 在退出 with 语句块时,记载当前时间(以秒为单元)并存储在实例属性 self.end 中。
- 盘算实行时间(self.end - self.start),并以两位小数的格式打印到控制台。
- 使用场景:
- 通过 with 语句使用 Timer 类来丈量代码块的实行时间。
- 示例: with Timer(): time.sleep(1) # 输出: 耗时: 1.00秒
- 在 with 语句块中调用了 time.sleep(1),模仿了一个耗时 1 秒的使用。
- Timer 类会自动盘算并打印出这段代码的实行时间。
让自界说类支持切片
- class MySequence:
- def __init__(self, data):
- self.data = data
- def __len__(self):
- return len(self.data)
- def __getitem__(self, index):
- if isinstance(index, slice):
- return self.data[index.start : index.stop : index.step]
- else:
- return self.data[index]
- seq = MySequence([0, 1, 2, 3, 4])
- print(seq[1:3]) # [1, 2](支持切片!)
复制代码 鸭子范例(Duck Typing)
Python不查抄对象的范例,而是查抄对象是否实现了特定的方法(便是否“像鸭子一样叫”)。
示例:
- class FakeList:
- def __len__(self):
- return 10
- def __getitem__(self, index):
- return index * 2
- fake = FakeList()
- print(len(fake)) # 10(调用__len__)
- print(fake[5]) # 10(调用__getitem__)
- print(isinstance(fake, list)) # False,但行为类似列表!
复制代码
|