零基础学习Python(三)

news2024/12/24 9:07:52

1. 多重继承

一个子类可以继承多个父类,这与一些编程语言的规则不通。

如果多个父类中有同名的变量和方法,子类访问的顺序是按照继承时小括号里书写的顺序进行访问的。

可以用issubclass(B, A)方法判断B是否为A的子类。

2. 绑定

类中的方法通过参数self与对象绑定,通过参数cls与类绑定,如果不用self或者cls来访问类中的变量或者方法,会报错找不到变量或者方法,或者达不到预期效果。

class C:
    x = 100
    def set_x(self, v):
        x = v

c = C()
c.set_x(520)

上述代码既不会改变对象c的属性x,也不会改变类C的属性x,set_x方法只是在函数内部建立了一个临时变量。

3. 重写与钻石继承

先定义父类:

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

    def add():
        return self.x + self.y

    def mul():
        return self.x * self.y

定义子类,并且重写父类的方法,同时调用父类的方法:

class D(C):
    def __init__(self, x, y, z):
        C.__init__(self, x, y)
        self.z = z

    def add():
        return C.add(self) + self.z

    def mul():
        return C.mul(self) * self.z

如果是钻石继承,这种直接通过类名调用类里面方法的方式可能会出现问题。什么是钻石继承?就是有两个类同时继承了同一个父类,然后另外一个类继承了这两个类,继承关系拓扑图类似于一个钻石(菱形):

钻石继承的问题如下:

可以发现,类A初始化了两次!使用super()函数可以解决上述问题,类B1、类B2、类C的代码修改如下:

class B1(A):
    def __init__(self):
        super().__init__()
        print("哈喽,我是B1~")

class B2(A):
    def __init__(self):
        super().__init__()
        print("哈喽,我是B2~")

class C(B1, B2):
    def __init__(self):
        super().__init__()
        print("哈喽,我是C~")

使用super()方法调用__init__方法,不用传递self参数,因为super方法会自动解决。super函数的原理依赖于Python的MRO(Method Resolution Order:方法解析顺序),这可以通过类的方法mro()或者变量__mro__查看:

关于MRO顺序的一个案例:

class Displayer:
    def display(self, msg):
        print(msg)

class LoggerMixin:
    def log(self, msg, filename):
        with open(filename, 'a') as f:
            f.write(msg)

    def display(self, msg):
        super().display(msg)
        self.log(msg)

class MySubClass(LoggerMixin, Displayer):
    def log(self, msg):
        super().log(msg, filename="subclasslog.txt")

subcls = MySubClass()
subcls.display("This is a test.")
        

运行结果是打印This is a test,并且生成subclasslog.txt,里面内容是This is a test。查看MySubClass的MRO顺序:

 

那么调用subcls的display方法,先去LoggerMixin里面找display方法,找到了,但是第一句是super().display(msg),此时不要以为会去LoggerMixin类的父类object里面找display方法,而是按照MRO顺序去Displayer里面找display方法,从而打印出This is a test,然后执行LoggerMixin力的display方法的第二句:self.log(msg),即调用MySubClass里面的log方法,发现没有,按照MRO顺序去LoggerMixin类里找log方法,找到了,即写入文件内容为msg。

4. __slots__属性

对象的属性除了直接obj.x = valueX这种方式设置外,还可以通过其字典__dict__的方式设置,比如:

c.__dict__['z'] = 666

 

Python中对象是可以随意添加任何属性的,这些属性存放在字典中,虽然字典访问效率高,但是浪费了很多空间,为了避免空间浪费,Python引入__slots__属性,通过__slots__属性设置一个类的对象只能拥有固定属性:

class C:
    __slots__ = ["x", "y"]
    def __init__(self, x)
        self.x = x

 

除了动态添加属性不行,在类的方法(包括构造方法)内添加属性也不行:

父类中的slots属性是不会在子类中生效的(但是子类仍然继承了父类的slots属性,只是不起作用了):

5. 魔法方法

