30. 面向对象高级编程

news2024/12/25 1:38:51

1. __solts__

正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性

from types import MethodType


class Student:
    def __init__(self):
        pass


def set_num(self, newnum):
    self.num = newnum


def set_score(self, score):
    self.score = score


# 为当前实例绑定属性num、实例方法set_num
# 注意, 仅仅是为当前实例
s1 = Student()
s1.num = 101
print(s1.num)
s1.set_num = MethodType(set_num, s1)
s1.set_num(102)
print(s1.num)

# 为了给所有实例都绑定属性和方法,可以直接在类上绑定
Student.name = "Zhang" # 在类上绑定属性name
s2 = Student()
s2.name = "Wang"
print(s2.name)

# 在类上绑定方法set_score
Student.set_score = set_score
s3 = Student()
s4 = Student()
s3.set_score(99)
print(s3.score)
s4.set_score(98)
print(s4.score)

在这里插入图片描述
通常情况下,上面的set_score方法可以直接定义在class中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。


__slots__的使用
但是,如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。
为了达到限制的目的,python允许在定义class的时候,定义一个特殊的__slots__变量来限制该class实例能添加的属性。接下来看下面的两个示例:demo1和demo2


# demo1, Student类实例只能动态绑定num和name属性, 否则报错
class Student:
    __slots__ = ('num', 'name')

    def __init__(self):
        pass


# 此时, 为实例s绑定属性num和name, 这是没有任何问题的;
# 但是为s绑定属性age, 此时就报错了, 因为age没有被放到__slots__里面去;
s = Student()
s.num = 101
s.name = 'Zhang'
# s.age = 100 # error

在这里插入图片描述


# demo2, 测试__slots__的继承性
class Student:
    __slots__ = ('num', 'name')

    def __init__(self):
        pass


class SonStudent(Student):
    # __slots__ = ()
    pass


# 但是注意, __slots__定义的属性仅仅对当前类实例起作用, 对继承的子类是不起作用的;
# 除非在子类中也定义__slots__, 这样, 子类实例允许定义的属性就是自身的__slots__加上父类的__slots__;
# 如果开启SonStudent中的__slots__, 那么运行将报错, 因为子类继承了父类的__slots__, 是不允许动态添加age属性的;
# 如果注释掉SonStudent中的__slots__, 那么运行将是OK的;
SonStudent().age = 100

在这里插入图片描述

2. @property

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是没办法对属性值进行验证,导致可以把成绩胡乱的写。

class Student:
    def __init__(self):
        pass

    def get_score(self):
        return self.score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError("the score must be an integer!")
        if value < 0 or value > 100:
            raise ValueError("the score must between 0 ! 100!")
        self.score = value


Student().set_score(60) # ok
Student().set_score(1000) # error

在这里插入图片描述
但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。
有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的python程序员来说,这是必须要做到的!
我们知道,装饰器(decorator)可以给函数动态添加功能吗。对于类的方法,装饰器一样起作用。python内置的@property装饰器就是负责把一个方法变成属性调用的。

class Student:
    # 要特别注意: 属性的方法名不要和实例变量重名.如果将下面的_score换成score, 那么将报错.
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError("the score must be an integer!")
        if value < 0 or value > 100:
            raise ValueError("the score must between 0 ! 100!")
        self._score = value


# 注意: 我们debug跟踪, 发现执行s.score=89时将会跳到@score.setter所修饰的函数里去;
# 执行print(s.score)时将会跳到@property所修饰的函数里去;
# 同时通过debug可知, 在实例化Student后, 实例化的对象已经有了一个score属性了;
s = Student()
s.score = 89  # 执行@score.setter修饰的方法
# print(s.score)  # 执行@score修饰的方法
s.score = 9999 # error

在这里插入图片描述
在这里插入图片描述

3. 定制类

看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在python中是有特殊用途的。
__slots__我们已经知道怎么用了,len()方法我们也知道是为了能让class作用于len()函数。
除此之外,python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类。

我们只需要在我们的类当中去重写它即可(重新实现它)
(1) 如果一个类想被用于for … in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象;然后,python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
(2) 要表现得像list那样按照下标取出元素(如list[0]),需要实现__getitem__()方法。
(3) 一个对象实例可以有自己的属性和方法,当我们调用实例方法时,我们用instance.method()来调用。能不能直接在实例本身上调用呢?在python中,答案是肯定的。任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用
(4) 正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。要避免这个错误,除了可以加上该属性外;python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性

# demo
# 此demo中我们可以认识__len__,__str__,__repr__,__iter,__next__,__getitem__等特殊函数.
# 定义一个Student类, 而后定义一个Vector类, Vector类中定义一个list, 而list中就用Student来填充,
# 
class Student:
    def __init__(self, num, name):
        self.num = num
        self.name = name

    def __len__(self):
        return 2

    def __str__(self):
        return 'Student(%d,%s)' % (self.num, self.name)

    __repr__ = __str__

    def __call__(self, *args, **kwargs):
        print('>>>>>>>>call myself.')

    def __getattr__(self, item):
        if item == 'score':
            return 100

