零基础学习Python(四)

1. __getitem__、__setitem__、__iter__、__next__魔法方法

__index__方法是对象被作为索引访问时调用的魔法方法,那么当对象要进行索引访问时,调用什么魔法方法呢?答案是__getitem__魔法方法。

class C:def __getitem__(self, index):print(index)

当索引位切片时,打印的是一个内置函数slice,也就是说,slice函数相当于一个切片:

使用[slice(2, 6)]进行索引访问,等同于[2:6],左闭右开。类似的,s[7:]相当于s[slice(7, None)],s[::4]相当于s[slice(None, None, 4)]。

根据索引或者切片进行赋值的操作会调用__setitem__魔法方法:

class D:def __init__(self, data):self.data = datadef __getitem__(self, index):return self.data[index]def __setitem__(self, index, value):self.data[index] = value

如果通过for循环获取数据,那么也会调用__getitem__方法:

class D:def  __init__(self, data):self.data = datadef __getitem__(self, index):return self.data[index] * 2
d = D([1, 2, 3, 4, 5])
for i in d:print(i, end=' ')

上述例子中for循环最终会调用到__getitem__魔法方法,其实并不是一定的,前提是对象没有__iter__魔法方法和__next__魔法方法。在Python中,如果定义了__iter__魔法方法,则认为是可迭代对象,如果一个可迭代对象定义了__next__魔法方法,则认为是一个迭代器。比如列表,是一个可迭代对象,但因为没有__next__方法,所以不是迭代器。for循环所做的事,就是将对象传给内置函数iter()获取一个迭代器,然后再去调用迭代器的__next__方法实现遍历。例如以下for循环:

x = [1, 2, 3, 4, 5]
for i in x:print(i, end=' ')

等价于:

_ = iter(x)
while True:try:i = _.__next__() except StopIteration:breakprint(i, end=' ')

自定义一个迭代器,根据传入的起始位置和终止位置,计算区间内的数乘以2:

class Double:def __init__(self, start, stop)self.value = start - 1self.stop = stopdef __iter__(self):return selfdef __next__(self):if self.value == self.stop:raise StopIterationself.value += 1return self.value * 2

2. __contains__、__bool__、__len__魔法方法

使用运算符in或者not in就会触发__contains__魔法方法:

class C:def __init__(self, data):self.data = datadef __contains__(self, item):print("嗨~")return item in self.data

如果没有__contains__魔法方法,使用了in或者not in运算符,那么Python就会去触发__iter__和__next__魔法方法:

class C:def __init__(self, data):self.data = datadef __iter__(self):print("Iter", end='->')self.i = 0return selfdef __next__(self):if self.i == len(self.data):raise StopIterationprint("Next", end='->')item = self.data[self.i]self.i += 1return item

使用bool函数会触发__bool__魔法方法:

class D:def __bool__(self):print("Bool")return True

如果没有实现__bool__魔法方法,则会去调用__len__魔法方法:

class D:def __init__(self, data):self.data = datadef __len__(self):print("Len")return len(self.data)

如果不想要某个魔法方法不生效,直接赋值为None,比如__contains__赋值为None,使用in或者not in运算符就会报错,而不是去调用__iter__和__next__魔法方法:

class C:def __init__(self, data):self.data = datadef __iter__(self):print("Iter", end='->')self.i = 0return selfdef __next__(self):if self.i == len(self.data):raise StopIterationprint("Next", end='->')item = self.data[self.i]self.i += 1return itemdef __contains__ = None

3. __str__、__repr__魔法方法

__str__魔法方法和__repr__魔法方法分别对应str()和repr()这两个函数,虽然在大多数情况下他们得到的结果是一样的,但是本质上str的结果是给人看的,repr的结果是给程序看的:

