Python笔记001-类的特殊方法

以下是我学习《流畅的Python》后的个人笔记,现在拿出来和大家共享,希望能帮到各位Python学习者。

首次发表于: 微信公众号:科技老丁哥,ID: TechDing,敬请关注。

本篇主要知识点:

  1. 类的特殊方法(一般都在前后带有两个下划线,比如__len__和__getitem__),其存在的目的是被Python解释器调用,而不是类的对象来调用。

  2. 对于自定义的类,一般无法体现出Python语言的核心特性,比如迭代和切片等,但是可以通过在自定义类中复写__len__和__getitem__等特殊方法来实现这些核心功能。对象调用len()方法时实际上Python解释器调用的是自定义类中的__len__,而对某个对象进行切片获取元素,或者排序时,Python解释器调用的是复写的__getitem__。

  3. 在自定义类中复写__getitem__至少可以获得1.类对象的切片和获取元素,2.对类对象进行迭代,可以是顺序迭代也可以是逆序迭代,3.对类对象进行重新排序,4.对类对象进行随机抽样等多种功能。

  4. 类的特殊方法有多达100种,作为示例,此处仅仅总结了加减乘除等的复写方法,并将所有特殊方法都整理成相关表格,便于后续复写某些特殊方法时作为参考。

1. 特殊方法示例

这些特殊方法长得比较奇怪,那是因为它提醒用户,不要轻易调用这些方法,因为它基本上是Python解释器专用。

比如下面先建立一整副纸牌,它包含有一个属性_cards,这个一个list,包含有52个Card对象。在复写了__len__和__getitem__方法之后,就可以直接获取到这个_cards属性的总长度和对其进行排序,切片来获取某几张纸牌。

from collections import namedtuple
Card=namedtuple('Card', ['rank', 'suit']) # 单张纸牌类class FrenchDeck: # 一副纸牌,包含4种花色,每种13种数字ranks = [str(n) for n in range(2, 11)] + list('JQKA') # 13种数字suits = 'spades diamonds clubs hearts'.split() # 四种不同花色:黑桃,方块,梅花,红桃def __init__(self):self._cards = [Card(rank, suit) for suit in self.suitsfor rank in self.ranks]# _cards属性是所有纸牌的集合,一个list, 包含4种花色共52张牌def __len__(self):# 类FrechDeck的特殊方法:会计算所有纸牌的张数,即52return len(self._cards)def __getitem__(self, position):# 类FrechDeck的特殊方法:从52张牌获取第position张牌return self._cards[position]
复制代码

构建一副纸牌后,我们想知道里面有多少张牌,或者想知道第1张,第10张,最后一张纸牌分别是什么:

## 通过len()获取deck中一共有多少张牌
deck=FrenchDeck()
print(len(deck)) # 52
## 通过切片方法获取某个位置的牌
print(deck[0]) # Card(rank='2', suit='spades')
print(deck[10]) # Card(rank='Q', suit='spades')
print(deck[-1]) # Card(rank='A', suit='hearts')
复制代码

如果没有复写__len__函数,在len(deck)时会报错:TypeError: object of type 'FrenchDeck' has no len().

同理,如果没有复写__getitem__方法,在deck[0]时报错:TypeError: 'FrenchDeck' object does not support indexing

可以对deck进行索引来获取某一个位置的纸牌,那么也就可以通过切片来获取一个批次,符合一定条件的纸牌,比如下面获取最后三张牌和牌面全是A的牌。

print(deck[-3:]) # 获取最后三张牌
print(deck[12::13]) # 获取全是A的牌,间隔型切片
复制代码

同理,复写了__getitem__方法后,就可以对deck对象进行迭代,不管是顺序迭代还是逆序迭代都可以。

# 顺序迭代
for card in deck[:10]:  # 只打印最前面的10张牌print(card)# 逆序迭代
for card in reversed(deck[-10:]):  # 只打印最后面的10张牌print(card)
复制代码

还可以判断某张牌是否存在于该副牌内:

## 判断某张牌是否存在于该副牌内:
print(Card('Q', 'hearts') in deck) # True
print(Card('Z', 'clubs') in deck) # False
复制代码

有了__getitem__方法,就可以对所有纸牌进行排序操作,此处我们排序的规定是:梅花2最小,方块2次之,红桃2,黑桃2,梅花3.。。这种形式,所以要自定义一个排序方法,这个方法返回一个整数,代表每张牌的大小,那么最小的梅花2就是0,最大的黑桃A就是51。