class Vector:
    def __init__(self, list, size):
        self.list = list
        self.size = size
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        seq = self.index
        if self.index >= self.size:
            raise StopIteration()
        self.index += 1
        return self.list[seq]

    def __getitem__(self, item):
        if item < len(self.list):
            return self.list[item]


s = Student(101, 'Zhang')
print(len(s)) # __len__
print(s) # __str__
Student(101, 'Wang')() # __call__
print(s.score) # __getattr__

print('----------------------------')
ls = [
    Student(101, 'Zhang'),
    Student(102, 'Wang'),
    Student(103, 'Li'),
    Student(104, 'Zhao')
]
v = Vector(ls, len(ls))
for stu in v:
    print(stu)

print('----------------------------')
print(v[2])
print(v[3])

在这里插入图片描述

更多请参考官网,此处抛砖引玉:
https://docs.python.org/3/reference/datamodel.html#special-method-names

4. 枚举类

当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如:

BIG = 100
MIDDLE = 60
SMALL = 10

好处是简单,缺点是类型是int,并且仍然是变量。
更好的方法是为这样的枚举类型定义一个class类型,然后每个常量都是class的一个唯一实例。python提供了Enum类来实现这个功能,如下所示:

from enum import Enum

Size = Enum('Size', ('BIG', 'SMALL', 'MIDDLE'))
# value属性则是自动赋给成员的int常量,默认从1开始计数.
for name, member in Size.__members__.items():
    print(name, '=>', member, ',', member.value)

在这里插入图片描述
如果需要更精确地控制枚举类型,可以从Enum派生出自定义类,如下所示:

from enum import Enum, unique


# @unique装饰器可以帮助我们检查保证没有重复值
@unique
class Weekday(Enum):
    Sun = 0  # Sun的value被设定为0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6


# 可用以下方法进行访问
print(Weekday.Mon)
print(Weekday['Tue'])
print(Weekday.Tue.value)
print(Weekday(1))

在这里插入图片描述

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

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

相关文章

OSCP_VULHUB_Matrix3

文章目录简介扫描ida汇编ssh登录/提权简介 下载地址&#xff1a; https://download.vulnhub.com/matrix/Machine_Matrix_v3.ova 环境&#xff1a; VMware 16虚拟机软件 Matrix3靶机IP地址&#xff1a;192.168.132.145 Kali的IP地址&#xff1a;192.168.132.139 Matrix3靶机与…

Shiro基础知识与集成应用

1、Shiro可以完成: 【认证、授权、加密、会话管理】、与Web集成、缓存等2、特点: 易于使用、全面、灵活、强力支持Web、兼容性强、社区支持 外部观看内部观看3、 登录认证:1)身份验证&#xff1a;一般需要提供如身份ID等一些标识信息来表明登录者的身份&#xff0c;如提供email…

Druid(德鲁伊)数据库连接池

文章目录一.数据库连接池的必要性(一).传统数据库连接模式的的步骤(二).传统数据库连接模式存在的问题二.数据库连接池技术(一).数据连接池的思想&#xff1a;(二).数据库连接池的任务&#xff1a;(三).数据库连接池的规模&#xff1a;(四).工作原理&#xff1a;(五).数据库连接…

5 -【Faster R-CNN】之 AnchorGenerator 代码精读

【Faster R-CNN】之 AnchorGenerator 代码精读1、anchor 的 size 和 aspect_ratios2、计算以中心坐标为 (0, 0) 的 anchor3、将 anchor 映射到原图上4、代码汇总anchor 的作用&#xff1a;anchor 是用来做辅助计算的&#xff0c;用于和 &#xff08;上节课说的&#xff0c;由RP…

共享模型之内存(一)

1.Java内存模型 1>.JMM即Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等; 2>.JMM体现在以下几个方面: ①.原子性 - 保证指令不会受到线程上下文切换的影响; ②.可见性 - 保证指令不会受cpu缓存的影响; ③.有序…

大型会场活动线上保障方案

背景 为保证活动上线后的质量&#xff0c;大型会场活动上线前通常会预设一些线上可能出现的问题&#xff0c;提前制定保障方案。 这些与活动保障相关的问题可能与App端上的容器环境有关&#xff0c;也可能与大盘用户设备特征有关&#xff0c;问题的处理方案会影响活动的线上效…

《啊哈算法图的遍历》(14张图解)

目录 前言 一&#xff0c;dfs和bfs是什么 二&#xff0c;城市地图--图的深度优先遍历 三&#xff0c;最少转机--图的广度优先遍历 前言 &#x1f33c;说爱你&#xff08;超甜女声版&#xff09; - 逗仔 - 单曲 - 网易云音乐 1月22日一个女孩加了我&#xff0c;她和我聊音…

adb常用指令合集

adb文件管理指令 1.复制设备里的文件到电脑 adb pull <设备里的文件路径> [电脑上的目录] 电脑上的目录 参数可以省略&#xff0c;默认复制到当前目录 例&#xff1a;adb pull /data/tsplogtool /home/jxq/文档/场景魔方 2.复制电脑里的文件到设备 adb push <电脑上的…

