Python CookBook 第八章 类与对象(下)

2023-10-27

目录

8.15委托属性的访问

 8.16在类中定义多个构造函数

8.17 不通过调用init来创建实例

8.18用Mixin类来扩展类定义

8.19实现带有状态的对象和状态机

8.20 调用对象上的方法,方法名以字符串形式给出

8.24让类支持比较操作

8.25 创建缓存实例


8.15委托属性的访问

# 8.15委托属性的访问
# 委托是一种编程模式,我们将某个特定的操作转交另一个不同的额对象实现,简单来说就是这样的
class A:
    def spam(self,x):
        pass
    def foo(self):
        pass

class B:
    def __init__(self):
        self._a = A()

    def sapm(self,x):
        return self._a.spam(x)

    def foo(self):
        return self._a.foo()

#实现代理的一个例子
class Proxy:
    def __init__(self,obj):
        self._obj = obj

    #委托属性浏览内部属性
    def __getattr__(self, name):
        print('Getting:',name)
        return getattr(self._obj,name)

    #委托属性设置
    def __setattr__(self, name, value):
        if name.startswith('_'):
            super().__setattr__(name,value)
        else:
            print('setattr:',name,value)
            setattr(self._obj,name,value)
    #委托属性删除
    def __delete__(self, name):
        if name.startswith('_'):
            super().__delattr__(name)
        else:
            print('Deleting:',name)
            delattr(self._obj,name)
#使用这个代理类
class Spam:
    def __init__(self,x):
        self.x = x
    def bar(self,y):
        print('Spam.bar:',self.x,y)
#创建一个实例
a = Spam(2)
#创建一个委托
s = Proxy(a)
print(s.x)
# Getting: x
# 2
s.bar(3)
# Getting: bar
# Spam.bar: 2 3
s.x = 37
# set

 8.16在类中定义多个构造函数

# 用户不限于__init__()提供的方法来创建实例
import time

class Date:
    #第一种
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
    #另一种
    @classmethod
    def today(cls):
        t = time.localtime()
        return cls(t.tm_year,t.tm_mon,t.tm_mday)

#会用这个构造函数
a = Date(2022,5,16)
b = Date.today()

8.17 不通过调用init来创建实例

class Date:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

d = Date.__new__(Date)
print(d)
d.year = 2022
d.month = 5
d.day = 16
print(d.year,d.month,d.day)   #2022 5 16  原文中不能直接设置,可能版本更新,可以直接设置响应的值
data = {'year':2022,'month':5,'day':17}  #实现字典的反序列化,将字典转化为实例
for key,value in data.items():
    setattr(d,key,value)
print(d.year,d.month,d.day)

8.18用Mixin类来扩展类定义

# 在类进行定制化处理时,我们有兴趣将各种各样的定制化处理方法添加到映射方法中
class LoggeMappingMixin:
    #添加一些日志设置检查的功能
    __slots__ = ()
    def __getitem__(self, key):
        print('Getting:' + str(key))
        return super().__getitem__(key)  #在这里使用super()是必要的,通过这个函数将任务转交给解析顺序(MRO)上的下一个类

    def __setattr__(self, key, value):
        print('Setting {} = {!r}'.format(key,value))
        return super().__setitem__(key,value)

    def __delitm__(self,key):
        print('Deleting ' + str(key))
        return super().__delitem__(key)

class SetOnceMappingMixin:
    #设置只允许设置一次键
    __slots__ = ()
    def __setitem__(self, key, value):
        if key in self:
            raise KeyError(str(key) + ' already set')
        return super().__setitem__(key,value)

class StringKeysMappingMixin:
    #限制键必须是字符串类型
    __slots__ = ()
    def __setitem__(self, key, value):
        if not isinstance(key,str):
            raise TypeError('keys must be strings')
        return super().__setitem__(key,value)

#使用这些类,这些类单独并没有什么用,只有和其他类一起使用时,才能发挥起作用
class LoggeDict(LoggeMappingMixin,dict):  #这里调用LoggeMappingMixin中的函数实际上传递给dict了
    pass

