《流畅的Python》学习笔记 第1章

本文分享了《流畅的Python》的学习心得,重点介绍了Python数据模型及其特殊方法的应用,如__len__和__getitem__,并通过实例展示了如何利用这些特殊方法实现自定义类的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前也用Python写过爬虫,处理过数据,但是感觉理解还是挺浮于表面的,很多Python的特性都不是很了解。所以决定跟着一本书来帮助自己更深入地理解Python。最后选择了这本《流畅的Python》。在学习的过程中发现确实能学到很多东西,作者的讲解也非常深入浅出,很容易理解并且让人感到Python的魅力,译者的翻译也很好。

并且在读这本书的过程中,真的发现自己对Python的了解还太少,很多函数、特性都不清楚,需要查资料去理解,所以决定把学习过程中自己不知道的点记录下来,算是把书变厚的一个过程吧,争取学到更多,记忆更深!

第1章 Python数据模型

第一章是概览性质的内容。

因为在一开始读这本书的时候,发现第一章的代码里面就有很多不知道的函数、不知道的用法,一度觉得自己把书买的太深了,不适合自己读。但是读到第二章发现,第一章的很多内容在第二章会有详细的解释,所以跟我一样的小伙伴们千万不要被第一章吓到呀 : )

在对数据模型的解释中,作者提到:

数据模型其实是对Python框架的描述,它规范了这门语言自身构建模块的接口,这些模块包括不限于序列、迭代器、函数、类和上下文管理器。

接着作者就讲到了特殊方法(但是我并不是很明白数据模型和这个有什么关系,等以后理解了再修改吧):

Python解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以两个下划线开头,以两个下划线结尾(例如__ getItem__)。比如obj[key]的背后就是__getItem__方法,为了能求得my_collection[key]的值,解释器实际会调用my_collection.__getItem__(key)。

1. 一摞Python风格的纸牌
作者通过这一节,实现__getItem__和__len__两个特殊方法,代码如下:

import collections
Card = collections.namedtuple('Card', ['rank', 'suit']) # 构建只有少数属性但没有方法的对象

class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA') # 牌2~10 + JQKA
    suits = 'spades diamonds clubs hearts'.split() # 四种花色 黑桃 方片 梅花 红桃

    def __init__(self):
        #  13 * 4  = 52 张牌,笛卡尔积
        self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks] 
    # 自定义__len__方法
    def __len__(self):
        return len(self._cards)

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

beer_card = Card('7', 'diamonds') # Card(rank='7', suit='diamonds')

deck = FrenchDeck()
len(deck) # 52

deck[0] # Card(rank='2', suit='spades')

deck[12::13] # [Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
# 切片,取第12个元素,后面每隔13个元素去一个[start: stop: step]

代码的主要内容在注释中已详述,主要包括:
(1)__len__特殊方法;
(2)列表推导(第二章详述);
(3)sorted/reversed方法(第二章详述sorted方法);
(4)切片。

2. 关于特殊方法的调用:
特殊方法的存在是为了被Python解释器调用的,并没有my_object.__len__()这种写法,而是应该使用len(my_object),在执行时,若my_object是一个自定义类的对象,那么Python会自己去调用其中自己实现的__len__方法。

通过下面的例子,实现一个二维向量类,来展示特殊方法的调用:

from math import hypot

class Vector:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y
    # 使用%r来获取对象各个属性的标准字符串表示形式
    def __repr__(self):
        return 'Vector(%r, %r)' % (self.x, self.y)
    # 取模
    def __abs__(self):
        return hypot(self.x, self.y) # 返回欧几里得范数sqrt(x * x + y * y)
    def __bool__(self):
        return bool(abs(self))
    # 通过__add__方法实现+运算符
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)
    # 通过__mul__方法实现*运算符
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

v1 = Vector(2, 4)
v2 = Vector(2, 1)
repr(v1) # 'Vector(2, 4)' 
v1 + v2  # Vector(4, 5) 
v1 * 2  # Vector(4, 8) 
abs(v1) # 4.47213595499958

上面这段代码的主要内容包括:
(1)特殊方法的调用方法;
(2)hypot函数,获得欧几里得距离;
(3)使用特殊方法实现运算符。

最后作者还讨论了内置函数repr和str的联系与区别:
(1)repr函数通过__repr__这个特殊方法来得到一个对象的字符串表示形式,方便调试和记录日志;
(2)str()函数中使用__str__,或者在用print函数打印一个对象时才被调用,返回的字符串对终端用户更加友好。

大概第一章是内容就是这些,引入了特殊方法的概念,并通过两段代码来说明特殊方法的意义与使用。

第二章会有更加具体的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值