Day01_特殊方法

特殊方法

又可以称为魔术方法,一般在类里面以__xx__存在的方法称为特殊方法

一、一副Python风格的纸牌

import collections
# 创建一个具名元组类,该类只有属性,而没有自定义的方法
Cards = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
    # ranks指代牌的大小
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    # suits指代牌的花色
    suits = "红桃 黑桃 梅花 方片"
    def __init__(self):
        # 生成扑克牌列表,共计52张牌
        self._cards = [Cards(rank, suit) for rank in self.ranks for suit in self.suits]
    # 特殊方法,可以通过len(对象)自动调用该方法
    def __len__(self):
        # 返回牌库大小
        return len(self._cards)
    # 特殊方法,对象[索引]自动调用该方法,有该方法的基础上,也可以实现for循环遍历
    def __getitem__(self, item):
        return self._cards[item]

1.1 通过Cards生成一个纸牌对象

beer_card = Cards('7', '梅花')
print(beer_card)
#Card(rank='7', suit='梅花')

1.2 __len__方法的使用

# 创建扑克牌对象
deck = FrenchDeck()
# len方法会自动调用对象的__len__方法,如果对象中没有实现__len__这一特殊方法,则使用len函数获取对象大小会报错
print(len(deck))

1.3 __getitem__方法的使用

# 创建扑克牌对象
deck = FrenchDeck()
# 通过索引回去对象中的某一项,会自动调用__getitem__方法,如果没有实现__getitem__则无法通过索引获取
card = deck[0]
print(card)
print('-------------------------------')
# 从序列中获取某一项(随机抽取),但是要去是序列,也就是可以通过索引获取内容的对象
from random import choice
# 从序列中随机抽取一项
card1 = choice(deck)
print(card1)
print('-------------------------------')
# 此处传入的是一个slice对象,item = slice(0, 12, None) 可以对序列进行切割(基于self._cards),也会自动调用__getitem__方法
cards = deck[0:12]
print(cards)
print('-------------------------------')
# 基于__getitem__方法,可以实现对对象的迭代(遍历)
for i in deck:
    print(i)
# 反向迭代    
for i in reversed(deck):
    print(i)

1.4 纸牌的排序

# 创建扑克牌对象
deck = FrenchDeck()
# 创建一个花色大小字典,用来针对花色做排序
suit_values = {'黑桃':4, '梅花':3, '红桃':2, '方片':1}
# 创建排序函数
def spades_high(card):
    # 获取牌面在扑克牌对象牌面中的位置
    rank_value = FrenchDeck.ranks.index(card.rank)
    # 公式: 牌面索引 * 4 + 花色大小
    return rank_value * len(suit_values) + suit_values[card.suit]
# 通过sorted进行排序,序列中的每个对象都会进行一次spades_high函数的运算,通过运算结果进行排序
for i in sorted(deck, key=spades_high):
    print(i)

二、 特殊方法是如何使用的

1. 特殊方法是交给Python解释器使用的,而不是自己
2. 特殊方法是隐式调用的,例如 for i in x: 其实在背后调用iter(x),接着调用x.__iter__(如果存在该方法)或者x.__getitem__(不存在__iter__)
3. 编程中大部分时间是用来实现特殊方法,而不是调用特殊方法,除了__init__外的特殊方法基本上都是通过内置函数来隐式调用的

三、 模拟数值类型

import math
class Vector:
    # 创建对象时需要传入两个参数,一个x,代表横坐标,一个y,代表纵坐标
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y
    # 特殊方法,可以在打印对象或调用str方法时自动调用该方法
    def __repr__(self):
        return f'Vector({self.x}, {self.y})'
    # 特殊方法,在调用abs(对象)时会自动调用该方法
    def __abs__(self):
        return math.hypot(self.x, self.y)
    # 特殊方法,在调用bool(对象)时会自动调用该方法
    def __bool__(self):
        # 判断坐标是否为(0,0) 不是则正确,是则错误
        return self.x != 0 or self.y != 0
    # 两个Vector对象使用+号时自动调用,+号前面为self,+号后面为other
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        # 此处返回的是一个新的Vector对象,原始对象的数值不会发生任何改变
        return Vector(x, y)
    # Vector * x , x在方法中只能是一个具体的数值,不能是对象
    def __mul__(self, other):
        # 此处返回的也是一个新的Vector对象,原始对象不会发生任何改变
        return Vector(self.x * other, self.y * other)

3.1 打印对象

# 创建一个向量对象
v1 = Vector(3, 5)
# 打印会自动调用__repr__方法,如果没有则会打印这个对象
print(v1)
# str函数也会自动去对象中寻找__str__或者__repr__方法
print(str(v1))

3.2 两个向量相加

# 创建两个向量对象
v1, v2 = Vector(3,4) , Vector(5, 6)
print(v1)
print(v2)
# id(对象) 获取对象在内存中的地址
print(id(v1))
print(id(v2))
print("-------------------------------")
v3 = v1 + v2
print(v3)
# 通过id函数可以看到v3是一个新的Vector对象
print(id(v1))
print(id(v2))
print(id(v3))

3.3 获取向量的绝对值

# 创建一个向量对象
v1 = Vector(3, 4)
# abs函数会自动调用对象中的__abs__方法
print(abs(v1))

3.4 判断向量是否是(0, 0)

# 创建4个向量对象
v1, v2, v3, v4 = Vector(0, 0), Vector(0,1), Vector(2, 0), Vector(1,1)
# 会自动调用对象的__bool__方法
print(v1, bool(v1))
print(v2, bool(v2))
print(v3, bool(v3))
print(v4, bool(v4))
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值