d = LoggeDict()
d['x'] = 2
print(d['x'])
del d['x']

from collections import defaultdict
class SetOnceDefaultDict(SetOnceMappingMixin,defaultdict):
    pass

d = SetOnceDefaultDict(list)
d['x'].append(2)
d['y'].append(3)
d['x'].append(9)
print(d)
d['x'] = 1
# Traceback (most recent call last):
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 156, in <module>
#     d['x'] = 1
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 127, in __setitem__
#     raise KeyError(str(key) + ' already set')
# KeyError: 'x already set'
# Getting: x

from collections import OrderedDict
class StringOrdereDict(StringKeysMappingMixin,
                       SetOnceMappingMixin,
                       OrderedDict):
    pass
d = StringOrdereDict()
d['x'] = 23
d[42] = 10
# Traceback (most recent call last):
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 172, in <module>
#     d[42] = 10
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 135, in __setitem__
#     raise TypeError('keys must be strings')
# TypeError: keys must be strings

8.19实现带有状态的对象和状态机

# 想实现对象在不同状态中进行操作,但是并不希望有大量的判断语句,我们将每一种操作状态以单独的类来定义
class Connection:
    def __init__(self):
        self.new_state(CLosedConnectionState)

    def new_state(self,newstate):
        self._state = newstate

    #委托状态类
    def read(self):
        return self._state.read(self)

    def write(self,data):
        return self._state.write(self,data)

    def open(self):
        return self._state.open(self)

    def close(self):
        return self._state.close(self)

#连接状态基类
class ConnectionState:
    @staticmethod
    def read(conn):
        raise NotImplementedError()

    @staticmethod
    def write(conn,data):
        raise NotImplementedError()

    @staticmethod
    def open(conn):
        raise NotImplementedError()

    @staticmethod
    def close(conn):
        raise NotImplementedError()

#设置不同状态
class CLosedConnectionState(ConnectionState):
    @staticmethod
    def read(conn):
        raise RuntimeError('Not open')

    @staticmethod
    def write(conn,data):
        raise RuntimeError('Not open')

    @staticmethod
    def open(conn):
        conn.new_state(OpenConnectionState)

    @staticmethod
    def close(conn):
        raise RuntimeError('ALready closed')

class OpenConnectionState(ConnectionState):
    @staticmethod
    def read(conn):
        print('Reading')

    @staticmethod
    def write(conn,data):
        print('writing')

    @staticmethod
    def open(conn):
        raise RuntimeError('Already open')

    @staticmethod
    def close(conn):
        conn.new_state(CLosedConnectionState)

c = Connection()
print(c._state)  #<class '__main__.CLosedConnectionState'>
# c.read()
# Traceback (most recent call last):
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 257, in <module>
#     print(c.read())
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 191, in read
#     return self._state.read(self)
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 224, in read
#     raise RuntimeError('Not open')
# RuntimeError: Not open
c.open()
c.read()  #Reading
print(c._state)   #<class '__main__.OpenConnectionState'>
c.close()
print(c._state)  #<class '__main__.CLosedConnectionState'>
#另一种实现方法是直接更改__class__属性
class Connection:                        #这里将连接和连接状态进行合并,随着状态的改变实例也会自己修改自己的类型
    def __init__(self):
        self.new_state(ClosedConnection)

    def new_state(self,newstate):
        self.__class__ = newstate

    def read(self):
        raise NotImplementedError()
    def write(self):
        raise NotImplementedError()
    def open(self):
        raise NotImplementedError()
    def read(self):
        raise NotImplementedError()

class ClosedConnection(Connection):
    def read(self):
        raise RuntimeError('Not open')
    def write(self):
        raise RuntimeError('Not open')
    def open(self):
        self.new_state((OpenConnection))
    def close(self):
        raise RuntimeError('Already closed')

class OpenConnection(Connection):
    def read(self):
        print('reading')
    def write(self):
        print('writing')
    def open(self):
        raise RuntimeError('Already Open')
    def close(self):
        self.new_state(ClosedConnection)