可以看到对于字符串,repr函数的结果会包一层引号,为什么会包一层引号,就是为了给eval函数解析用的。将str函数的结果传给eval函数,会报错,因为程序会去寻找FishC这个变量,因为没找到所以报错,而repr的结果传给eval函数,程序会认为'FishC'是一个字符串,从而正确识别。

所以eval函数被认为是repr的反函数,即传一个参数给repr函数,然后再将结果传给eval函数,最终会得到参数本身:

如果没有定义__str__魔法方法,调用str函数时就会去触发__repr__魔法方法:

class C:def __repr__(self):return 'I love FishC'

但如果实现了__str__魔法方法,但是没有实现__repr__魔法方法,调用repr函数时,是不会触发__str__魔法方法的:

class C:def __str__(self):return 'I love FishC'

如果只定义了__str__魔法方法,没有定义__repr__魔法方法,打印对象列表,是不会触发到__str__魔法方法的,打印的结果是对象的地址:

但是反过来,如果只定义了__repr__魔法方法,没有定义__str__魔法方法,打印对象列表,则可以触发__repr__魔法方法:

使用__str__方法和__repr__方法实现对象在不同场景下的不同显示效果:

class C:def __init__(self, data):self.data = datadef __str__(self):return f'data = {self.data}'def __repr__(self):return f'C({self.data})'def __add__(self, other):self.data += other

4. property函数和装饰器

使用property函数,可以将变量由另一个变量全权代理:

class C:def __init__(self):self._x = 250def getx(self):return self._xdef setx(self, x):self._x = xdef delx(self):del self._xx = property(getx, setx, delx)

property函数的参数是函数,所以property经常被当做装饰器来使用,如果一个get函数使用property函数来修饰,则可以将函数名等价于变量名来使用:

class E:def __init__(self):self._x = 250@propertydef x(self):return self._x

这样也就实现了只读的对象属性。为了使对象可写可删,还需实现对象名.setter和deleter方法:

class E:def __init__(self):self._x = 250@propertydef x(self):return self._x@x.setterdef x(self, value):self._x = value@x.deleterdef x(self):del self._x

5. 描述符以及用描述符实现property函数

描述符定义:如果实现了__get__、__set__、__delete__这三个方法其中任意一个或者多个,那么这个类就可以称为描述符。描述符可不是管理本类对象的属性,是用来管理其他类的属性,类似于property函数:

class D:def __get__(self, instance, owner):print(f"get~\nself -> {self}\ninstance -> {instance}\nowner -> {owner}")def __set__(self, instance, value):print(f"set~\nself -> {self}\ninstance -> {instance}\nvalue -> {value}")def __delete__(self, instance):print(f"delete~\nself -> {self}\ninstance -> {instance}")class C:x = D()

可以看到,self参数对应的是描述符类的对象,instance参数对应的是被描述符所拦截的属性所在的类的对象,owne参数对应的是描述符所拦截的属性所在的类。使用描述符实现上述property函数的代码"x = property(getx, setx, delx)":

class D:def __get__(self, instance, owner):return instance._xdef __set__(self, instance, value):instance._x = valuedef __delete__(self, instance):del instance._xclass C:def __init(self, x=250):self._x = xx = D()

 

使用描述符实现property函数(这里定义位MyProperty,功能与property一样):

class MyProperty:def __init__(self, fget=None, fset=None, fdel=None):self.fget = fgetself.fset = fsetself.fdel = fdeldef __get__(self, instance, owner):return self.fget(instance)def __set__(self, instance, value):self.fset(instance, value)def __delete__(self, instance):self.fdel(instance)class C:def __init(self, x=250):self._x = xdef getx(self):return self._xdef setx(self, value):self._x = valuedef delx(self):del self._xx = MyProperty(getx, setx, delx)

 

实现装饰器功能:

