@spiritnotes
2016-06-15T13:26:08.000000Z
字数 4943
阅读 1874
Python
读书笔记
DOING
使用python3来运行3.x版本
在运行程序时通过sys.version_info获得当前版本信息
命名
表达式与语句
可以使用两个辅助函数进行转换
### python3
def to_str(str_or_bytes):
if isinstance(str_or_bytes, bytes):
value = str_or_bytes.decode('utf-8')
else:
value = str_or_bytes
return value
def to_bytes(str_or_bytes):
...
# bytes和str是两种类型,写程序时需要注意
### python2
def to_unicode(str_or_unicode):
...
def to_str(str_or_unicode):
..
# 对于接受str的函数,也可以使用只使用ascii的unicode,如果接受unicode,可以传入str
可读性 辅助函数 > if/else表达式 > or/and复杂表达式
somelist[start: end]
如题
生成器计算为迭代器
生成器有状态,只能onepass
替代range生产i然后访问x[i]
enumerate可以接受参数用于指定开始使用的计数值
python2中zip是返回元组,可以使用itertools.izip
长度不同,使用 itertools.izip-longest/zip_longest
def sort_priority(values, group):
def helper(x):
if x in group:
return (0, x)
return (1, x)
values.sort(key=helper)
变量赋值规则
使用yield表达式达到同样效果
def do(get_iter):
sum_ = sum(get_iter())
for i in get_iter():
pass
if iter(numbers) is iter(numbers): ## iter使用在迭代器上返回自身
raise TypeError('Must Be a Container')
...
使用 ×args
def log(messsage, *args):
return message % args
log('ccccc', *(1,2,3))
def f(a, b=1, c=2, d=3): pass
f(1, c=3)
即期望默认值在每次执行函数时运算,而该期望与Python语言特性是矛盾的
正确应该设置为None,判断为None时进行计算
如果默认值类型是可变的,则一般情况下需要使用None代替
python3中 fun(a, v, *, z, m, **kwargs) z,m必须以关键字赋值,可以有默认值
Python2实现
## 1
def decr_fun(n):
def dec(fun):
def _fun(*args, **kwargs):
if 'd' not in kwargs:
raise ...
...
return _fun
return dec
@decr_fun(3)
def fun(a, b, c, d, *args, **kwargs):
pass
## 2
def fun(a, b, c, **kwargs):
d = kwargs.pop('d', 0)
e = kwargs.pop('e', 0)
if kwargs:
raise
字典用于保存某个对象在其生命周期里的动态内部状态。
动态是指这些待保存的信息,其标识符无法提前获知。
将嵌套结构重构为类。
可以使用namedtuple来过渡。问题:1)无默认参数,2)会被人通过下标和迭代访问,后续会产生修改问题。
嵌套字典或者元组,可以依次改为嵌套类。
Python中很多接口都支持传递函数,如回调函数、sort的key参数
函数可以是无状态函数,也可以是含有状态信息的闭包。
使用类实例的绑定方法用作回调,可以用于保存状态。
使用定义了__call__方法的类实例,直接进行计算。
多态:使得继承体系中的多个类都能以各自所独有的方式来实现某个方法。满足相同接口,或继承自相同的抽象类。
Python中每个类只有一个 __init__ 来构造对象。
可以通过@classmethod来创建对象,也可以用于创建对象的子类。
多重继承情况下,直接通过father.__init__调用会产生问题。钻石继承在多路径上的类的方法会被调用多次。
通过super按照mro(方法解析顺序)的方向来调用初始化。
可以通过mro方法来查看类的顺序。
python3中可以直接通过super()函数进行调用,其是通过__class__和self来调用,而python2未实现__class__,而self.__class__是指的类的实际类型
Mix-in类:只定义其他类可能需要提供的一套附加方法。不定义自己的实例属性,不要求调用__init__方法
实现的原理:Python动态特性,可以允许本类的方法访问的属性不是本类定义。
例子:将对象的属性以及其嵌套属性都递归转换为字典表示,再用于json进行序列化
private属性,双下划线开头,其会被重命名,子类不能访问父类的私有属性
原理:Python看到访问__开头的属性时,先会加上该类的类名后再寻找新变量名_ClassName__VariName,因此可手动产生变量明访问
习惯性使用下划线开头来告诉使用者注意
private合理使用是用于避免子类和父类属性重名,如_value,在实例中只会存在一个,在父类中__value表示,则子类中可以定义自己的_value
实现比较简单的类型可以直接继承内部类型
abc中定义了一些抽象基类,其可以帮我么检查是否所有需要的方法都已经定义,而且其还提供了很多相关方法
class AAA:
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
可以用属性来进行类型检查、数值检查、延迟计算、防止父类属性被覆盖等
写属性时应该合理,最小惊讶原则,getter不应该改变其他属性的值
把简单的数值属性迁移为实时计算(按需计算、动态计算等)
如果@property使用过于频繁,则需要考虑是否应该重构
class Grade:
def __get__(self, instance, instance_type):
#
def __set__(self, instance, value):
instance._value = value # 不能赋值给self,该实例会被共享
self._values[instance] = value # 会对instance的删除产生问题,需要使用weakref,WeakKeyDictionary
class Exam:
math_grade = Grade() # 所有类实例共享同一份实例
science_grade = Grade()
# exam.math_grade = v
# => Exam.__dict__['math_grade'].__set__(exam, v)
如果实例对象没有该名称的属性,则转向其类定义查找同名的类属性,如果其是定义了__get__和__set__方法的对象,则Python认为该对象遵循描述符协议
普通实例属性、@property和描述符都需要预先定义
并发与并行的关键区别在于能不能提速。
subprocess.Popen, communicate()/poll(),可以使用管道来进行输入输出
communicate有timeout参数,避免死锁或失去响应,3.3之后有
GIL是以把互斥锁
Python虚拟机中原子操作在于其自己的字节码,而不是可见的语句为单位