#试一下
c = Connection()
print(c)   #<__main__.ClosedConnection object at 0x00000226505F1A60>
# c.read()
# Traceback (most recent call last):
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 310, in <module>
#     c.read()
#   File "E:\vippython\Python CookBook\第八章 类与对象(下).py", line 290, in read
#     raise RuntimeError('Not open')
# RuntimeError: Not open
c.open()
print(c)  #<__main__.OpenConnection object at 0x00000226505F1A60>
c.read()  #reading

8.20 调用对象上的方法,方法名以字符串形式给出

# 对于简单的情况 使用getattr()  调用一个方法,可以使用相应getattr查询相应的属性,将查询的方法
# 当做函数进行使用就可以了,使用operator.methodcall()创建一个可调用对象,通过包含在字符串中的
# 名称来调用函数。
import math

class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __repr__(self):
        return 'Point{!r:},{!r:}'.format(self.x,self.y)

    def distance(self,x,y):
        return math.hypot(self.x-x,self.y-y)

p = Point(2,3)
d = getattr(p,'distance')(3,2)   #1.4142135623730951
print(d)
#另一种方法是使用operator.methodcaller()
import operator
a = operator.methodcaller('distance',3,2)(p)
print(a)  #1.4142135623730951


#在环状数据结构中管理内存
# 使用weakref库中提供的弱引用机制
import weakref

class Node:
    def __init__(self,value):
        self.value = value
        self._parent = None
        self.children = []

    def __repr__(self):
        return 'node({!r:})'.format(self.value)

    @property
    def parent(self):
        return self._parent if self._parent is None else self._parent()

    @parent.setter
    def parent(self,node):
        self._parent = weakref.ref(node)

    def add_child(self,child):
        self.children.append(child)
        self.parent = self

root = Node('parent')
print(root)
c1 = Node('child')
print(c1)
root.add_child(c1)
print(c1.parent)
del root
print(c1.parent)

8.24让类支持比较操作

# 在类之间实现比较操作,但是不能编写大量的特殊方法
# 举例子 比较房子大小
from functools import total_ordering

class Room:
    def __init__(self,name,length,width):
        self.name = name
        self.length = length
        self.width = width
        self.square_feet = self.length * self.width

@total_ordering
class House:
    def __init__(self,name,style):
        self.name = name
        self.style = style
        self.rooms = []

    @property
    def living_space_footage(self):
        return sum(r.square_feet for r in self.rooms)

    def add_room(self,room):
        self.rooms.append(room)

    def __str__(self):
        return '{} : {} square foot {}'.format(self.name,
                                               self.living_space_footage,
                                               self.style)

    def __eq__(self, other):    #定义进行比较的方法
        return self.living_space_footage == other.living_space_footage

    def __lt__(self, other):
        return self.living_space_footage < other.living_space_footage

h1 = House('h1','Cape')
h1.add_room(Room('Master Bedroom',14,21))
h1.add_room(Room('Living Room',18,21))
h1.add_room(Room('Kitchen',12,16))
h1.add_room(Room('Office',14,12))

h2 = House('h2','Ranch')
h2.add_room(Room('Master Bedroom',14,21))
h2.add_room(Room('Living Room',18,21))
h2.add_room(Room('Kitchen',12,16))

h3 = House('h3','Split')
h3.add_room(Room('Master Bedroom',14,21))
h3.add_room(Room('Living Room',18,21))
h3.add_room(Room('Kitchen',12,16))
h3.add_room(Room('Office',14,17))
houses = [h1,h2,h3]

print(h1 > h2) # True
print(h1 < h2) # False
print(h1 >= h2) #  True
print(max(houses))  # h3 : 1102 square foot Split
#__le__ <=  __gt__  >  __ge__ >=  __ne__ ==

8.25 创建缓存实例

# 想要确保针对某一组输入参数只会有一个类实例存在时使用一个与类本身相分离的工厂函数
class Spam:
    def __init__(self,name):
        self.name = name

import weakref
_spam_cache = weakref.WeakValueDictionary()  #将实例缓存再这个里边,但不再需要时,删除就行

