我是靠谱客的博主 幽默热狗,最近开发中收集的这篇文章主要介绍流畅的python第一章_《流畅的Python》学习笔记1(第1章:Python数据模型),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.1 一摞Python风格的纸牌

__getitem__和__len__

例1,一摞有序的纸牌

importcollections#namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素,#并可以用属性而不是索引来引用tuple的某个元素。#namedtuple用来构建只有少数属性但是没有方法的对象

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

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 inself.ranksfor suit inself.suits]def __len__(self):returnlen(self._cards)def __getitem__(self, position):returnself._cards[position]#利用namedtuple会轻松得到一个纸牌对象

beer_card = Card('7','diamonds')

print(beer_card)#用len()函数来查看一叠牌有多少张

deck = FrenchDeck()

print(len(deck))#利用__getitem__方法从一叠牌中抽取特定的一张纸牌,比如第一张或最后一张。

print(deck[0])

print(deck[-1])#Python内置从一直序列中随机选出一个元素的函数random.choice。

from random import choice

print("随机抽取一张牌3次:")

print(choice(deck))

print(choice(deck))

print(choice(deck))#查看一摞牌最上面3张和只看牌面是A的牌的操作#其中第二种操作的具体方法是,先抽出索引12的那张牌,然后每向后数13张牌拿一张

print("最上面3张牌:")

print(deck[:3])

print("牌面为A的牌:")

print(deck[12::13])

输出结果:

Card(rank='7', suit='diamonds')52Card(rank='2', suit='spades')

Card(rank='A', suit='hearts')

随机抽取一张牌3次:

Card(rank='9', suit='clubs')

Card(rank='J', suit='clubs')

Card(rank='10', suit='diamonds')

最上面3张牌:

[Card(rank='2', suit='spades'), Card(rank='2', suit='diamonds'), Card(rank='2', suit='clubs')]

牌面为A的牌:

[Card(rank='5', suit='spades'), Card(rank='8', suit='diamonds'), Card(rank='J', suit='clubs'), Card(rank='A', suit='hearts')]

为了能够清晰的看出每一步得到的结果,也不需要这么多的输出语句,(注意注释掉上面暗调的代码)可在控制台运行:

>>> from frenchdeck importFrenchDeck, Card>>> beer_card = Card('7','diamonds')>>>beer_card

Card(rank='7', suit='diamonds')>>> deck =FrenchDeck()>>>len(deck)52

>>>deck[0]

Card(rank='2', suit='spades')>>> deck[-1]

Card(rank='A', suit='hearts')>>> from random importchoice>>>choice(deck)

Card(rank='2', suit='hearts')>>>choice(deck)

Card(rank='K', suit='hearts')>>>choice(deck)

Card(rank='J', suit='spades')>>> deck[:3]

[Card(rank='2', suit='spades'), Card(rank='2', suit='diamonds'), Card(rank='2', suit='clubs')]>>> deck[12::13]

[Card(rank='5', suit='spades'), Card(rank='8', suit='diamonds'), Card(rank='J', suit='clubs'), Card(rank='A', suit='hearts')]>>>

给一摞扑克牌排序,按照2最小,A最大;黑桃最大,红桃次之,方块再次,梅花最小。

按照这个规则给扑克牌排序,梅花2大小是0,黑桃A是51

suit_values = dict(spades =3, hearts=2, diamonds=1, clubs=0)defspades_high(card):#在[2,3,4,5,6,7,8,9,10,J,Q,K,A]中的位置

rank_value =FrenchDeck.ranks.index(card.rank)#suit_values[card.suit]加上花色的大小

return rank_value*len(suit_values)+suit_values[card.suit]

deck=FrenchDeck()for card in sorted(deck, key=spades_high):print(card)

Card(rank='2', suit='clubs')

Card(rank='2', suit='diamonds')

Card(rank='2', suit='hearts')

...(46cards ommitted)

Card(rank='A', suit='diamonds')

Card(rank='A', suit='hearts')

Card(rank='A', suit='spades')

一般注记:按照目前的设计,FenchDeck是不能洗牌的,因为这摞牌是不可变的:卡牌和它们的位置都是固定的,除非破坏这个类的封装性,直接对_cards进行操作。第11章会讲到。

1.2 如何使用特殊方法

首先明确一点,特殊方法的存在是为了被Python解释器调用的,你自己并不需要调用它们。也就是说没有my_object.__len__()这种写法,而应该使用len(my_object)。

通常你的代码无需直接使用特殊方法。除非有大量的元编程存在,直接调用特殊方法的频率远远低于你去实现它们的次数。唯一的例外可能是__init__方法。

1.2.1 模拟数值类型

