首页 > 编程语言 >【Python】笔记:接口:从协议到抽象基类

【Python】笔记:接口:从协议到抽象基类

时间:2022-12-03 21:23:41浏览次数:39  
标签:__ return Python self ._ 接口 基类 position def

S11 接口:从协议到抽象基类

# random.shuffle 就地打乱
from random import shuffle

l = list(range(10))
shuffle(l)
print(l)
shuffle(l)
print(l)
[0, 6, 3, 2, 4, 8, 5, 7, 1, 9]
[0, 5, 9, 7, 6, 2, 4, 8, 1, 3]

猴子补丁

import collections

Card = collections.namedtuple('Card', 'rank suit')

class FrenchDeck:

    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamondes 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]
# target: 洗牌
deck = FrenchDeck()
shuffle(deck)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In [4], line 3
      1 # target: 洗牌
      2 deck = FrenchDeck()
----> 3 shuffle(deck)


File c:\Users\qiany\AppData\Local\Programs\Python\Python39\lib\random.py:362, in Random.shuffle(self, x, random)
    359     for i in reversed(range(1, len(x))):
    360         # pick an element in x[:i+1] with which to exchange x[i]
    361         j = randbelow(i + 1)
--> 362         x[i], x[j] = x[j], x[i]
    363 else:
    364     _warn('The *random* parameter to shuffle() has been deprecated\n'
    365           'since Python 3.9 and will be removed in a subsequent '
    366           'version.',
    367           DeprecationWarning, 2)


TypeError: 'FrenchDeck' object does not support item assignment
# 打补丁
def set_card(deck, position, card):
    deck._cards[position] = card

FrenchDeck.__setitem__ = set_card
shuffle(deck)
print(deck[:5])
[Card(rank='9', suit='spades'), Card(rank='2', suit='spades'), Card(rank='5', suit='spades'), Card(rank='Q', suit='clubs'), Card(rank='10', suit='hearts')]

定义抽象基类的子类

import collections

Card = collections.namedtuple('Card', 'rank suit')

class FrenchDeck2(collections.MutableSequence):

    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamondes 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]

    def __setitem__(self, position, value):  # 欲实现 shuffle 须实现 __setitem__
        self._cards[position] = value

    def __delitem__(self, position):
        del self._cards[position]

    def insert(self, position, value):
        self._cards.insert(position, value)

继承 MutableSequence 必须实现 __delitem__, insert

FrenchDeck2

  • Sequence 继承了 __contains__, __iter__, __reversed__, index, count
  • MutableSequence 继承了 append, extend, pop, remove, __iadd__

标准库中的抽象基类

collections.abs

第一层:

  • Iterable : Sequence, Mapping, Set, Iterator 通过 __iter__ 方法支持迭代
  • Container: Sequence, Mapping, Set 通过 __contains__ 方法支持 in
  • Sized : Sequence, Mapping, Set, MappingView 通过 __len__ 方法支持 len()
  • Callable : (None)
  • Hashable : (None)

第二层:

  • Sequence : MutableSequence
  • Mapping : MutableMapping
  • Set : MutableSet, ItemsView, KeysView
  • MappingView : ItemsView, KeysView, ValuesView

numbers

  • Number
  • Complex
  • Real
  • Rational
  • Intergal

eg. 检查一个数是否为整数: isinstance(x, numbers.Integral)

isinstance(x, type)

  • type 为 Intergal 检查 int, bool
  • type 为 Real 检查 int, bool, float, fractions.Fraction, Numpy中相关对象

检查对象是否可以被 调用, 可用 callable()

检查对象是否可以被 散列, 可用 isinstance(obj, Hashable)

import numbers

print(1, isinstance(233, numbers.Integral))
print(2, isinstance(233.33, numbers.Integral))
print(3, isinstance(233.00, numbers.Integral))
print(4, isinstance(True, numbers.Integral))
print(5, isinstance(False, numbers.Integral))
True
False
False
True
True

定义并使用一个抽象基类

Tombola:

  • 抽象方法:

    • load()
    • pick()
  • 具体方法:

    • loaded()
    • inspect()
import abc

class Tombola(abc.ABC):

    @abc.abstractclassmethod  # 一般 abstractclassmethod 只有 文档字符串
    def load(self, iterable):
        '''可从迭代对象中添加元素'''

    @abc.abstractclassmethod
    def pick(self):
        '''随机删除元素并返回
        若果实例为空, 抛出 LookupError'''
    
    def loaded(self):  # 抽象基类可以包含具体实现方法
        '''是否有元素'''
        return bool(self.inspect())  # 抽象基类中的具体方法 只能依赖基类定义的接口(即该抽象基类中其他具体方法、抽象方法、特征)

    def inspect(self):
        '''返回一个由当前元素构成的有序元组'''

        items = []
        while True:
            try:
                items.append(self.pick())
            except LookupError:
                break
        self.load(items)
        return tuple(sorted(items))

抽象方法可以有实现代码(不仅局限于文档字符串)

但即使实现了,子类 必须 覆盖抽象方法