class MyProperty:def __init__(self, fget=None, fset=None, fdel=None):self.fget = fgetself.fset = fsetself.fdel = fdeldef __get__(self, instance, owner):return self.fget(instance)def __set__(self, instance, value):self.fset(instance, value)def __delete__(self, instance):self.fdel(instance)def getter(self, func):self.fget = funcreturn selfdef setter(self, func):self.fset = funcreturn selfdef deleter(self, func):self.fdel = funcreturn selfclass D:def __init(self, x=250):self._x = x@MyPropertydef x(self):return self._x@x.setterdef x(self, value):self._x = value@x.deleterdef x(self):del self._x

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/383603.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode回退不显示了,不方便操作

一、后退前进按钮 顶部显示&#xff0c;方便调试 <—— ——> 文件-> 首选项 -> 设置->commandcenter->勾选 Window: Title Bar Style->custom 将native —>custom

MongoDB教程(二十二):MongoDB固定集合

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、固定集…

单片机学习历程

学习单片机的过程可以分为几个主要阶段&#xff0c;每个阶段都涉及不同的学习内容和技能提升。下面我将以一个典型的学习历程为例进行介绍&#xff1a; 初学阶段 1.入门理论学习&#xff1a; 开始接触单片机的基础知识&#xff0c;学习其工作原理、体系结构和常见的芯片类型…

昇思25天学习打卡营第20天|CV-ResNet50图像分类

打卡 目录 打卡 图像分类 ResNet网络介绍 数据集准备与加载 可视化部分数据集 残差网络构建 Building Block 结构 代码实现 Bottleneck结构 代码实现 构建ResNet50网络 代码定义 模型训练与评估 可视化模型预测 重点&#xff1a;通过网络层数加深&#xff0c;感知…

vue3前端开发-小兔鲜项目-路由拦截器增加token的携带

vue3前端开发-小兔鲜项目-路由拦截器增加token的携带&#xff01;实际开发中&#xff0c;很多业务接口的请求&#xff0c;都要求必须是登录状态&#xff01;为此&#xff0c;这个token信息就会频繁的被加入到了请求头部信息中。request请求头内既然需要频繁的携带这个token.我们…

STM32烧录的时候报错:Error :Flash Download failed -“Cortex-M3“

点击图中标号1&#xff0c;按顺序点击进入设置 按图中标序&#xff0c;进入添加页面 添加图中所选&#xff0c;然后一直确定退出即可&#xff0c;若没有图中所示选项&#xff0c;可能软件没下载对&#xff0c;文章已附带 添加后&#xff0c;即可烧录成功。

《JavaEE篇》--多线程(2)

《JavaEE篇》--多线程(1) 线程安全 线程不安全 我们先来观察一个线程不安全的案例&#xff1a; public class Demo {private static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() -> {//让count自增5W次…

【Android】碎片—动态添加、创建Fragment生命周期、通信

简单用法 在一个活动中添加两个碎片&#xff0c;并让这两个碎片平分活动空间 先新建一个左侧碎片布局和一个右侧碎片布局 左侧碎片 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/…

场外期权如何报价?名义本金是什么?

今天带你了解场外期权如何报价&#xff1f;名义本金是什么&#xff1f;投资者首先需要挑选自己想要进行期权交易的沪深上市公司股票。选出股票后&#xff0c;需要将股票信息、预期的操作时间&#xff08;如期限&#xff09;、看涨或看跌的选择以及预计的交易金额等信息报给场外…

java-selenium 截取界面验证码图片并对图片文本进行识别

参考链接 1、需要下载Tesseract工具并配置环境变量&#xff0c;步骤如下 Tesseract-OCR 下载安装和使用_tesseract-ocr下载-CSDN博客 2、需要在IDEA中导入tess4j 包&#xff1b;在pom.xml文件中输入如下内容 <!--导入Tesseract 用于识别验证码--><dependency>&l…

跟代码执行流程,读Megatron源码(四)megatron初始化脚本initialize.py之initialize_megatron()分布式环境初始化

