特殊方法的使用

特殊方法的使用

什么是特殊方法,在Python中,如果一个方法的前后各有两个_横线,例如__len__方法,这样的方法就被称为特殊方法,有时也称为魔术方法双下划线方法

请不要将任意方法设置为特殊方法,不要乱用__*__

文章介绍

  1. 通过一个纸牌对象介绍了__len__方法和__item__方法的使用
  2. 通过一个向量对象介绍了__repr__方法和一些数值操作的特殊方法
  3. 主要说明了特殊方法的一个执行方式和特殊方法一览表。

1. 一摞Python风格的纸牌

通过纸牌类来详细说明__getitem__和__len__特殊方法的使用

python 复制代码
import collections
# 函数工厂,实现一个Card类,里面只用rank和suit这两个属性,没有其他方法
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
    # 生成2-10加JQKA的十四章牌面
    rank = [str(n) for n in range(2, 11)] + list('JQKA')
    # 生成 '黑桃','红桃','方片','梅花' 四种花色
    # split没有参数时将以空格作为分隔符
    suits = "heart spade diamonds clubs".split()

    def __init__(self):
        # 生成不包含大小王在内的52张卡片
        self._cards = [Card(rank, suit) for rank in self.rank for suit in self.suits]

    def __len__(self):
        print("__len__方法被调用了")
        return 52  # 必须返回一个integer,整数类型

    def __getitem__(self, item):
        # print(item)
        print("__getitem__方法被调用了")
        return self._cards[item]  # 返回索引对应的内容

if __name__ == "__main__":
    deck = FrenchDeck()
    print("1.打印扑克牌数量")
    print("扑克牌数量是:",len(deck))
    print("-"*11)
    print("2.获取牌堆中的第一张扑克牌")
    print("牌堆中的第一张是:", deck[0])
    print("-"*11)
    print("3.获取牌堆中的第三到第十张牌")
    # 如果此时打印__getitem__的item参数,会发现是slice(3, 11, None)这样的,这是在序列中进行切片操作的一个类
    print("第三到第十张牌分别是:", deck[3:11])
    print("-"*11)
    print("4.遍历整个牌库")
    for card in deck:
        print(card)
    print("-"*11)
    print("5.判断某张牌是否在牌堆中")
    card = Card('7', "heart")
    # 会遍历牌堆,如果发现对应数据则终止,否则遍历完
    print(card in deck)
cmd 复制代码
1.打印扑克牌数量
__len__方法被调用了
扑克牌数量是: 52
-----------
2.获取牌堆中的第一张扑克牌
__getitem__方法被调用了
牌堆中的第一张是: Card(rank='2', suit='heart')
-----------
3.获取牌堆中的第三到第十张牌
__getitem__方法被调用了
第三到第十张牌分别是: [Card(rank='2', suit='clubs'), Card(rank='3', suit='heart'), Card(rank='3', suit='spade'), Card(rank='3', suit='diamonds'), Card(rank='3', suit='clubs'), Card(rank='4', suit='heart'), Card(rank='4', suit='spade'), Card(rank='4', suit='diamonds')]
-----------
4.遍历整个牌库
__getitem__方法被调用了
Card(rank='2', suit='heart')
__getitem__方法被调用了
Card(rank='2', suit='spade')
__getitem__方法被调用了
Card(rank='2', suit='diamonds')
__getitem__方法被调用了
Card(rank='2', suit='clubs')
__getitem__方法被调用了
Card(rank='3', suit='heart')
__getitem__方法被调用了
....
-----------
5.判断某张牌是否在牌堆中
__getitem__方法被调用了
__getitem__方法被调用了
__getitem__方法被调用了
__getitem__方法被调用了
__getitem__方法被调用了
__getitem__方法被调用了
__getitem__方法被调用了
....
True

2. 模拟数值类型之向量类

通过向量类来介绍关于数值操作的特殊方法和打印对象的__repr__特殊方法

python 复制代码
import math

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

    def __repr__(self):
        print("__repr__方法被调用了")
        return f"Vector({self.x}, {self.y})"  # 这里的返回内容必须是字符串

    def __abs__(self):
        print("__abs__方法被调用了")
        return math.hypot(self.x, self.y)

    def __bool__(self):
        print("__bool__方法被调用了")
        return self.x != 0 or self.y != 0

    def __add__(self, other):
        print("__add__方法被调用了")
        print(f"self:{self}")
        print(f"other:{other}")
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, other):
        print("__mul__方法被调用了")
        print(f"self:{self}")
        print(f"other:{other}")
        return Vector(self.x * other, self.y * other)

