写在前面
《流畅的Python》(Fluent Python)是一本由Luciano Ramalho编写的Python编程书籍。这本书的目标是帮助中级到高级Python程序员更深入地理解Python编程语言,以及如何以更加Pythonic(符合Python惯用法)的方式编写代码。这本书不仅介绍了Python的基本语法和特性,还探讨了Python中的高级概念、最佳实践和一些常用的设计模式。
这本书的主要内容包括:
1. Python数据模型:介绍了如何使用特殊方法来实现具有Pythonic行为的自定义对象。
2. 序列:深入讲解了列表、元组和字符串的内部实现和Pythonic用法。
3. 字典和集合:介绍了如何高效地使用这两种主要的Python数据结构。
4. 文本和字节:讲解了如何处理Unicode文本和二进制数据。
5. 第一类函数:深入讲解了如何处理函数作为对象,以及高阶函数的使用。
6. 设计模式:介绍了如何实现一些常用的设计模式,如装饰器、观察者和命令模式。
7. 并发编程:讲解了如何使用线程、进程和协程(coroutine)进行并发编程。
8. 元编程:深入学习如何使用元类、类装饰器和描述符进行元编程。
我将从2023年9月1日起更新学习这本书的一些笔记,本人基础较差所以学习起来会比较慢,内容也会比较详细~
python纸牌
实现原理
import collections # 导入collections模块
Card=collections.namedtuple('Card',['rank','suit']) # 定义一个namedtuple,用来表示一张牌
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):# 定义len函数
return len(self._cards)
def __getitem__(self,position):# 定义getitem函数
return self._cards[position]
deck = FrenchDeck()# 创建一副扑克牌
print(len(deck)) # 输出:52,因为一副扑克牌有52张牌
print(deck[0]) # 输出:Card(rank='2', suit='spades'),即第一张牌:2 of spades
print(deck[-1]) # 输出:Card(rank='A', suit='hearts'),即最后一张牌:A of hearts
from random import choice
print(choice(deck)) # 输出:随机抽选一张牌
print(deck[:3]) # 输出:前三张牌
print(deck[12::13]) # 输出:A of spades, A of diamonds, A of clubs, A of hearts
for card in deck: # 输出:一张张地打印出所有的牌
print(card)
for card in reversed(deck): # 输出:一张张地打印出所有的牌,但是顺序与上面相反
print(card)
print(Card('Q','hearts') in deck) # 输出:True,因为Q of hearts在这副牌中
print(Card('7','beasts') in deck) # 输出:False,因为7 of beasts不在这副牌中
# 排序
suit_values=dict(spades=3,hearts=2,diamonds=1,clubs=0) # 为每个花色赋予一个权值
def spades_high(card): # 定义一个函数,用来对牌进行排序
rank_value=FrenchDeck.ranks.index(card.rank) # 获取牌的序号
#在实例deck中,每一个元素都是一个tuple,我们获取这个tuple的属性rank,就等于得到了扑克牌的点数
return rank_value*len(suit_values)+suit_values[card.suit]
# 用点数乘以权值,再加上花色的权值,就得到了这张牌的权值
for card in sorted(deck,key=spades_high):
print(card)
# 输出:
以上的python纸牌实现的完整代码,代码中出现了一些比较不熟悉的名词,比如namedtuple、init、getitem、sorted函数。下面我将详细解释,包含例子。
namedtuple对象
namedtuple
是Python中collections模块提供的一个工具,它可以用来创建自定义的元组对象,并为元组中的每个位置分配一个名称。这使得代码可读性更高,同时保持了元组的不可变性。使用namedtuple
创建的对象可以通过字段名称或索引访问元素,它还具有内置的__repr__
方法,可以方便地显示对象的内容。
下面是一个如何使用namedtuple
的例子:
from collections import namedtuple
# 创建一个名为Person的namedtuple,具有姓名、年龄和城市属性
Person = namedtuple('Person', ['name', 'age', 'city'])
# 使用 Person 创建一个新的对象
person1 = Person('Alice', 30, 'New York')
# 通过名称访问字段
print(person1.name) # 输出: Alice
print(person1.age) # 输出: 30
print(person1.city) # 输出: New York
# 通过索引访问字段
print(person1[0]) # 输出: Alice
print(person1[1]) # 输出: 30
print(person1[2]) # 输出: New York
# 使用内置的__repr__方法显示对象的内容
print(person1) # 输出: Person(name='Alice', age=30, city='New York')
namedtuple
主要用于定义简单的类,当你需要一个具有特定属性的容器时,而不需要额外的方法、逻辑或其他功能时,它非常有用。这使得代码简洁,易于阅读和维护。
__init__方法
__init__
方法是一个特殊的Python方法,称为类的构造函数或初始化方法。当您创建一个类的新实例时,__init__
方法会自动调用。它的主要作用是为新创建的对象设置初始状态,这通常包括初始化属性和执行其他配置任务。
在Python中,特殊方法的名称以双下划线__
开头和结尾,以区别于常规方法。__init__
方法是一个非常常见的特殊方法,它在大多数类中都有定义。
以下是一个示例,展示了如何编写一个带有__init__
方法的类:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print(f"Hello, my name is {self.name} and I am {self.age} years old.")
在这个例子中,我们定义了一个名为Person
的类,它有一个__init__
方法。__init__
方法接收两个参数(除了self
):name
和age
。当创建一个Person
实例时,这些参数需要传递给构造函数:
person = Person("Alice", 30)
现在,Person
实例已经创建并初始化了,我们可以调用say_hello
方法:
person.say_hello() # 输出:Hello, my name is Alice and I am 30 years old.
在上述代码中,__init__
方法负责将创建的对象的name
和age
属性初始化为传递给构造函数的值。
__getitem__方法
__getitem__
方法是Python类的一个特殊方法,它使得类的实例可以使用方括号[]
索引运算符访问其元素。当您尝试使用索引运算符访问类的实例时,Python会自动调用__getitem__
方法。
在Python中,特殊方法的名称以双下划线__
开头和结尾,以区别于常规方法。__getitem__
方法通常在表示集合、序列或映射等具有元素的类中定义。
以下是一个示例,展示了如何编写包含__getitem__
方法的类:
class MyList:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.data[index]
在这个例子中,我们定义了一个名为MyList
的类,它有一个__getitem__
方法。这个方法接收一个参数(除了self
):index
,它指定了要访问的元素的索引。
现在,我们可以使用方括号[]
索引运算符访问MyList
实例的元素:
my_list = MyList([1, 2, 3, 4, 5])
print(my_list[1]) # 输出:2
在上述代码中,my_list[1]
尝试访问MyList
对象的第二个元素。Python将自动调用__getitem__
方法并传递索引值1
。__getitem__
方法将使用索引值从data
属性中返回相应的元素。
sorted 函数
sorted
函数是Python的内置函数,用于对列表、元组或其他可迭代对象中的元素进行排序。它会返回一个新的已排序列表,而不会修改原始的可迭代对象。
以下是sorted
函数的一般用法:
sorted(iterable, *, key=None, reverse=False)
参数说明:
iterable
:一个可迭代对象(例如列表、元组、字典等),其中的元素将进行排序。key
(可选):一个函数,用于确定排序中使用的值。这个函数应用于可迭代对象的每个元素,用于生成排序依据的键。默认值为None
,表示直接使用元素本身的值进行排序。reverse
(可选):一个布尔值,指定排序的顺序。True
表示降序排序,False
表示升序排序。默认值为False
。
以下是一些使用sorted
函数的示例:
# 对数字列表升序排序
numbers = [4, 2, 9, 7, 5, 1, 8, 3, 6]
sorted_numbers = sorted(numbers)
print(sorted_numbers) # 输出:[1, 2, 3, 4, 5, 6, 7, 8, 9]
# 对字符串列表按字母顺序排序
words = ["apple", "banana", "cherry", "orange", "grape"]
sorted_words = sorted(words)
print(sorted_words) # 输出:['apple', 'banana', 'cherry', 'grape', 'orange']
# 使用 key 函数对字符串列表按字符串长度进行排序
sorted_words_by_length = sorted(words, key=len)
print(sorted_words_by_length) # 输出:['apple', 'grape', 'banana', 'cherry', 'orange']
# 对数字列表降序排序
sorted_numbers_desc = sorted(numbers, reverse=True)
print(sorted_numbers_desc) # 输出:[9, 8, 7, 6, 5, 4, 3, 2, 1]
需要注意的是,sorted
函数返回一个新的已排序列表,而原始列表并未被修改。如果需要就地(in-place)排序列表,请使用列表对象的sort
方法。