《Fluent Python》笔记
1 functools.partial()和functools.partialmethod()
1)functools.partial()主要用于将原函数的某些参数固定,减少代码冗余,减少函数调用时的参数。
import functools
import operator
triple = functools.partial(operator.mul, 3)
print(list(map(triple, range(10))))
# [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
2)functools.partialmethod 函数(Python 3.4 新增)的作用与partial 一样,不过是用于处理方法的
from functools import partialmethod
class Cell(object):
def __init__(self):
self._alive = False
@property
def alive(self):
return self._alive
def set_state(self, state):
self._alive = bool(state)
set_alive = partialmethod(set_state, True)
set_dead = partialmethod(set_state, False)
set_alive_p = functools.partial(set_state, True)
c = Cell()
print(c.alive)
c.set_alive()
print(c.alive)
# c.set_alive_p() #报错,partial()不用于处理方法
print(c.alive)
参考:
偏方法partialmethod
python中partial的使用规则
原书5.10.2节
有待更新
2 python中的浅拷贝和深拷贝
1)python中非容器类型(比如数字、字符串和其他“原子”类型的对象,像xrange对象等)没有被拷贝一说,浅拷贝是用完全切片操作来完成的。
2)其他浅复制的几种情况:
使用切片[:]操作
使用工厂函数(如list/dir/set)
使用copy模块中的copy()函数
3)python中的赋值(=)实际上是一种引用,对赋值、浅拷贝和深拷贝原书8.3节和 python中对象的赋值、浅拷贝和深拷贝,讲的很清楚了。
4)元组不可修改和浅拷贝的问题
4.1)元组是相对不可变的,其不可修改指的是不可使用=(assignmen),但元组内存在list等可变对象可使用append/extend,因为append/extend只是增加了列表中的值,而列表的内存地址并没有发生改变。
l1 = [1, 2]
print(id(l1))
l1.extend([3, 4])
print(id(l1))
print(l1)
# 2108870255176 内存地址并没有发生改变,元组中存储的是引用,内存地址没变当然可以使用
# 2108870255176
# [1, 2, 3, 4]
t1 = (1, 2, [3, 4])
t1[2].append(5)
print(t1)
# (1, 2, [3, 4, 5])
4.2)元组中+=的问题
首先需要重温+=这个运算符,如a+=b:
- 对于可变对象(mutable object)如list, +=操作的结果会直接在a对应的变量进行修改,而a对应的地址不变.
- 对于不可变对象(imutable object)如tuple, +=则是等价于a = a+b 会产生新的变量,然后绑定到a上而已.
- python中+=不是原子操作,相当于两步,extend和=
>>> a = ([1, 2], 3, 4)
>>> a[0] += [3, 4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> print(a)
([1, 2, 3, 4], 3, 4)
#+=相当于首先进行a[0].extend([3,4]),改变了元组a引用的值,而后进行=操作,
#报错(元组不可修改,不支持=操作),但实际上a引用的值已经发生了改变。
参考:
Python中tuple+=赋值的四个问题
Why does += of a list within a Python tuple raise TypeError but modify the list anyway? [duplicate]
3 可哈希的问题
1) 散列函数是一种从任何一种数据中创建小的数字”指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值的指纹。散列值通常用来代表一个短的随机字母和数字组成的字符串。好的散列函数在输入域中很少出现散列冲突。在散列表和数据处理中,不抑制冲突来区别数据会使得数据库记录更难找到。你可以把哈希值简单地理解成是一段数据(某个文件,或者是字符串)的DNA,或者身份证;
2)通过一定的哈希算法(典型的有MD5,SHA-1等),将一段较长的数据映射为较短小的数据,这段小数据就是大数据的哈希值。他有这样一个特点,他是唯一的,一旦大数据发生了变化,哪怕是一个微小的变化,他的哈希值也会发生变化。另外一方面,既然是DNA,那就保证了没有两个数据的哈希值是完全相同的。
3)正是因为这样的特点,它常常用来判断两个文件是否相同。比如,从网络上下载某个文件,只要把这个文件原来的哈希值同下载后得到的文件的哈希值进行对比,如果相同,则表示两个文件完全一致,下载过程没有损坏文件。而如果不一致,则表明下载得到的文件跟原来的文件不同,文件在下载过程中受到了损坏。
4)相同的数据有相同的哈希值。
5) python术语对照表中有:
由此可知可哈希对象要满足:哈希值在其生命周期内不改变、有__hash__方法、有__eq__方法(原书3.1节也对此进行了讲解);
5.1)解析以下原书9.6节的代码vector2d.py,改代码将Vector2d变成了一个可哈希对象:
from array import array
import math
class Vector2d:
typecode = 'd'
def __init__(self, x, y):
self.__x = float(x) #将x,y变成私有属性使其不能够改变创建的实例,保持创建的实例不发生改变
#进而保持实例的哈希值不变
self.__y = float(y)
@property
def x(self):
return self.__x
@property
def y