if __name__ == "__main__":
    v1 = Vector(4, 8)
    v2 = Vector(3, 4)
    v3 = Vector(0, 0)
    print("1.打印v1对象")
    print(v1)
    print("-"*20)
    print("2.获取v2对象的绝对值")
    print(abs(v2))
    print("-"*20)
    print("3.获取v3对象的真假")
    print(bool(v3))
    print("-"*20)
    print("4.v1+v2")
    v1 += v2
    print(v1)
    print("-"*20)
    print("5.v2 * 5")
    v2 *= 5
    print(v2)
cmd 复制代码
1.打印v1对象
__repr__方法被调用了
Vector(4, 8)
--------------------
2.获取v2对象的绝对值
__abs__方法被调用了
5.0
--------------------
3.获取v3对象的真假
__bool__方法被调用了
False
--------------------
4.v1+v2
__add__方法被调用了
__repr__方法被调用了
self:Vector(4, 8)
__repr__方法被调用了
other:Vector(3, 4)
__repr__方法被调用了
Vector(7, 12)
--------------------
5.v2 * 5
__mul__方法被调用了
__repr__方法被调用了
self:Vector(3, 4)
other:5
__repr__方法被调用了
Vector(15, 20)

3.关于特殊方法的一些细节

1.特殊方法是如何执行的

首先要明确一点,特殊方法是给python的解释器调用的,例如一般不会通过my_objct.__len__的方式来调用__len__方法,而是通过len(my_object)来调用的(这里的my_object是你创建的对象)。

其次特殊方法的调用是隐式的,例如,for i in my_object,其实首先找的是my_object对象中的__iter__这个特殊方法,当对象中没有这个特殊方法时,才会去找__getitem__这个特殊方法,只不过解释器将这个流程隐藏起来了,导致看起来遍历会直接调用__getitem__一样。__str____repr__也是如此。

2. 特殊方法一览表

1. 特殊方法名称(不包含运算符)
分类 方法名称
字符串(字节)表示形式 repr str format bytes fspath
转换为数值 bool complex int float hash index
模拟容器 len getitem setitem delitem contains
迭代 iter aiter next anext reversed
可调用对象或执行协程 call await
上下文管理 enter exit aexit aenter
构造和析构实例 new init del
属性管理 getattr getattribute setattr delattr dir
属性描述符 get set delete set_name
抽象基类 instancecheck subclasscheck
类元编程 prepare init_subclass class_getitem mro_entries
2.运算符的符合和背后的特殊方法
运算符分类 符号 特殊方法
一元数值运算符 - + abs neg pos abs
比较运算符 < <= == != > >= lt le eq ne gt ge
算数运算符 + - * / // % @ divmod() round() ** pow() add sub mul truediv floordiv mod matmul divmod round pow
反向算数运算符 (交换算术运算符的操作数) radd ...
增量赋值算术运算符 += -= *= /= //= %= @= **= iadd isub imul itruediv ifloordiv imod imatmul ipow
按位运算符 & | ^ << >> ~ and or xor lshift rshift invert
反向按位运算符 (交换按位运算符的操作数) rand ...
增量按位运算符 &= ... iand ...
相关推荐
云动雨颤7 分钟前
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
python·单元测试
SunnyDays101127 分钟前
Python 实现 HTML 转 Word 和 PDF
python·html转word·html转pdf·html转docx·html转doc
跟橙姐学代码1 小时前
Python异常处理:告别程序崩溃,让代码更优雅!
前端·python·ipython
蓝纹绿茶2 小时前
Python程序使用了Ffmpeg,结束程序后,文件夹中仍然生成音频、视频文件
python·ubuntu·ffmpeg·音视频
mahuifa2 小时前
OpenCV 开发 -- 图像基本处理
人工智能·python·opencv·计算机视觉
一个java开发2 小时前
distributed.client.Client 用户可调用函数分析
大数据·python
eqwaak02 小时前
Matplotlib 动态显示详解:技术深度与创新思考
网络·python·网络协议·tcp/ip·语言模型·matplotlib
007php0073 小时前
某大厂MySQL面试之SQL注入触点发现与SQLMap测试
数据库·python·sql·mysql·面试·职场和发展·golang
CodeCraft Studio3 小时前
Excel处理控件Aspose.Cells教程:使用 Python 将 Pandas DataFrame 转换为 Excel
python·json·excel·pandas·csv·aspose·dataframe
flashlight_hi3 小时前
LeetCode 分类刷题:2563. 统计公平数对的数目
python·算法·leetcode