## 使用自定义方法对所有纸牌进行重新排序
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0) # 将花色转换为数值
def spades_high(card):rank_value = FrenchDeck.ranks.index(card.rank) # 获取某张牌的数字return rank_value * len(suit_values) + suit_values[card.suit]# 将某张牌的数字和花色换成整数返回for card in sorted(deck, key=spades_high):  # 按照自定义方法spades_high得到的整数进行排序print(card)
复制代码

小结一下:自定义类通过复写__getitem__方法,可以获得多种原来不存在的功能:比如切片功能,索引功能,还可以判断某个对象是否存在于类对象列表中,还可以对类对象进行迭代操作和排序操作。

2. 特殊方法的使用

对于自定义的类型,使用这些特殊方法可以使得他们的表现具有某些Python核心功能,在你对这些自定义类型进行操作时,比如len(deck)时,Python解释器会去找deck类的__len__方法。

而Python内置的类型,比如list, str, tuple等,Python解释器则直接抄近路,会直接返回PyVarObject里的Ob_size属性,这是一个长度可变的C语言结构体,所以速度要比调用__len__方法快得多。

你自己对这些特殊方法的使用频率会很低,因为都是Python解释器自动调用,只有类定义时的__init__方法例外。

2.1 自定义加减乘除功能

class Person:def __init__(self,name,age,score):self.name=nameself.age=ageself.score=scoredef __add__(self,other):# 此处仅仅是将得分相加return self.score+other.scoredef __sub__(self,other):# 此处将得分相减return self.score-other.scoredef __mul__(self,other):# 此处将两个的年龄相乘return self.age*other.agedef __truediv__(self,other):# 将两个的得分相除return self.score/other.score
复制代码

这个自定义类Person复写了加减乘除方法,根据需要对里面的属性进行算术操作,那么就可以用符号+,-,*,/等进行操作,比如:

P1=Person('Jack',20,90)
P2=Person('Rose',18,60)
print(P1+P2) # 150
print(P1-P2) # 30
print(P1*P2) # 360
print(P1/P2) # 1.5
复制代码

2.2 自定义print后的形式

还有一个非常常用的特殊函数:__repr__,它决定了print被直接调用后结果表现形式。

class Person:def __init__(self,name,age,score):self.name=nameself.age=ageself.score=scoredef __repr__(self):return 'Person(name={},age={},score={})'.format(self.name,self.age,self.score)P1=Person('Jack',20,90)
print(P1) # Person(name=Jack,age=20,score=90)
复制代码

如果没有复写__repr__,在用print(P1)时,会得到内存地址信息,人眼无法判断出具体内容,复写之后,就可以按照我们想要的形式直接print。

3. 特殊方法汇总

Python内置的特殊方法有将近一百种,其中有很多是实现算数运算,位运算和比较操作的,下面将这些方法的意义总结如下:

下面的整理于:CSDN: Python中特殊方法的分类与总结

所以,如果自定义类想实现某方面的功能,可以参考上面的表格来逐一实现即可。

首次发表于: 微信公众号:科技老丁哥,ID: TechDing,敬请关注。

本文所有代码都已经上传到我的github,欢迎下载

参考资料:

  1. 《流畅的Python》,Luciano Ramalho (作者) 安道 , 吴珂 (译者)。

  2. CSDN:Python中特殊方法的分类与总结

转载于:https://juejin.im/post/5cf66aafe51d45599e019d6b

