Python 之特殊方法(魔术方法)

199 阅读4分钟

什么是 Python 特殊方法?

Python3 中的特殊方法是以 双下划线开头和结尾的方法 ,也被称为 魔术方法 或者 魔法方法。这些方法可以用来定制类的行为,例如实现类的比较、运算符重载、属性访问等。

特殊方法的定义如下:

class MyClass:
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

    def __str__(self):
        return f'MyClass({self.arg1}, {self.arg2})'

    def __eq__(self, other):
        return self.arg1 == other.arg1 and self.arg2 == other.arg2

在上面的例子中,我们定义了一个名为 MyClass 的类,并实现了 __init____str____eq__ 三个特殊方法。

其中,__init__ 方法是初始化方法,在创建对象时调用;__str__ 方法返回对象的字符串表示形式,可以通过 print 函数打印;__eq__ 方法实现对象的等于比较,可以使用 == 运算符。

通过实现这些特殊方法,我们可以对类进行更加细致的定制,让其行为更符合我们的需求。

特殊方法是如何调用的

要明确的是:特殊方法是给解释器调用的,不是我们开发自己,也就是没有 my_object.__len__() 这种写法,正确的写法是: len(my_object) .

Python 解释器调用特殊方法来执行基本对象操作,特殊方法通常由特殊语句触发 。例如:特殊方法__getitem__

__getitem__ 是 Python3 中的一个特殊方法,用于实现对象的索引操作。当我们使用 [] 运算符访问对象时 ,Python 会 自动调用 该对象的 __getitem__ 方法来获取对应的值。

以下是一个简单的例子:

class MyList:
    def __init__(self, data):
        self.data = data

    def __getitem__(self, index):
        return self.data[index]

在上面的例子中,我们定义了一个名为 MyList 的类,它包含一个属性 data,并实现了 __getitem__ 方法。当我们使用 [] 运算符访问 MyList 对象时,Python 会自动调用 __getitem__ 方法,并将索引作为参数传递给该方法。

例如,我们可以这样使用 MyList 类:

my_list = MyList([1, 2, 3, 4, 5])
print(my_list[2])  # 输出 3

在上面的代码中,我们创建了一个 MyList 对象,并使用 [] 运算符访问该对象的第三个元素。由于 MyList 类实现了 __getitem__ 方法,Python 会自动调用该方法,并返回对应的值。因此,上面的代码会输出 3

通过实现 __getitem__ 方法,我们可以让自定义的类支持索引操作,从而更加方便地访问对象的属性。

一个例子

import collections

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 suit in self.suits
                                      for rank in self.ranks]
    
    def __len__(self):
        return len(self._cards)
    
    def __getitem__(self,position):
        return self._cards[position]

if __name__=='__main__':
    beer_card = Card("7","diamonds")

    print(beer_card)

    deck = FrenchDeck()

    print(len(deck))

    print(deck[0])
    print(deck[-1])

    from random import choice
    print(choice(deck))

    print(deck[:3])
    print(deck[12::13])

    for card in deck:
        print(card)
    
    for card in reversed(deck):
        print(card)
> 
> python3 FrenchDeck.py
Card(rank='7', suit='diamonds')
52
Card(rank='2', suit='spades')
Card(rank='A', suit='hearts')
Card(rank='K', suit='diamonds')
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
Card(rank='5', suit='spades')
Card(rank='6', suit='spades')
Card(rank='7', suit='spades')
Card(rank='8', suit='spades')
Card(rank='9', suit='spades')
Card(rank='10', suit='spades')
Card(rank='J', suit='spades')
Card(rank='Q', suit='spades')
Card(rank='K', suit='spades')
Card(rank='A', suit='spades')
Card(rank='2', suit='diamonds')
Card(rank='3', suit='diamonds')
Card(rank='4', suit='diamonds')
Card(rank='5', suit='diamonds')
Card(rank='6', suit='diamonds')
Card(rank='7', suit='diamonds')
Card(rank='8', suit='diamonds')
Card(rank='9', suit='diamonds')
Card(rank='10', suit='diamonds')
Card(rank='J', suit='diamonds')
Card(rank='Q', suit='diamonds')
Card(rank='K', suit='diamonds')
Card(rank='A', suit='diamonds')
Card(rank='2', suit='clubs')
Card(rank='3', suit='clubs')
Card(rank='4', suit='clubs')
Card(rank='5', suit='clubs')
Card(rank='6', suit='clubs')
Card(rank='7', suit='clubs')
Card(rank='8', suit='clubs')
Card(rank='9', suit='clubs')
Card(rank='10', suit='clubs')
Card(rank='J', suit='clubs')
Card(rank='Q', suit='clubs')
Card(rank='K', suit='clubs')
Card(rank='A', suit='clubs')
Card(rank='2', suit='hearts')
Card(rank='3', suit='hearts')
Card(rank='4', suit='hearts')
Card(rank='5', suit='hearts')
Card(rank='6', suit='hearts')
Card(rank='7', suit='hearts')
Card(rank='8', suit='hearts')
Card(rank='9', suit='hearts')
Card(rank='10', suit='hearts')
Card(rank='J', suit='hearts')
Card(rank='Q', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='A', suit='hearts')
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
Card(rank='J', suit='hearts')
Card(rank='10', suit='hearts')
Card(rank='9', suit='hearts')
Card(rank='8', suit='hearts')
Card(rank='7', suit='hearts')
Card(rank='6', suit='hearts')
Card(rank='5', suit='hearts')
Card(rank='4', suit='hearts')
Card(rank='3', suit='hearts')
Card(rank='2', suit='hearts')
Card(rank='A', suit='clubs')
Card(rank='K', suit='clubs')
Card(rank='Q', suit='clubs')
Card(rank='J', suit='clubs')
Card(rank='10', suit='clubs')
Card(rank='9', suit='clubs')
Card(rank='8', suit='clubs')
Card(rank='7', suit='clubs')
Card(rank='6', suit='clubs')
Card(rank='5', suit='clubs')
Card(rank='4', suit='clubs')
Card(rank='3', suit='clubs')
Card(rank='2', suit='clubs')
Card(rank='A', suit='diamonds')
Card(rank='K', suit='diamonds')
Card(rank='Q', suit='diamonds')
Card(rank='J', suit='diamonds')
Card(rank='10', suit='diamonds')
Card(rank='9', suit='diamonds')
Card(rank='8', suit='diamonds')
Card(rank='7', suit='diamonds')
Card(rank='6', suit='diamonds')
Card(rank='5', suit='diamonds')
Card(rank='4', suit='diamonds')
Card(rank='3', suit='diamonds')
Card(rank='2', suit='diamonds')
Card(rank='A', suit='spades')
Card(rank='K', suit='spades')
Card(rank='Q', suit='spades')
Card(rank='J', suit='spades')
Card(rank='10', suit='spades')
Card(rank='9', suit='spades')
Card(rank='8', suit='spades')
Card(rank='7', suit='spades')
Card(rank='6', suit='spades')
Card(rank='5', suit='spades')
Card(rank='4', suit='spades')
Card(rank='3', suit='spades')
Card(rank='2', suit='spades')
 ~/workspace/vscode-workspace/python_notes/python——魔术方法 ---------------------------------------------------------------------- at 17:07:52 
>