1. Example of two-dimensional vector: Vector(2,4) + Vector(2,1) results in Vector(4,5)
import math # special methods used: __repr__ , __abs__ , __add__ , __mul__ class Vector: def __init__(self, x=0, y=0): self.x = x self.y = y def __repr__(self): return "Vector(%r, %r)" % (self.x, self.y) # we use %r to obtain the standard representation of the attributes to be displayed. # !r should be used in the str.format method. def __abs__(self): return math.hypot(self.x, self.y) # math.hypot(x, y) 即相当于 math.sqrt(x*x + y*y) def __bool__(self): """ By default, instances of user-defined classes are considered truthy, unless either __bool__ or __len__ is implemented. Basically, bool(x) calls x.__bool__() and uses the result. If __bool__ is not implemented, Python tries to invoke x.__len__(), and if that returns zero, bool returns False. Otherwise bool returns True. :return: """ return bool(self.x or self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Vector(x, y) # create and return a new instance of Vector def __mul__(self, other): return Vector(self.x * other, self.y * other) """ in both __add__ and __mul__ , the methods should create and return a new instance of Vector, and DO NOT modify either operand -- 'self' or 'other' (应该生成新的对象) """ v1 = Vector(2, 4) v2 = Vector(2, 1) print(v2) print("add: v1 + v2", v1 + v2) v = Vector(3, 4) print("abs(3,4)", abs(v)) print("v * 3", v * 3) print("abs(v*3)", abs(v * 3))
2.1. 列表生成式的嵌套 for 循环:
示例如下:
li1 = range(1,6) li2 = list("ABC") # list("ABC") 的结果为 ["A", "B", "C"] for m in li1: for n in li2: print((m,n)) li = [(m,n) for m in li1 for n in li2] print(li) # 输出结果: (1, 'A') (1, 'B') (1, 'C') (2, 'A') (2, 'B') (2, 'C') (3, 'A') (3, 'B') (3, 'C') (4, 'A') (4, 'B') (4, 'C') (5, 'A') (5, 'B') (5, 'C') [(1, 'A'), (1, 'B'), (1, 'C'), (2, 'A'), (2, 'B'), (2, 'C'), (3, 'A'), (3, 'B'), (3, 'C'), (4, 'A'), (4, 'B'), (4, 'C'), (5, 'A'), (5, 'B'), (5, 'C')] # 列表生成式中的 两个 for 循环 作用就相当于 for 循环的嵌套
参考链接: https://www.jb51.net/article/150400.htm
2.2 A Pythonic Card Deck: __len__ & __getitem__
示例如下:
import collections Card = collections.namedtuple("Card", ["rank", "suit"]) class FrenchDeck(object): 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] deck = FrenchDeck() print(len(deck)) # len() 实际只适合 dict, list 等;想要 适用于 deck ,就需要重写 __len__ 方法 # output: # 52 print(deck[0], deck[1]) # __getitem__ delegates to the [] operator """ Special methods是理解Python语言的关键之一。例如,__getitem__特殊方法用来支持obj[key]。因此,当实现my_collection[key],解释器实际上调用的是my_collection.__getitem__(key) """ # output: # Card(rank='2', suit='spades') Card(rank='3', suit='spades') import random print(random.choice(deck)) print(random.choice(deck)) print(random.choice(deck)) # output: # Card(rank='8', suit='clubs') # Card(rank='J', suit='clubs') # Card(rank='2', suit='diamonds') """ random.choice(seq) 的原理: random.choice内部实现是先用len方法获取总长度然后从0到总长度时间取一个随机数作为索引获取 源码如下: def choice(self, seq): # Choose a random element from a non-empty sequence. try: i = self._randbelow(len(seq)) except ValueError: raise IndexError('Cannot choose from an empty sequence') from None return seq[i] """ # 切片: class slice(start, stop[, step]) print(deck[12::13]) # output: # [Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), # Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')] for card in deck: print(card) # by implementing the __getitem__ special method, deck is also iterable # the statement -- for i in x: actually causes the invocation of iter(x), which in turn may call x.__iter__() if that is possible. # the deck can also be iterated in reverse : for card in reversed(deck): print(card) """ reversed(seq) Return a reverse iterator. seq must be an object which has a __reversed__() method or supports the sequence protocol (the __len__() method and the __getitem__() method with integer arguments starting at 0). """ print(Card("Q", "hearts") in deck) print(Card("7", "beasts") in deck) # output: # True # False # 特殊方法 __contains__ 是用来进行in检验的。 # Sorting: """ 要求: A common system of ranking cards is by rank(with aces being highest),then by suit the order of spades(highest), then hearts, diamonds, and clubs(lowest). """ suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0) def spades_high(card): card_rank = FrenchDeck.ranks.index(card.rank) return card_rank * len(suit_values) + suit_values[card.suit] for card in sorted(deck, key=spades_high):
# deck 中的每个 item 会传为 spades_high 的参数 传入 spades_high 中 print(card) """ By implementing the special methods __len__ and __getitem__ , our FrenchDeck behaves like a standard Python sequence.
The `list.sort` method sorts a list in place -- that is, without making a copy. (list.sort 方法是对一个列表进行【就地】排序;返回 None);
In contrast , the built-in function `sorted` creates a new list and returns it. (返回排序后的 list) """