Python笔记001-类的特殊方法相关推荐

  1. 初学者python笔记(类的装饰器、property方法、元类)

    文章目录 上下文协议管理 类的装饰器基本原理 property方法的巧用 利用描述符自定制property property下的setter与deleter Python的元类 元类的概念 自定义元类 ...

  2. 初学者python笔记(类的继承与多态---详解)

    文章目录 一.类的组合与继承的区别 二.类的继承 1.继承的功能分析 2.类的继承之派生.接口继承 3.用接口模块abc来实现接口继承 4.使用接口继承的好处 5.类的继承顺序 6.在子类中调用父类的 ...

  3. 初学者python笔记(列表的食用方法)

    本篇是关于可迭代对象中的列表一些相关使用方法的记录. 可迭代对象简单描述:可以被for循环执行的对象(字符串,列表,元组,字典-) input()方法接收的其实只是字符串 a = input(&quo ...

  4. 第8.15节 Python重写自定义类的__repr__方法

    一. 引言 前面两节分别介绍了Python类中的__str__和__repr__方法的作用和语法,所有新式类都支持这两个方法,因为object类实现了这两个方法,但实际上各位开发者在自定义类的过程中, ...

  5. python:掌握类的基本方法。定义一个Circle类,根据圆的半径求周长和面积。 再由Circle类创建2个圆对象,其半径分别为5和10,要求输出各自的周长和面积

    掌握类的基本方法.定义一个Circle类,根据圆的半径求周长和面积. 再由Circle类创建2个圆对象,其半径分别为5和10,要求输出各自的周长和面积 请在[python数据分析之禅]gzh后台,回复 ...

  6. 《手把手陪您学Python》42——类的魔法方法

    在上一篇<手把手陪您学Python>41--类方法与实例方法中,我们引入了类方法的概念,并介绍了类方法与实例方法在语法规则和引用方面的差异.今天,我们将会继续介绍实例方法的应用,并介绍一种 ...

  7. [python笔记]八.类

    一.创建和使用类 1)创建类 eg: class Dog():def __init__(self, name, age):self.name = nameself.age = agedef sit(s ...

  8. 《Java 核心技术卷1 第10版》学习笔记------ Object类的 hashCode 方法

    散列码( hash code ) 是由对象导出的一个整型值.散列码是没有规律的.如果 x 和 y 是两个不同的对象, x.hashCode( ) 与 y.hashCode( ) 基本上不会相同. 在表 ...

  9. 《Java 核心技术卷1 第10版》学习笔记------Object类的 equals 方法

    Object 简述 Object 类是 Java 中所有类的始祖, 在 Java 中每个类都是由它扩展而来的. 在 Java 中, 只有基本类型 ( primitive types) 不是对象, 例如 ...

  10. python创建person类用printinfo方法_python高级练习题代码

    一. 1.创建Person类,属性有姓名.年龄.性别,创建方法printInfo,打印这个人的信息 2.创建Student类,继承Person类,属性有学院college ,班级class,重写父类p ...

最新文章

  1. CCF真题 201312-2 ISBN号码
  2. usb PHY linux驱动
  3. 10 张令人喷饭的程序员漫画
  4. python用线性回归预测股票价格
  5. python2和python3的默认编码_Python2和Python3中的字符串编码问题解决
  6. jq写的项目如何部署到静态服务器_如何把前端项目部署到服务器
  7. JIRA状态为任务结束,但是解决结果为未解决相关配置
  8. 《面向模式的软件体系结构2-用于并发和网络化对象模式》读书笔记(10)--- 接受器 - 连接器...
  9. 学科分类号查询 计算机工程,学科分类与代码分类号查询.doc
  10. Android 四大组件面试
  11. 自主导航:赋予移动机器人智能感知与运动的能力
  12. C++基础习题(计算三角形斜边)
  13. 51中程序存储器和数据存储器
  14. html5图片自动滑动,超简单的图片左右切换滑动
  15. 水滴IP告诉你,IP地址是如何划分的
  16. 为什么把文字图片放大后有一圈彩色的像素方块,而不是纯黑色的
  17. 汽车通信脉冲电子 100Base-T1 汽车|以太网共模扼流圈
  18. 原始传奇显示区名的服务器,《原始传奇》新人新区需要了解的一些问题
  19. vue3学习笔记(ref, reactive, setup, hook...)
  20. 简单登录功能(一)token的使用

热门文章

  1. db2配置、db和dbm
  2. 附录E-分贝(dB和dBm)的理解
  3. python --爬虫 --下载小说
  4. ABAP如何获取当前月的第一天和最后一天
  5. 信阳市的计算机本科学校,郭华平 - 信阳师范学院 - 计算机与信息技术学院
  6. NIOS II入门学习笔记【一】--- NIOS II软核处理器开发入门
  7. 防火墙基本概念及分类
  8. 孪生网络 应用_数字孪生照进现实,Unity如何打造数字世界的基础设施?
  9. html css blockquote,3个Blockquote的css样式【css3实现】
  10. eclipse SWT 中实现工程图标最小化到托盘,并只能右键托盘图标选择关闭