或者用 super() 函数调用抽象方法

注: @abc.abstractmethod 和其他修饰器连用时, @abc.abstractmethod 应放在最内层

# 不符合 Tombola 的子类
class Fake(Tombola):
    def pick(self):
        return 13

f = Fake()
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In [13], line 6
      3     def pick(self):
      4         return 13
----> 6 f = Fake()


TypeError: Can't instantiate abstract class Fake with abstract method load
# Tombola 的子类 BingoCage

import random
class BingoCage(Tombola):

    def __init__(self, items):
        self._randomizer = random.SystemRandom()  # 调用 os.random() 函数, 生成"适合加密"的随机字节序列
        self._items = []
        self.load(items)  # 委托 load 初始化

    def load(self, items):
        self._items.extend(items)
        self._randomizer.shuffle(self._items)  # 打乱

    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            raise LookupError('pick from empty BingoCage')

    def __call__(self):
        self.pick()
class LotteryBlower(Tombola):

    def __init__(self, iterable):
        self._balls = list(iterable)

    def load(self, iterable):
        self._balls.extend(iterable)

    def pick(self):
        try:
            position = random.randrange(len(self._balls))
        except IndexError:
            raise LookupError('pick from empty LotteryBlower')
        return self._balls.pop(position)

    def loaded(self):  # 重写 loaded
        return bool(self._balls)
    
    def inspect(self):
        return tuple(sorted(self._balls))

虚拟子类

注册虚拟子类 在抽象基类上调用 register 方法, 这样, issubclassisinstance 都能识别

但 注册的类 不会从抽象基类中继承如何方法或属性

@Tombola.register  # 注册为 Tombola 的 虚拟子类
class TomboList(list):  # 继承 list
    def pick(self):
        if self:  # 是否为空
            position = random.randrange(len(self))
            return self.pop(position)
        else:
            raise LookupError('pop from empty TomboList')

    load = list.extend

    def loaded(self):
        return bool(self)
    
    def inspect(self):
        return tuple(sorted(self))
print(1, issubclass(TomboList, Tombola))

t = TomboList(range(100))
print(2, isinstance(t, Tombola))

print(3, TomboList.__mro__)  # 按顺序列出类及其超类
1 True
2 True
3 (<class '__main__.TomboList'>, <class 'list'>, <class 'object'>)

__subclasses__ 返回类的直接子类列表, 不包含虚拟子类

_abc_registry 只有抽象基类有整个属性(一个WeakSet对象)

标签:__,return,Python,self,._,接口,基类,position,def
From: https://www.cnblogs.com/Zinc233/p/FluentPython_S11.html

相关文章

  • 【Python】笔记:正确重载运算符
    正确重载运算符一元运算符-(__neg__)+(__pos__)最好返回self的副本~(__invert__)对整数位按位取反(~x==-(x+1))print(~2)-3中辍运算符+fromarray......
  • 回文链表-python
    问题:给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。思考:对称结构要想到stack方案一:双指针法将节点值赋值到数组......
  • 接口隔离原则介绍
    目录介绍00.问题思考分析01.前沿简单介绍02.如何理解接口隔离原则03.接口理解为一组API接口集合04.接口理解为单个API接口或函数05.接口理解为OOP中的接口概念06.总结一下分......
  • Python内容写入文件
       Python允许你将内容写入文件,方式与使用print()函数将字符串‘写’到屏幕上类似,但是,如果打开文件时用读模式,就不能写入,你需要以纯文本模式或添加纯文本模式打开该文......
  • Python 跳动的小球
    一、实验内容:跳动的小球游戏介绍二、实验对象:《零基础学Python》第13章Pygame游戏编程实例01用以下代码创建一个游戏弹窗:导入pygame模块并且用init()方法初始化,设置窗......
  • n202_python数据类型和数据结构
    3.数据类型和数据结构python的数据类型大致可以分为两种:python自带的内置数据类型和第三方扩展包中的数据类型。其中,python自带的内置数据类型可以分为两种:可变数据类......
  • Python爬取中国最好大学排行榜报错TypeError: unsupported format string passed to N
    ​本文使用的是如下网址:http://gaokao.xdf.cn/201911/10991728.html1问题分析与解决报错为类型错误,显示我们传递了不支持的格式字符串1.1strip()我们查看网页源码,......
  • python常用第三方库
    python常用第三方库官网主页查询、下载和发布Python包或库官网地址参考来源网络爬虫requests:https://pypi.org/project/requests/简洁且简单的处理HTTP请求的......
  • [oeasy]python0024_ 输出时间_time_模块_module_函数_function
    输出时间回忆上次内容​print​​函数有个默认的​​end参数​​​end参数​​的值可以是任意字符串​​end参数​​的值会输出到结尾位置​​end参数​​的默认值是......
  • Python调用接口鲁棒化处理防止阻塞
    如果是同其他团队或者系统协作开发,无法保证对方的接口不出问题,所以要考虑一种鲁棒的方法,保证自己的程序不管什么情况下都可以有合适的值返回。1.如果调用对方接口网络不同......