浅谈未来10年IT行业的变局与抉择,一文带你认识元宇宙

一. 困局据国家就业部门最新统计数据报告&#xff0c;2022年应届毕业生的数量首次突破1000万大关。其中研究生达到130万&#xff0c;985、211等名校毕业生75万&#xff0c;普通本科毕业生470万&#xff0c;专科生460万&#xff0c;另外还有几十万的归国留学生&#xff01;但这还…

《从0开始学大数据》之Spark性能优化案例

基于软件性能优化原则和 Spark 的特点&#xff0c;Spark 性能优化可以分解为下面几步。 性能测试&#xff0c;观察 Spark 性能特性和资源&#xff08;CPU、Memory、Disk、Net&#xff09;利用情况。分析、寻找资源瓶颈。分析系统架构、代码&#xff0c;发现资源利用关键所在&a…

【前端】Vue项目:旅游App-(17)home:页面滚动显示搜索栏、节流、时间同步

文章目录目标过程与代码页面滚动到目标位置显示搜索框优化&#xff1a;节流搜索栏显示时间同步效果总代码修改或添加的文件search-bar.vueuseScroll.jsstore的main.jsformatDate.jshome.vue参考本项目博客总结&#xff1a;【前端】Vue项目&#xff1a;旅游App-博客总结 目标 …

HDFS文件浏览器功能OOM排查

现象描述 涉及HDFS文件浏览器的某个功能运行一段时间后会出现OOM的情况 错误日志如下&#xff1a; service.log.2023-02-01-0.log:java.lang.OutOfMemoryError: Java heap space排查过程 需要查看dump文件排查一下造成OOM的原因 查看jvm参数如下&#xff1a; java -Duser.t…

一文讲明Docker的基本使用,常见Docker命令使用 、Docker的安装使用等【详细说明+图解+概念+实践】

一个混迹于Github、Stack Overflow、开源中国、CSDN、博客园、稀土掘金、51CTO等 的野生程序员。 目标&#xff1a;分享更多的知识&#xff0c;充实自己&#xff0c;帮助他人 GitHub公共仓库&#xff1a;https://github.com/zhengyuzh 以github为主&#xff1a; 1、分享前端后端…

【Python合集系列】2023兔年吉祥,新的一年希望放烟花的人跟看烟花的人都能平平安安哦~(附多种源码)

前言 希望放烟花的人跟看烟花的人都能平平安安。 &#x1f440; NICE TO MEET YOU :)&#x1f319; 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 ​哈喽&#xff01;我是木子&#xff0c;新…

设计模式之适配器模式,以C++为例。

今天来盘一盘适配器模式。适配器&#xff1a;顾名思义&#xff0c;就是让原本不合适的变为合适的&#xff0c;好似一对男女&#xff0c;没有中间的媒婆是不会互相了解的&#xff0c;好像不太恰当&#xff0c;就这么解释吧&#xff0c;只有有了这个中间人他们才会产生联系&#…

智能驾驶开启高精定位新赛道,这家供应商正加码布局海外市场

高工智能汽车研究院监测数据显示&#xff0c;2022年1-11月中国市场乘用车前装标配搭载NOA交付达到18.38万辆&#xff0c;同比增长91.86%&#xff1b;同时&#xff0c;NOA搭载的车型配置价格还在不断下滑&#xff0c;正在把NOA的配置拉至15万元价格区间。 而作为高精定位&#x…

面向对象——static(静态)Math类自定义工具类代码块

目录 static&#xff08;静态&#xff09;关键字 static的注意事项 static的优点和缺点 应用场景 自定义工具类 代码块 static&#xff08;静态&#xff09;关键字 static是一个修饰符&#xff0c;用于修饰成员&#xff08;成员变量 、成员方法&#xff09;static的特点…

Redis处理client连接数过多,大量空闲链接无法释放问题

打开redis命令终端&#xff0c;输入&#xff1a; client list 查看连接数&#xff0c;用于返回所有连接到服务器的客户端信息和统计数据 参数解析&#xff1a; id: 唯一的64位的客户端ID(Redis 2.8.12加入)。 addr: 客户端的地址和端口 fd: 套接字所使用的文件描述符 age…

python真的很骚可惜你不会

python基本语法 &#x1f4d2;博客主页&#xff1a; 微笑的段嘉许博客主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由微笑的段嘉许原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1f334;2023年1月日3…

redis分布式缓存

文章目录一、redis持久化1.1.RDB持久化1.1.1.执行时机1.1.2.RDB原理1.1.3.小结1.2.AOF持久化1.2.1.AOF原理1.2.2.AOF配置1.2.3.AOF文件重写1.2.4.小结1.3.RDB与AOF对比二、Redis主从集群2.1.集群结构2.2.准备实例和配置2.3.启动2.4.开启主从关系2.5.测试2.6.主从数据同步原理2.…