当前位置: 首页 > news >正文

Python魔术方法

前言

没有系统的学过python,看ML perf storage的源码发现这中双下划线的函数什么情况,明明grep找不到在哪里调用了可是就是调用了n次,觉得有点诡异了,查了一下原来如此,魔术方法。

魔术方法

魔术方法(magic methods)或双下划线方法(dunder methods,“dunder” 是 “double underscore” 的缩写)。魔术方法是 Python 中具有特殊意义的函数,通常由双下划线包围,如 initstrgetitem 等。这些方法使得类实例可以与内置操作和函数无缝集成,从而实现自定义行为。

init

这个看名字就很明白,对象初始化方法,实例化对象之后立即触发,在构造函数之后调用。我直接拿ML perf storage的源码举例子。

def __init__(self, format_type, dataset_type, epoch, worker_index,total_num_workers, total_num_samples, samples_per_worker, batch_size, shuffle=Shuffle.OFF, seed=1234):self.format_type = format_typeself.dataset_type = dataset_typeself.epoch = epochself.total_num_workers = total_num_workersself.total_num_samples = total_num_samplesself.samples_per_worker = samples_per_workerself.batch_size = batch_sizeself.worker_index = worker_indexself.shuffle = shuffleself.total_num_steps = self.samples_per_worker//batch_size# pdb.set_trace()self.reader = ReaderFactory.get_reader(type=self.format_type,dataset_type=self.dataset_type,thread_index=worker_index,epoch_number=self.epoch)self.seed = seedif not hasattr(self, 'indices'):self.indices = np.arange(self.total_num_samples, dtype=np.int64)if self.shuffle != Shuffle.OFF:if self.shuffle == Shuffle.SEED:np.random.seed(self.seed)np.random.shuffle(self.indices)

call

这就是那个让我觉得诡异的函数,grep也没别的地方调用啊,我特地备注了调用了无数次,主要介绍一下call,后面的简单举例。call这个方法允许类的实例被像函数一样调用。

  • 接收一个 sample_info 参数。
  • 记录读取操作的调试信息。
  • 根据 sample_info 计算当前样本的全局索引 sample_idx。
  • 检查是否超过了步数限制或样本数量限制,如果是,则抛出 StopIteration 异常,表示 epoch 结束。
  • 使用 Profile 上下文管理器记录数据加载的性能信息。
  • 从 reader 读取指定索引的图像。
  • 返回图像和相应的索引。
    def __call__(self, sample_info): # 调用无数次logging.debug(f"{utcnow()} Reading {sample_info.idx_in_epoch} out of {self.samples_per_worker} by worker {self.worker_index}")sample_idx = sample_info.idx_in_epoch + self.samples_per_worker * self.worker_indexlogging.debug(f"{utcnow()} Reading {sample_idx} on {sample_info.iteration} by worker {self.worker_index}")step = sample_info.iteration       if step >= self.total_num_steps or sample_idx >= self.total_num_samples:# Indicate end of the epochraise StopIteration()with Profile(MODULE_DATA_LOADER, epoch=self.epoch, image_idx=sample_idx, step=step):image = self.reader.read_index(self.indices[sample_idx], step)return image, np.uint8([self.indices[sample_idx]])

举个简单例子:

class MyClass:def __init__(self, value):self.value = valuedef __call__(self):return f"Called with value: {self.value}"# 自动调用 __call__
obj = MyClass(10)
print(obj())  # 输出: Called with value: 10

iternext

iternext 方法在使用迭代(例如 for 循环)时自动调用。

class MyClass:def __init__(self, values):self.values = valuesself.index = 0def __iter__(self):self.index = 0return selfdef __next__(self):if self.index < len(self.values):result = self.values[self.index]self.index += 1return resultelse:raise StopIteration# 自动调用 __iter__ 和 __next__
obj = MyClass([1, 2, 3])
for value in obj:print(value)

getitemsetitem

getitemsetitem 方法在使用索引访问和设置元素时自动调用。

class MyClass:def __init__(self, values):self.values = valuesdef __getitem__(self, index):return self.values[index]def __setitem__(self, index, value):self.values[index] = value# 自动调用 __getitem__ 和 __setitem__
obj = MyClass([1, 2, 3])
print(obj[1])  # 自动调用 __getitem__,输出: 2
obj[1] = 10    # 自动调用 __setitem__
print(obj[1])  # 自动调用 __getitem__,输出: 10

strlen