__new__方法是在__init__方法之前调用的,常见的self对象就是它返回的。创建一个类,使得传给他的字符串始终为大写:

class CapStr(str):
    def __new__(cls, string):
        string = string.upper()
        return super().__new__(cls, string)

 

因为CapStr继承自str,所以str有的方法它也有:

对象被销毁时会调用__del__方法:

class C:
    def __init__(self):
        print("我来了~")
    
    def __del__(self):
        print("我走了~")

 

注意,不是使用了del语句就会调用__del__这个魔法方法,而是对象被销毁前才会调用,也就是说调用del语句并不会立即销毁对象,只是销毁对象的引用,只有当对象的引用都被销毁时,才会去销毁对象。比如将c再赋值给d,调用del c不会触发__del__魔法方法,接着调用del d才会触发。 

既然__del__方法可以在对象被销毁前动手动脚,那么可以通过将即将要销毁的对象赋值给全局变量的方式,实现对象的重生。但是使用全局变量可能会污染命名空间,那么可以通过闭包的形式将对象传递给函数的参数,从而实现永久保存:

class E:
    def __init__(self, name, func):
        self.name = name
        self.func = func
    
    def __del__(self):
        self.func(self)

def outer():
    x = 0
    def inner(y=None):
        nonlocal x
        if y:
            x = y
        else
            return x
    return inner

 

重写add方法可以实现自定义的加法功能,比如字符串的相加不再是拼接,而是字符长度的相加:

 

注意,加号调用的是左边对象的__add__方法,s1 + s2相当于s1.__add__(s2)。

__radd__方法的调用原则:如果加号两边的数据类型不同,并且左侧对象没有定义__add__方法,或者__add__方法实现为NotImplemented,那么Python就会去右侧对象找__radd__方法。

__iadd__方法不仅进行加法运算,还会将运算后的结果赋值给左侧对象,调用时机是使用了运算符+=:

__index__魔法方法是当对象作为索引值才会去调用,而不是对象的索引访问触发:

class C:
    def __index__(self):
        print("被拦截了~")
        return 3

关于属性的方法:hasattr、getattr:

class C:
    def __init(self, name, age):
        self.name = name
        self.__age = age

c = C("小甲鱼", 18)
hasattr(c, "name") # 返回True
getattr(c, "name") # 返回小甲鱼

对于私有属性,依然可以访问:

getattr(c, "_c__age") # 返回18

设置属性:

setattr(c, "_c__age", 19) # 返回18

删除属性:

delattr(c, "_c__age")

魔法方法__getattribute__会拦截getattr方法: 

class C:
    def __init(self, name, age):
        self.name = name
        self.__age = age
    
    def __getattribute__(self, attrname):
        print("拿来吧你~")
        return super().getattribute__(attrname)

c = C("小甲鱼", 18)
getattr(c, "name")

 

魔法方法__getattr__只有尝试去获取不存在的属性时才会去触发:

class C:
    def __init(self, name, age):
        self.name = name
        self.__age = age
    
    def __getattribute__(self, attrname):
        print("拿来吧你~")
        return super().getattribute__(attrname)

    def __getattr__(self, attrname):
        if attrname == 'FishC':
            print("I love FishC")
        else
            raise AttributeError(attrname)

c = C("小甲鱼", 18)

 

给属性赋值对应的魔法方法是__setattr__,但是这个方法里面的实现不能是self.attrname=value,因为这个语句又会调用魔法方法__setattr__,所以会死循环,正确做法是:

class D:
    def __setattr(self, attrname, value):
        self.__dict__[attrname] = value

同理,del语句删除属性时,也不能在魔法方法__del__中直接使用del self.attrname,否则也会无限循环,正确做法依然是操作self.__dict__这个字典:

class D:
    def __setattr(self, attrname, value):
        self.__dict__[attrname] = value

    def __delattr(self, attrname):
        self.__dict__[attrname]

​​​​​​​ 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【代码随想录笔记】数组

