特殊方法的使用

特殊方法的使用

什么是特殊方法,在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 ...
相关推荐
PythonFun16 分钟前
Python批量下载PPT模块并实现自动解压
开发语言·python·powerpoint
炼丹师小米1 小时前
Ubuntu24.04.1系统下VideoMamba环境配置
python·环境配置·videomamba
GFCGUO1 小时前
ubuntu18.04运行OpenPCDet出现的问题
linux·python·学习·ubuntu·conda·pip
985小水博一枚呀2 小时前
【深度学习基础模型】神经图灵机(Neural Turing Machines, NTM)详细理解并附实现代码。
人工智能·python·rnn·深度学习·lstm·ntm
萧鼎4 小时前
Python调试技巧:高效定位与修复问题
服务器·开发语言·python
IFTICing4 小时前
【文献阅读】Attention Bottlenecks for Multimodal Fusion
人工智能·pytorch·python·神经网络·学习·模态融合
大神薯条老师4 小时前
Python从入门到高手4.3节-掌握跳转控制语句
后端·爬虫·python·深度学习·机器学习·数据分析
程序员爱德华4 小时前
Python环境安装教程
python
huanxiangcoco4 小时前
152. 乘积最大子数组
python·leetcode
萧鼎5 小时前
Python常见问题解答:从基础到进阶
开发语言·python·ajax