特殊方法的使用

特殊方法的使用

什么是特殊方法,在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 ...
相关推荐
q5673152321 分钟前
在 Bash 中获取 Python 模块变量列
开发语言·python·bash
是萝卜干呀22 分钟前
Backend - Python 爬取网页数据并保存在Excel文件中
python·excel·table·xlwt·爬取网页数据
代码欢乐豆23 分钟前
数据采集之selenium模拟登录
python·selenium·测试工具
狂奔solar1 小时前
yelp数据集上识别潜在的热门商家
开发语言·python
Tassel_YUE1 小时前
网络自动化04:python实现ACL匹配信息(主机与主机信息)
网络·python·自动化
聪明的墨菲特i1 小时前
Python爬虫学习
爬虫·python·学习
努力的家伙是不讨厌的2 小时前
解析json导出csv或者直接入库
开发语言·python·json
云空2 小时前
《Python 与 SQLite:强大的数据库组合》
数据库·python·sqlite
凤枭香3 小时前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
测试杂货铺3 小时前
外包干了2年,快要废了。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展