def get_spam(name):
    if name not in _spam_cache:
        s = Spam(name)
        _spam_cache[name] = s
    else:
        s = _spam_cache[name]
    return s

a = get_spam('foo')
b = get_spam('bar')
print(a is b)  #False
c = get_spam('foo')
print(a is c)  #True

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python CookBook 第八章 类与对象(下) 的相关文章

  • 避免由于相对 URL 导致的错误请求

    我正在尝试使用Scrapy抓取一个网站 并且我想要抓取的每个页面的url都是使用这种相对路径编写的 a href en item to scrap html Link a 现在 在我的浏览器中 这些链接可以工作 您可以访问类似的网址http
  • 翠儿。让流永远运行

    我对 tweepy python 库比较陌生 我想确保我的流 python 脚本始终在远程服务器上运行 因此 如果有人能够分享如何实现这一目标的最佳实践 那就太好了 现在我正在这样做 if name main while True try
  • 如何使用 cython 编译扩展?

    我正在尝试从示例页面编译一个简单的 cython 扩展here http docs cython org src userguide tutorial html在我安装了 Python 2 6 64 位版本的 Windows 7 64 位计
  • 一次将Python dict的内容分配给多个变量?

    我想做这样的事情 def f return a 1 b 2 c 3 a b f or a b f IE 这样 a 被分配为 1 b 被分配为 2 并且 c 是未定义的 这与此类似 def f return 1 2 a b f 依赖于变量名称
  • 从字符串到类型的词法转换

    最近 我尝试用Python存储和读取文件中的信息 遇到了一个小问题 我想从文本文件中读取类型信息 从 string 到 int 或 float 的类型转换非常有效 但从 string 到 type 的类型转换似乎是另一个问题 当然 我尝试了
  • 优化 Keras 以使用所有可用的 CPU 资源

    好吧 我真的不知道我在说什么 所以请耐心听我说 我正在使用 Theano 后端运行 Keras 以在 MNIST 图像上运行基本的神经网络 目前只是一个教程 过去 我一直使用我的旧 HP 笔记本电脑 因为我有 Windows 和 Ubunt
  • 带图像的简单 GUI [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我试图在简单的 GUI 上显示一些卡
  • 如何限制Django CreateView中ForeignKey字段的选择?

    我有一个沿着这些思路的模型结构 models py class Foo models Model class Bar models Model foo models ForeignKey Foo class Baz models Model
  • sudo pip install python-Levenshtein 失败,错误代码 1

    我正在尝试在 Linux 上安装 python Levenshtein 库 但每当我尝试通过以下方式安装它时 sudo pip install python Levenshtein 我收到此错误 命令 usr bin python c 导入
  • Python Kivy - 在本机网络浏览器中打开 url 的应用程序

    我尝试制作一个简单的应用程序 在单击 Screen One 上的按钮后 在 Kivy 中打开一个网页 我使用了这个主题 Python 在应用程序中直接显示网络浏览器 iframe https stackoverflow com questi
  • 无法打开 Python。错误 0xc000007b

    我最近一直在学习 Python 3 我在我的上网本 32 位 Windows 7 上创建简单的小程序没有任何问题 当我将它安装在我的上网本上时 我没有遇到任何问题 但现在我已经开始使用它了 我想将它安装在我的台式机上 并且我有一个 我的桌面
  • 在径向(树)网络x图中查找末端节点(叶节点)

    给定下图 是否有一种方便的方法来仅获取末端节点 我所说的端节点是指那些具有一个连接边的到节点 我认为这些有时被称为叶节点 G nx DiGraph fromnodes 0 1 1 1 1 1 2 3 4 5 5 5 7 8 9 10 ton
  • 更改 pandas 中多个日期时间列的时区信息

    有没有一种简单的方法可以将数据帧中的所有时间戳列转换为本地 任何时区 不是逐列进行吗 您可以有选择地将转换应用于所有日期时间列 首先 选择它们select dtypes https pandas pydata org pandas docs
  • 获取列表中倒数第二个元素[重复]

    这个问题在这里已经有答案了 我可以通过以下方式获取列表的倒数第二个元素 gt gt gt lst a b c d e f gt gt gt print lst len lst 2 e 有没有比使用更好的方法print lst len lst
  • Python:计算数据帧列中所有行中特定字符的实例数

    我有一个包含列 toaddress ccaddress body 的数据框 df 我想迭代数据帧的索引 以获取 toaddress 和 ccaddress 字段中电子邮件地址的最小 最大和平均数量 这是通过计算这两列中每个字段中的 和 的实
  • 将输入发送到 python 子进程而不等待结果

    我正在尝试为一段代码编写一些基本测试 该代码通常通过 stdin 无休止地接受输入 直到给出特定的退出命令 我想检查程序是否在给出一些输入字符串时崩溃 经过一段时间来考虑处理 但似乎无法弄清楚如何发送数据而不是陷入等待我不知道的输出关心 我
  • Python 3.2 中 **kwargs 和 dict 有什么区别?

    看起来Python的很多方面都只是功能的重复 除了我在 Python 中的 kwargs 和 dict 中看到的冗余之外 还有什么区别吗 参数解包存在差异 许多人使用kwargs 并通过dict作为论据之一 使用参数解包 Prepare f
  • 如何禁止 celery 中的 pickle 序列化

    Celery 默认使用 pickle 作为任务的序列化方法 如中所述FAQ http ask github com celery faq html isn t using pickle a security concern 这代表一个安全漏
  • 检查字符串是否只有字母和空格 - Python

    试图让 python 返回一个字符串仅包含字母和空格 string input Enter a string if all x isalpha and x isspace for x in string print Only alphabe
  • 在 Python 模块中使用 InstaLoader

    我正在尝试使用 Instaloader 下载与主题标签相关的照片以进行图像分析 我在GitHub存储库中找到了一个全面的方法 如何在终端中执行它 但是 我需要将脚本集成到Python笔记本中 这是脚本 instaloader no vide

随机推荐

  • 刷题之移动零

    给定一个数组 nums 编写一个函数将所有 0 移动到数组的末尾 同时保持非零元素的相对顺序 示例 输入 0 1 0 3 12 输出 1 3 12 0 0 说明 必须在原数组上操作 不能拷贝额外的数组 尽量减少操作次数 来源 力扣 Leet
  • ESP8266-NodeMCU——从苏宁API获取实时天气

    前言 本篇介绍如何使用ESP8266 NodeMCU从苏宁API获取实时天气 苏宁API 点击跳转 其显示如下 其中我们要抓取的是红线部分的内容 并通过串口打印 当然 这部分也可以用来显示在OLED上 我之前就是这么玩 在正式开始前 需要了
  • 采用python解决实际问题_python使用ddt过程中遇到的问题及解决方案【推荐】

    前言 在使用DDT数据驱动 HTMLTestRunner输出测试报告时遇到过2个问题 1 生成的测试报告中 用例名称后有dict gt new empty dictionary 2 使用ddt生成的用例名称无法更改 1 用例名称后有dict
  • 区块链光谱

    虫洞社区签约作者介绍 叶露 王二 销售人员 克莱登技术有限公司 本文根据Taylor Pearson所著区块链光谱图 从密码学 分布式系统 政治学和经济学的角度对区块链做出的全方面分析 想象你是一位大学院长 学院正要新增一门关于区块链的课程
  • Visual ChatGPT原理解读——大模型论文阅读笔记四

    论文 https arxiv org abs 2303 04671 代码 https github com microsoft TaskMatrix 一 整体框架 如图所示 用户上传一张黄花的图像并输入一个复杂的语言指令 请根据该图像的预测
  • Springboot自带线程池

    一 ThreadPoolTaskExecuto 1 ThreadPoolTaskExecutor线程池 ThreadPoolTaskExecutor是Spring基于java本身的线程池ThreadPoolExecutor做的二次封装 主要
  • ConcurrentHashMap详解

    目录 ConcurrentHashMap介绍 ConcurrentHashMap底层数据结构 ConcurrentHashMap部分分析 ConcurrentHashMap与HashMap HashTable的区别 源码为jdk1 7 Co
  • vscode clang-format配置(不生效问题)

    打开Settings设置 菜单栏File gt Preferences gt Setting Windows Ctrl Shift P 搜索Settings打开 Settings分类 User 全局设置 安装时默认文件目录里 Remote
  • 前馈电容的作用-DCDC

    DCDC电路中的前馈电容 如下图为典型的DCDC电路 芯片是台湾省立琦科技的 上图为DCDC典型应用电路 CIN为输入滤波电容 CBOOT是上管驱动 自举 电容 L是储能电感 R1和R2是反馈电阻 CFF是前馈电容 COUT是输出滤波电容
  • 解决导入torch报错from torch._C import xxxx

    当使用import torch是 报错from torch C import xxxx 与Symbol not found mkl blas caxpy或其他类似的报错 解决方法 pip uninstall torch 卸载当前的pytor
  • STM32F103CBT6单片机I2C接口读取锂电池电量计LC709203F数据

    一 基本情况 LC709203F是一款适用于单节锂离子 聚合物电池应用的电量计 通过HG CVR算法来测量电池的RSOC 相对电荷状态 精确的RSOC数据有助于改善便携式设备的运行时间和合理使用 利用单片机的I2C口与LC709203F通讯
  • 大气层整合傻瓜包_【工具】switch大气层9.2系统升级固件+大气层0.10.3离线整合包...

    全部解压到TF卡根目录覆盖即可 hekate ctcaer 5 1 2引导启动时选择Atmosphere选项 如果做了双系统的 想进官方系统的在启动时选择Stock SYSNAND 选项 离线升级教程 下面开始教程 务必保证机器有50 以上
  • ARDUINO学习过程 (7)步进电机实验

    七 步进电机实验 1 uln2003芯片 凹槽朝上放置 如上图所示 左下角接地 实验中 所有器件接地要统一 当1B给予高电平 1C相当于成为阴极 相当于接地 当3B给予高电平 3C相当于成为阴极 相当于接地 以此类推 2 步进电机 四相五线
  • js遍历文件目录

    当我们需要在项目里找到目标文件或是某一类后缀的文件时 就需要对目录做遍历了 以查找项目里所有tsx文件为例 const fs require fs const path require path const targetFilesMap 存
  • 小程序发送短信

    新建云函数sendSms 在sendSms文件夹命令行下 执行 npm install qcloudsms js qcloudsms js 是腾讯提供的 node js 包 云函数入口文件 const cloud require wx se
  • Java实现远程连接服务器并执行命令的方法

    一 Apache sshd java实现远程连接服务器并执行命令的方法 先描述一下场景 本人在通信领域工作 暂时负责命令行这一块业务 公司使用apache sshd在Java应用中嵌入sshd服务 实现了通过SecureCRT等工具调用自定
  • SCN论文理解

    Scale wise Convolution for Image Restoration AAAI 用于图像恢复的按比例卷积 https github com ychfan scn sr 问题 单纯地将尺度不变技术 如多尺度测试 随机尺度数
  • 【2022-6-17 pytorch的各个组件和实战】

    学习目标 pytorch的各个组件和实战 学习内容 基本配置 首先导入必须的包 对于一个PyTorch项目 我们需要导入一些Python常用的包来帮助我们快速实现功能 常见的包有os numpy等 此外还需要调用PyTorch自身一些模块便
  • SpringCloud中打开feign的熔断机制

    spingcloud openfeign的依赖中包含了hystrix的jar包 不需要额外导入 打开熔断只需yml中添加 feign hystrix enabled true 然后在feign的接口类上添加fallback指定熔断的回调方法
  • Python CookBook 第八章 类与对象(下)

    目录 8 15委托属性的访问 8 16在类中定义多个构造函数 8 17 不通过调用init来创建实例 8 18用Mixin类来扩展类定义 8 19实现带有状态的对象和状态机 8 20 调用对象上的方法 方法名以字符串形式给出 8 24让类支