特殊方法的使用

特殊方法的使用

什么是特殊方法,在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 ...
相关推荐
nuclear20111 小时前
使用Python 在Excel中创建和取消数据分组 - 详解
python·excel数据分组·创建excel分组·excel分类汇总·excel嵌套分组·excel大纲级别·取消excel分组
Lucky小小吴1 小时前
有关django、python版本、sqlite3版本冲突问题
python·django·sqlite
GIS 数据栈2 小时前
每日一书 《基于ArcGIS的Python编程秘笈》
开发语言·python·arcgis
爱分享的码瑞哥2 小时前
Python爬虫中的IP封禁问题及其解决方案
爬虫·python·tcp/ip
傻啦嘿哟3 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
B站计算机毕业设计超人3 小时前
计算机毕业设计SparkStreaming+Kafka旅游推荐系统 旅游景点客流量预测 旅游可视化 旅游大数据 Hive数据仓库 机器学习 深度学习
大数据·数据仓库·hadoop·python·kafka·课程设计·数据可视化
IT古董3 小时前
【人工智能】Python在机器学习与人工智能中的应用
开发语言·人工智能·python·机器学习
湫ccc4 小时前
《Python基础》之pip换国内镜像源
开发语言·python·pip
hakesashou4 小时前
Python中常用的函数介绍
java·网络·python
菜鸟的人工智能之路4 小时前
极坐标气泡图:医学数据分析的可视化新视角
python·数据分析·健康医疗