str 方法在调用 print() 函数或使用 str() 函数时自动调用。len 方法在调用 len() 函数时自动调用。

class MyClass:def __init__(self, value):self.value = valuedef __str__(self):return f"MyClass with value: {self.value}"def __len__(self):return len(self.value)obj = MyClass([1, 2, 3])
# 自动调用 __str__
print(obj)
# 自动调用 __len__
print(len(obj))  # 输出: 3

一些其他的

算术运算符方法

  • add(self, other):实现加法运算 +。
  • sub(self, other):实现减法运算 -。
  • mul(self, other):实现乘法运算 *。
  • truediv(self, other):实现除法运算 /。

比较运算符方法

  • eq(self, other):实现等于运算 ==。
  • ne(self, other):实现不等于运算 !=。
  • lt(self, other):实现小于运算 <。
  • le(self, other):实现小于等于运算 <=。
  • gt(self, other):实现大于运算 >。
  • ge(self, other):实现大于等于运算 >=。

容器类型方法

  • getitem(self, key):定义使用索引访问元素的行为。
  • setitem(self, key, value):定义使用索引设置元素的行为。
  • delitem(self, key):定义使用索引删除元素的行为。
  • len(self):定义对象的长度,通常与 len() 函数配合使用。
  • contains(self, item):定义使用 in 运算符检查成员资格的行为。

优点和应用

魔术方法通过定义类的行为方式,增强了代码的可读性和可维护性。例如,通过实现 getitemsetitem,类实例可以像列表或字典一样使用索引访问和修改元素;通过实现 iternext,类实例可以参与迭代操作。

这些方法在实现运算符重载、容器类型行为、迭代器协议、上下文管理等方面提供了强大的支持,使自定义类与 Python 内置类型和功能无缝集成,从而实现更自然和直观的接口。这种灵活性和强大功能,使得魔术方法在 Python 面向对象编程中发挥了重要作用。

相关文章:

  • liunx配置网络的命令
  • mac电脑鼠标键盘共享软件:ShareMouse for Mac 激活版
  • CV每日论文--2024.6.4
  • 【干货】超详细域名申请和备案流程,分别需要哪些资料?
  • 性能测试学习-基本使用-元件组件介绍(二)
  • CSS - 元素竖向百分比的基准值是什么?
  • 平板显示LED背光芯片OC6700,输入3.6V~60V,升压型 LED 恒流驱动器
  • Linux设备驱动platform驱动
  • Springboot JVM监控 通过Promethus
  • PS怎么编程:深入探索Photoshop的编程奥秘
  • 静态网页实现-人脸识别-案例(web)
  • 代码随想录35期Day60-JavaScript
  • 产品经理的需求善变,利用规则引擎减少80%的需求变更成本
  • Python3 列表
  • 2023年简单易用的透明加密软件--安秉网盾企业数据防泄密方案
  • $translatePartialLoader加载失败及解决方式
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • Android 架构优化~MVP 架构改造
  • Babel配置的不完全指南
  • CSS实用技巧干货
  • golang 发送GET和POST示例
  • k个最大的数及变种小结
  • MySQL的数据类型
  • Python3爬取英雄联盟英雄皮肤大图
  • SQLServer之创建显式事务
  • 程序员最讨厌的9句话,你可有补充?
  • 第十八天-企业应用架构模式-基本模式
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 前嗅ForeSpider中数据浏览界面介绍
  • 什么软件可以剪辑音乐?
  • 使用权重正则化较少模型过拟合
  • 小程序01:wepy框架整合iview webapp UI
  • 移动端唤起键盘时取消position:fixed定位
  • 带你开发类似Pokemon Go的AR游戏
  • #13 yum、编译安装与sed命令的使用
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (1)虚拟机的安装与使用,linux系统安装
  • (16)Reactor的测试——响应式Spring的道法术器
  • (4)事件处理——(7)简单事件(Simple events)
  • (C11) 泛型表达式
  • (SpringBoot)第七章:SpringBoot日志文件
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (几何:六边形面积)编写程序,提示用户输入六边形的边长,然后显示它的面积。
  • (四)模仿学习-完成后台管理页面查询
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)LINQ之路
  • (转)Unity3DUnity3D在android下调试
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • .net 按比例显示图片的缩略图
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .net8.0与halcon编程环境构建
  • [\u4e00-\u9fa5] //匹配中文字符
  • [8481302]博弈论 斯坦福game theory stanford week 1