流畅的Python学习笔记(1)特殊方法

文章介绍了Python的collections模块,特别是namedtuple和OrderedDict,展示了如何使用它们来增强Python内置数据类型的功能。通过示例创建了Card类和FrenchDeck类,讨论了特殊方法如_len_和_getitem_在自定义类中的作用,并提到了优化代码性能的重要性。此外,还提及了特殊方法用于响应运算符的编程技巧。
摘要由CSDN通过智能技术生成
import collections

        Python的集合(collections)模块,为很多用其他方法很难实现的场景提供了解决方案。他其实是Python高级特性的一个相关应用。collections在我看来给Python内置的数据类型和方法的基础提供了额外的高性能数据类型,比如基础的字典是不支持顺序的,collections模块的OrderedDict类构建的字典可以支持顺序,能简化Python代码,提高Python代码逼格和效率

Card = collections.namedtuple('Card', ['rank', 'suit'])

        这创建了一个叫做Card的类,他有两个属性rank和suit。这个类目前来看只有属性并没有自定义方法。

class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for rank in self.ranks for suit in self.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        return self._cards[position]

        之前创造的Card类表示的是单张纸牌,那么现在创造的Frenchdeck就是表示的一摞纸牌。ranks创建了一个列表['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'],suits也创建了一个列表['spades', 'diamonds', 'clubs', 'hearts'],split()的作用是拆分字符串。之后迭代生成52张card,也就是self._cards。得益于_len_和_getitem_我们可以知道实例的长度以及随机抽取一张卡牌。

suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)

def spades_high(card):
    rank_value = FrenchDeck.ranks.index(card.rank)
    return rank_value * len(suit_values) + suit_values[card.suit]
deck = FrenchDeck()
for card in sorted(deck, key=spades_high):
    print(card)

        为了让扑克牌大小有顺序,我们定义了不同suit的大小。定义了一个sapdes_high函数,返回了输入card所对应的值,这个值=面值的大小*4+card的suit。进而进行一个升序排列。

        全代码如下:

import collections
import random
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for rank in self.ranks for suit in self.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        return self._cards[position]

suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
print(len(suit_values))
def spades_high(card):
    rank_value = FrenchDeck.ranks.index(card.rank)
    return rank_value * len(suit_values) + suit_values[card.suit]
deck = FrenchDeck()
for card in sorted(deck, key=spades_high):
    print(card)

        我们要注意的是,在这个Frenchdeck类里的_len_和_getitem_属于我们自定义的特殊方法,python本身并不存在他存在的是len()和list[]。对于我们菜鸟来说,调用特殊方法要比调用内置函数慢的多,内置函数类似于抄近路。在Python中有许多的特殊方法,但是他是隐式调用的,例如用for对x进行迭代,实际上是背后用iter(x),再往背后看是用x._iter_()。所以我们如果需要调用特殊方法真不如直接调用相应内置函数,又快又准(目前我这么认为)。

        还有特殊方法可以让咱们响应各种运算符,例如二维向量:

import math
# Python高效编程

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

    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)

    def __sub__(self, other):
        x = self.x - other.x
        y = self.y - other.y
        return Vector(x, y)

    def __abs__(self):
        return math.sqrt(self.x ** 2 + self.y ** 2)

    def __bool__(self):
        return bool(self.x or self.y)

    def __mul__(self, times):
        return Vector(self.x * times, self.y * times)

    def __repr__(self):
        return 'Vector({}, {})'.format(self.x, self.y)

        创建一个二维向量类,可以让他们之间实现加减取模数乘等运算。

v1 = Vector(3, 4)
v2 = Vector(4, 5)
print(v1+v2)
print(v1-v2)
print(abs(v1))
print(v1*3)

        这些6个特殊方法在类的内部,不能直接调用,通常被Python解释器调用。_repr_是为了获取对象的字符串表现形式,如果不定义,结果如下:

print(v1)
>> <__main__.Vector object at 0x000001E3099AEFD0>

        _bool_方法,如果向量模为0,则返回false,若不为0则返回true。

        我们如果用Python内置类型的实例时候用内置函数例如len(),那么运行速度很快,但是如果是自定义对象,用特殊方法_len_既满足了速度的要求,又满足了语言的一致性

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值