目录 1、二分查找 2、移除元素 3、有序数组的平方 4、螺旋矩阵II 1、二分查找 对于二分搜索法&#xff0c;有两个边界问题是容易把握不准的 1. 是left < right还是left < right 2. 当nums[middle] > target时&#xff0c;需要更新右边界&#xff0c;那是right …

【深度学习入门篇 ⑥】PyTorch搭建卷积神经网络

【&#x1f34a;易编橙&#xff1a;一个帮助编程小伙伴少走弯路的终身成长社群&#x1f34a;】 大家好&#xff0c;我是小森( &#xfe61;ˆoˆ&#xfe61; ) &#xff01; 易编橙终身成长社群创始团队嘉宾&#xff0c;橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…

‍我想我大抵是疯了,我喜欢上了写单元测试

前言 大家好我是聪。相信有不少的小伙伴喜欢写代码&#xff0c;但是对于单元测试这些反而觉得多此一举&#xff0c;想着我都在接口文档测过了&#xff01;还要写什么单元测试&#xff01;写不了一点&#xff01;&#xff01; 由于本人也是一个小小程序猿&#x1f649;&#xf…

Unity | Shader基础知识(第十八集:Stencil应用-透视立方盒子)

目录 一、前言 二、场景布置 三、 shader部分 1.图片的部分 2.图片部分纯净代码 3.遮罩部分复习 4.深度写入 ZWrite 5.颜色遮罩ColorMask 6.遮罩纯净代码 四、场景中shader使用 五、作者的碎碎念 一、前言 因为这个内容稍微有点多&#xff0c;我尽力讲清楚了&#x…

VAE论文阅读

在网上看到的VAE解释&#xff0c;发现有两种版本&#xff1a; 按照原来论文中的公式纯数学推导&#xff0c;一般都是了解生成问题的人写的&#xff0c;对小白很不友好。按照实操版本的&#xff0c;非常简单易懂&#xff0c;比如苏神的。但是却忽略了论文中的公式推导&#xff…

jquery中pdf在页面的显示和导出

jquery中pdf在页面的显示和导出 01 显示pdf01 .pdf结尾在线接口显示到页面 &#xff08;pdf.js库怎么安装及使用&#xff09;&#xff1a;只显示一页02 如何用PDF.JS显示整个PDF (而不仅仅是一页)&#xff1f;03 jQuery实现在线预览PDF文件(通过a标签链接跳转)&#xff1a; 02 …

【网络安全】PostMessage:分析JS实现XSS

未经许可&#xff0c;不得转载。 文章目录 前言示例正文 前言 PostMessage是一个用于在网页间安全地发送消息的浏览器 API。它允许不同的窗口&#xff08;例如&#xff0c;来自同一域名下的不同页面或者不同域名下的跨域页面&#xff09;进行通信&#xff0c;而无需通过服务器…

【STM32 HAL库】全双工DMA双buffer的I2S使用

1、配置I2S 我们的有效数据是32位的&#xff0c;使用飞利浦格式。 2、配置DMA **这里需要注意&#xff1a;**i2s的DR寄存器是16位的&#xff0c;如果需要发送32位的数据&#xff0c;是需要写两次DR寄存器的&#xff0c;所以DMA的外设数据宽度设置16位&#xff0c;而不是32位。…

ArrayLis练习