我们来实现一个二维向量(vector)类,这里的向量就是欧几里得几何中常用的概念。

__repr__、__abs__、__add__和__mul__

例2,一个简单的二维向量类

from math importhypotclassVector:def __init__(self, x=0, y=0):

self.x=x

self.y=ydef __repr__(self):return 'Vector(%r, %r)' %(self.x, self.y)def __abs__(self):returnhypot(self.x, self.y)def __bool__(self):returnbool(abs(self))def __add__(self, other):

x= self.x +other.x

y= self.y +other.yreturnVector(x,y)def __mul__(self, scalar):return Vector(self.x * scalar,self.y * scalar)

为了给这个类设计API,我们先写个模拟的控制台会话来做doctest。

>>> from vector importVector>>> v1 = Vector(2,4)>>> v2 = Vector(2,1)>>> v1 +v2

Vector(4, 5)>>> v = Vector(3,4)>>>abs(v)5.0

>>> v * 3Vector(9, 12)>>> abs(v * 3)15.

>>> v * -3

Vector(-9, -12)

abs是一个内置函数,如果输入是整数或者浮点数,它返回的是输入值的绝对值;如果输入是复数,那么返回这个复数的摸。

*运算符实现向量的标量乘法(即向量与数的乘法,得到的结果向量的方向与原向量方向一致,模变大。如果向量与负数相乘,得到的结果向量的方向与原向量相反。)

1.2.2 字符串表示形式

Python有一个内置的函数叫repr,它能把对一个对象用字符串的形式表达出来以便辨认,这就是“字符串表示形式”。

%和str.format是两种格式化字符串的手段。

1.2.3 算术运算符

通过例2发现,__add__和__mul__两个方法的返回值都是新创建的向量对象,被操作的两个向量(self或other)还是原封不动,代码里只是读取了它们的值而已。中缀运算符的基本原则就是不改变操作对象,而是产出一个新的值。

1.2.4 自定义的布尔值

如果想让Vector.__bool__更高效,可以采用:

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

它不那么易读,却能省掉从abs到__abs__到平方再到平方根这些中间步骤。通过bool把返回类型显示转换为布尔值是为了符合__bool__对返回值的规定,因为or运算符可能会返回x或者y本身的值:若x的值等价于真,则or返回x的值;否则返回y的值。

1.3 特殊方法一览

表1-1:跟运算符无关的特殊方法

类别

方法名

字符串字节序列表示形式

_ repr _ , _ format _ , _ str _ , _ bytes _

数值转换

_ abs _ , _ bool _ , _ complex _ , _ int _ ,_ float _ , _ hash _ , _ index _

集合模拟

_ len _ , _ getitem _ , _ setitem _ , _ delitem _ ,_ contains _

迭代枚举

iter _ , _ reversed _ , _ next _

可调用模拟

_ call _

上下文管理

_ enter _ , _ exit _

实例创建和销毁

_ new _ , _ init _ , _ del _

属性管理

_ getattr _ , _ getattribute _ , _ setattr _ , _ delattr _ , _ dir _

属性描述符

_ get _ , _ set _ , _ delete _

跟踪相关的服务

_ prepare _ , _ instancecheck _ , _ subclasscheck _

表1-2:跟运算符相关的特殊方法

类别

方法名和对应的运算符

一元运算符

neg _ -, _ pos _ +, _ abs _ abs( )

比较运算符

_ lt _  , _ ge _ >=,

算术运算符

_ add _ + , _ sub _ - , _ mul _ * , _ truediv _ / , _ floordiv _ //

_ mod _ % , _ divmod _ divmode() , _ pow _ **或pow() _ round _ round()

反向算数运算符

_ radd _ , _ rsub _ , _ rmul _ , _ rtruediv _ , _ rfloordiv _

_ rmod _ , _ rdivmod _ , _ rpow _

增量赋值运算符

_ iadd _ , _ isub _ , _ imul _ , _ itruediv _ , _ ifloordiv _

_ imod _ , _ idivmod _ , _ ipow _

位运算符

_ invert _ ~, _ lshift _ <>, _ adn _ &, _ or _

反向位运算符

_ rlshift _ , _ rrshift _ , _ rand _ , _ rxor _ , _ ror _

增量赋值位运算符

_ ilshift _ , _ irshift _ , _ iand _ , _ ixor _ , _ ior _

提示:当交换两个操作数的位置时,就会调用反向运算符(b*a而不是a*b)

最后

以上就是幽默热狗为你收集整理的流畅的python第一章_《流畅的Python》学习笔记1(第1章:Python数据模型)的全部内容,希望文章能够帮你解决流畅的python第一章_《流畅的Python》学习笔记1(第1章:Python数据模型)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部