在前文中&#xff0c;我们讲述了pretrain函数的执行流程&#xff0c;其首要步骤是megatron分组的初始化与环境的配置。本文将深入initialize_megatron函数源码&#xff0c;剖析其初始化分布式训练环境的内部机制。 注&#xff1a;在此假设读者具备3D并行相关知识 一. initiali…

Linux - 进程的概念、状态、僵尸进程、孤儿进程及进程优先级

目录 进程基本概念 描述进程-PCB task_struct-PCB的一种 task_struct内容分类 查看进程 通过系统目录查看 通过ps命令查看 通过系统调用获取进程的PID和PPID 通过系统调用创建进程- fork初始 fork函数创建子进程 使用if进行分流 Linux进程状态 运行状态-R 浅度睡眠状态-S…

AV1技术学习:Constrained Directional Enhancement Filter

CDEF允许编解码器沿某些(可能是倾斜的)方向应用非线性消阶滤波器。它以88为单位进行。如下图所示&#xff0c;通过旋转和反射所示的三个模板来定义八个预设方向。 Templates of preset directions and their associated directions. The templates correspond to directions of…

Python小工具之httpstat网络分析

一、简介 Python httpstat是一个基于Python的命令行工具&#xff0c;用于测量HTTP请求的性能和状态信息。它能够向目标服务器发送HTTP请求&#xff0c;并显示详细的统计信息&#xff0c;包括DNS解析时间、建立连接时间、TLS/SSL握手时间、首字节时间、总时间等。这些信息对于排…

Mailspring搭建安装教程:打造个性邮件体验

Mailspring搭建安装教程步骤&#xff01;如何选择电子邮件服务商&#xff1f; Mailspring作为一款功能强大、界面友好的邮件客户端&#xff0c;成为了许多用户的首选。AokSend将为大家提供详细的Mailspring搭建安装教程&#xff0c;帮助您打造个性化的邮件体验。 Mailspring搭…

若依 ruoyi poi Excel合并行的导入

本文仅针对文字相关的合并做了处理 &#xff0c;图片合并及保存需要另做处理&#xff01;&#xff01; 目标&#xff1a;Excel合并行内容的导入 结果&#xff1a; 1. ExcelUtil.java 类&#xff0c;新增方法&#xff1a;判断是否是合并行 /*** 新增 合并行相关代码&#xff1a;…

Java | Leetcode Java题解之第264题丑数II

题目&#xff1a; 题解&#xff1a; class Solution {public int nthUglyNumber(int n) {int[] dp new int[n 1];dp[1] 1;int p2 1, p3 1, p5 1;for (int i 2; i < n; i) {int num2 dp[p2] * 2, num3 dp[p3] * 3, num5 dp[p5] * 5;dp[i] Math.min(Math.min(num2…

Docker-Compose配置zookeeper+KaFka+CMAK简单集群

1. 本地DNS解析管理 # 编辑hosts文件 sudo nano /etc/hosts # 添加以下三个主机IP 192.168.186.77 zoo1 k1 192.168.186.18 zoo2 k2 192.168.186.216 zoo3 k3注&#xff1a;zoo1是192.168.186.77的别名&#xff0c;zoo2是192.168.186.18的别名&#xff0c;zoo3是192.168.186.1…

react中组件间的通信

一、父传子 1.代码展示 import React, { useState } from react;function SonPage(props){ // 子组件const {msg} propsreturn (<div>我是子组件 {msg}</div>) }function App() { // 父组件const [msgText,setMsgText] useState(父传子)return (<div classN…

全国区块链职业技能大赛第八套区块链产品需求分析与方案设计

任务1-1:区块链产品需求分析与方案设计 医疗健康平台中涉及到医院、医生、患者等参与方,他们需要在区块链医疗健康平台中完成账户注册、身份上链、挂号就诊、查询病例等多种业务活动。通过对业务活动的功能分析,可以更好的服务系统的开发流程。基于医疗健康平台系统架构,以…