流畅的python

3.8.1

set

两个集合a, b:
a & b 交集
a | b 合集
a - b 差集
比直接for循环省时间

dict

setdefault更新value且避免重复搜索

dict查找key非常快,同时很消耗内存

不要对字典同时进行迭代和修改。如果想扫描并修改一个字典,最好:
1.迭代,找出需要添加的内容,放入一个新字典
2.迭代结束后对原有字典进行更新
原因:往dict添加新key时,py解释器可能会为dict扩容,导致新建一个更大的散列表。将已有元素加入新表时可能发生的散列冲突,会导致dict顺序改变。因此若边遍历边修改,很有可能跳过一些key。

4

编码

  1. 一个例子:

    流畅的python_第1张图片
  2. 显式指定编码可以解决很多问题。

7.函数装饰器和闭包

7.2

装饰器的一个关键特性是,它们在被装饰的函数定义后立刻运行。这通常是在导入时(即python模块加载时)。

7.8 标准库中的装饰器

functools.lru_cache

会把结果缓存,传入参数相同时直接返回结果。
被该装饰器装饰的函数,所有参数必须是可散列的

functools.lru_cache(maxsize=128, typed=False)
	maxsize: 指定缓存的结果数,缓存慢了后旧的结果会被扔掉
	typed: 设为True时,会把不同参数类型得到的结果分开保存
		(即把通常认为相等的整数参数与浮点数参数1/1.0区分开

functools.singledispatch
对于 Python 来说是不支持方法的重载的,不过它为我们提供了一个装饰器,能将普通函数变为泛函数(generic function)

# 针对不同类型的数据进行不同的处理,而又不想将它们写到一起

@functools.singledispatch
def typecheck():
    pass

@typecheck.register(str)
def _(text):
    print(type(text))
    print("str--")

@typecheck.register(list)
def _(text):
    print(type(text))
    print("list--")

@typecheck.register(int)
def _(text):
    print(type(text))
    print("int--")
# 测试

a = 1
typecheck(a)
>>>  

int--  

a = "check"
typecheck(a)
>>>

str--

8.对象引用、可变性和垃圾回收

== 与 is 的区别

== 比较两个对象的值(对象中保存的数据
is 比较两个对象的标识

a = 1
b = a
c = 1

a == c   >>> True
c is a   >>> False
b == a   >>> True
b is a   >>> True

默认做浅copy

copy做浅拷贝
deepcopy做深拷贝
若对象有循环引用,深拷贝会进入无线循环,deepcopy会记住已经复制的对象,因此能优雅处理循环引用。

a = [10, 20]
b = [a, 30]
a.append(b)      >>>  a:  [10, 20, [[...], 30]]
from copy import deepcopy
c = deepcopy(a)   >>>  c:  [10, 20, [[...], 30]]

del和垃圾回收

del语句删除名称,而不是对象。只有当一个对象的所有引用都被删除,或者无法获得该对象时,他才会被销毁回收。(重新绑定也会改变对象的引用数)

s1 = {1, 2, 3}
s2 = s1      >>>  s1,s2都指向 {1, 2, 3}
del s1       >>>  删除变量s1,但此时{1,2,3}还存在引用,不被回收
s2 = '123'   >>>  s2改变引用,此时{1,2,3}被销毁回收

9.符合python风格的对象

@classmethod

修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数。然后可以直接调用。

class A(object):
    bar = 1
    def func1(self):  
        print ('fun1') 
   
    @classmethod
    def func2(cls):
        print ('func2')
        print (cls.bar)
        cls().func1()   # 调用 foo 方法
 
A.func2()               # 不需要实例化

@staticmethod

如果在方法中不需要访问任何实例方法和属性,纯粹地通过传入参数并返回数据的功能性方法,那么它就适合用静态方法来定义。它节省了实例化对象的开销成本,往往这种方法放在类外面的模块层作为一个函数存在也是没问题的,而放在类中,仅为这个类服务。

class C(object):
    @staticmethod
    def func(n):
        print('func:' + n);
 
C.f();          # 静态方法无需实例化
cobj = C()
cobj.f()        # 也可以实例化后调用

10.序列的修改、散列和切片

functools.reduce(func, iter, init)

functools.reduce(lambda a,b: a b, range(1, 6))
>>>  120
functools.reduce(operator xor, range(6))
>>>  1
functools.reduce(operator xor, [], 0)
>>>  0

zip(*iterables)

>>> list(zip([1, 2, 3], [4, 5, 6]))
[(1, 4), (2, 5), (3, 6)]
>>> x2, y2 = zip(*zip(x, y))
>>> x == list(x2) and y == list(y2)
True
>>> list(zip([1.0, 2.0, 3.0, 4.0], 'abc', range(3)))
[(1.0, 'a', 1), (2.0, 'b', 2), (3.0, 'c', 3)]

enumerate(iterable, start=0)

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

14.可迭代的对象、迭代器和生成器

14.1

序列可以迭代的原因:iter函数
若实现了则直接调用;若没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试按顺序(从索引0开始)获取元素;否则抛出TypeError异常。

14.2

迭代器
迭代器是这样的对象:实现了无参数的__next__方法,返回序列中的下一个元素。没有元素时抛出StopIteration异常。python的迭代器还实现了__iter__方法,因此迭代器也可以迭代。
注:可迭代的对象不是迭代器。且可迭代的对象一定不能是自身的迭代器,其可以实现__iter__方法,但不能实现__next__方法

15 上下文管理器和else块

15.1

以下三种的else当做‘then’会更好理解
for/else
仅当for循环运行完毕时(即for循环没有被break中止)才运行else块
while/else
仅当while循环因为条件为假值而退出时(即while循环没有被break中止)才运行else块
try/while
仅当try块中没有抛出异常时才运行else块

15.2

上下文管理器协议包含__enter____exit__方法。with语句开始运行时,会在上下文管理器对象上调用__enter__方法,结束时调用__exit__方法

class Sample:
    def __enter__(self):
        print "In __enter__()"
        return "Foo"

    def __exit__(self, type, value, trace):
        print "In __exit__()"

def get_sample():
    return Sample()

with get_sample() as sample:
    print "sample:", sample

输出:
In __enter__()
sample: Foo
In __exit__()

16.协程

协程状态
当前状态可用inspect.getgeneratorstatus(...)确定
GEN_CREATED:等待执行开始
GEN_RUNNING:解释器正在执行
GEN_SUSPENDED:在yield表达式处暂停
GEN_CLOSED:执行结束

16.3

def averager():
	total = 0.0
	count = 0
	average = None
	while True:
		term = yield average
		total += term
		count += 1
		average = total / count

输出:
>>>mie = averager()
>>>next(mie)
>>>mie.send(10)
10.0
>>>mie.send(30)
20.0
>>>mie.send(5)	
15.0

16.4

coroutine装饰器
不预激的协程没什么用(初始调用mie.send(x)之前一定要调用next(mie)),为了简化协程用法,会使用一些预激装饰器。

from coroutil import coroutine

@coroutine
def averager():
	total = 0.0
	count = 0
	average = None
	while True:
		term = yield average
		total += term
		count += 1
		average = total / count

输出:
>>>mie = averager()
>>>from inspect import get generatorstatus
>>>generatorstatus(mie)
'GEN_SUSPENDED'
>>>mie.send(10)
10.0
>>>mie.send(30)
20.0
>>>mie.send(5)	
15.0

17.使用期物处理并发

期物 :https://www.jianshu.com/p/6be8f184feda

19 doing

你可能感兴趣的:(笔记)