代码呈现 import java.util.ArrayList;public class ArrayListTest {public static void main(String[] args) {//创建集合ArrayList<String> list new ArrayList();//添加元素list.add("A");list.add("B");list.add("C");list.add(&quo…

222.买卖股票的最佳时机(力扣)

代码解决 class Solution { public:int maxProfit(vector<int>& prices) {// 初始化最小买入价为第一个价格int min1 prices[0];// 初始化最大利润为0int max1 0;// 从第二天开始遍历价格数组for (int i 1; i < prices.size(); i) {// 计算当前价卖出的利润&a…

C++:智能指针shared_ptr、unique_ptr、weak_ptr的概念、用法即它们之间的关系

智能指针 (1)概述 A.Why&#xff08;C为什么引入智能指针&#xff09; C引入智能指针的根本原因就是解决手动管理动态内存所带来的问题&#xff0c;手动管理动态内存常见的问题如下&#xff1a;内存泄漏、悬挂指针、释放操作未定义等 内存泄漏问题&#xff1a; 当程序用光了它…

React的usestate设置了值后马上打印获取不到最新值

我们在使用usestate有时候设置了值后&#xff0c;我们想要更新一些值&#xff0c;这时候&#xff0c;我们要想要马上获取这个值去做一些处理&#xff0c;发现获取不到&#xff0c;这是为什么呢&#xff1f; 效果如下&#xff1a; 1、原因如下 在React中,当你使用useState钩子…

线程安全(七)ReentrantLock 简介、Condition 条件变量、锁的工作原理、synchronized 与 Lock 的区别

目录 一、ReentrantLock 简介1.1 Reentrant 的特性:1.2 基本语法1.3 ReentrantLock 的主要方法:1.4 lock()、tryLock()、lockInterruptibly() 的区别:二、Condition 条件变量2.1 什么是 Condition 条件变量?2.2 Condition 的核心方法:2.3 Condition 使用示例1:等待与唤醒…

PJA1介导的焦亡抑制是鼻咽癌产生耐药性的驱动因素

引用信息 文 章&#xff1a;PJA1-mediated suppression of pyroptosis as a driver of docetaxel resistance in nasopharyngeal carcinoma. 期 刊&#xff1a;Nature Communications&#xff08;影响因子&#xff1a;14.7&#xff09; 发表时间&#xff1a;2024年6月2…

LLaMA-Factory

文章目录 一、关于 LLaMA-Factory项目特色性能指标 二、如何使用1、安装 LLaMA Factory2、数据准备3、快速开始4、LLaMA Board 可视化微调5、构建 DockerCUDA 用户&#xff1a;昇腾 NPU 用户&#xff1a;不使用 Docker Compose 构建CUDA 用户&#xff1a;昇腾 NPU 用户&#xf…

变阻器与电位器有什么区别?

变阻器和电位器都是可以改变电阻值的电子元件&#xff0c;它们在电路中的作用和调节方式有一定的相似性&#xff0c;但它们之间还是存在一些区别的。 1. 结构上的区别&#xff1a;变阻器主要由固定电阻体和可动滑片组成&#xff0c;通过滑动滑片来改变电阻体的电阻值。而电位器…

数据库(创建数据库和表)

目录 一&#xff1a;创建数据库 二&#xff1a;创建表 2.1&#xff1a;创建employees表 2.2&#xff1a;创建orders表 2.3&#xff1a;创建invoices表 一&#xff1a;创建数据库 mysql> create database mydb6_product; Query OK, 1 row affected (0.01 sec) mysql&g…

linux centos limits.conf 修改错误,无法登陆问题修复 centos7.9

一、问题描述 由于修改/etc/security/limits.conf这个文件中的值不当&#xff0c;重启后会导致其账户无法远程登录&#xff0c;本机登录。 如改成这样《错误示范》&#xff1a; 会出现&#xff1a; 二、解决 现在知道是由于修改limits.conf文件不当造成的&#xff0c;那么就…

智慧农业新纪元:解锁新质生产力,加速产业数字化转型

粮食安全乃国家之根本&#xff0c;“浙江作为农业强省、粮食生产重要省份&#xff0c;在维护国家粮食安全大局中肩负着重大使命。浙江粮食产业经济年总产值已突破4800亿元&#xff0c;稳居全国前列&#xff0c;然而&#xff0c;同样面临着规模大而不强、质量效益有待提升、数字…

JVM高频面试点

文章目录 JVM内存模型程序计数器Java虚拟机栈本地方法栈Java堆方法区运行时常量池 Java对象对象的创建如何为对象分配内存 对象的内存布局对象头实例数据对齐填充 对象的访问定位 垃圾收集器找到垃圾引用计数法可达性分析&#xff08;根搜索法&#xff09; 引用概念的扩充回收方…