个人笔记,方便自己查阅使用
Py.LangSpec.Contents
- Refs
- Built-in
- Closure
- Collections
- Data Structures
- Dictionary
- Comprehension
- Sort
- Traverse
- List
- List Comprehensions
- Sets
- Dictionary
- Data Structures (Implementations)
- Decorators
- Exception
- Functions
- Parameters& Arguments
- Generators,
yield
, Iterables - Grammar/Syntax
- I/O
- Iterable
- Lambda, filter, reduce and map
- Logic
- Object and Class
- metaclass
- class variables
- Object Types
- 检查空对象?
- is vs ==
- None
- Operators
- Scope
- Strings
- Style
- Variables, Objects, Types, References
- python中的变量 和 引用
- 函数传参
- 强类型,弱类型?
- Global vars
- python中的变量 和 引用
- With..as..
- Topics
- Commandline
- Concurrency
- GIL
- Debug
- Encoding
- Errors
- Errors you meet
- File
- Garbage Collection
- Sort
- Regular Expression
- System&Software
- Questions/Problems
Refs
Lang Py 2.7
Built-in
- compile
- The
compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
built-in can be used to speed up repeated invocations of the same code with exec or eval by compiling the source into a code object beforehand. - Doc: Compile
- Compile the source into a code or AST object. Code objects can be executed by an exec statement or evaluated by a call to eval().
- The
- eval, exec
- What's the difference between eval, exec, and compile in Python?
- The
exec
function (which was a statement in Python 2) is used for executing a dynamically created statement or program -
only exec accepts source code that contains statements like
def, for, while, import, or class
- Both exec and eval accept 2 additional positional arguments - globals and locals - which are the global and local variable scopes that the code sees.
-
compile
?
Closure
Python’s closures are late binding. This means that the values of variables used in closures are looked up at the time the inner function is called. (RUNTIME)
def multipliers():
return [lambda x : i * x for i in range(4)]
print [m(2) for m in multipliers()]
The output of the above code will be [6, 6, 6, 6] (not [0, 2, 4, 6]).
The reason for this is that Python’s closures are late binding. This means that the values of variables used in closures are looked up at the time the inner function is called. So as a result, when any of the functions returned by multipliers() are called, the value of i is looked up in the surrounding scope at that time. By then, regardless of which of the returned functions is called, the for loop has completed and i is left with its final value of 3. Therefore, every returned function multiplies the value it is passed by 3, so since a value of 2 is passed in the above code, they all return a value of 6 (i.e., 3 x 2).
对于这个例子,重要的一个点是,for i in range(4)
是不属于这个lambda函数的,所以multipliers返回的是一个含有4个function的列表。late binding告诉我们,运行该lambda函数的时候,我们才计算函数的内容(也不一定要是lambda,一般的函数也可以,因为我们这里是讨论闭包),而彼时i已经变成3。这个问题的难度在于,把列表推导式使用的变量与lambda函数调用的变量用到了一起,再加上了闭包。
Collections
OrderedDict
有序的字典对象
-
Doc collections.OrderedDict
OrderedDict.popitem(last=True)
- The popitem() method for ordered dictionaries returns and removes a (key, value) pair. The pairs are returned in LIFO order if last is true or FIFO order if false.
Data Structures (Types)
Sequential Data Types or: Sequence
del 用del来删除dict/list中的一个/多个元素,比使用remove要快
Dictionary
Dictionary Mapping for Functions Why Doesn't Python Have Switch/Case?
-
Comprehension
In Python 2.6 and earlier, the dict constructor can receive an iterable of key/value pairs:
d = dict((key, value) for (key, value) in iterable)
From Python 2.7 and 3 onwards, you can just use the dict comprehension syntax directly:
d = {key: value for (key, value) in iterable}
-
Sort
-
Traverse
- 注意:字典元素的顺序通常没有定义。换句话说,迭代的时候,字典中的键和值都能保证被处理,但是处理顺序不确定。如果顺序很重要的话,可以将键值保存在单独的列表中,例如迭代前进行排序。
- items() --> a list of tuples :
for k,v in d.iteritems()
也可以加上括号for (k,v) in dict.items()
- iteritems() - iterator-generator ->
for k,v in d.iteritems()
也可以加上括号 - 遍历方式比较
- Python 循环遍历字典元素
- Basics of Python Dictionary: Looping & Sorting
- items()和iteritems()区别和使用,字典的get()函数也不错
- 遍历python字典几种方法
List
- Initialization 初始化
plist = ['a',1,obj1]
-
plist = ["wulala"]
得到 ['wulala'] -
plist = list()
空列表 或者plist=[]
- NOTE:
plist = list["wula"]
- 会得到 ['w','u','l','a'] !!!
- 切片
-
python 列表切片
-
print li[::-1]
#输出[7,6,5,4,3,2,1],省略起始索引、终止索引,步长值为-1,表示反向获取
-
- 倒序输出列表
-
range()
返回列表 -
range(0,3)[::-1]
#输出[2,1,0]
-
-
python 列表切片
- the statement
list = [ [ ] ] * 5
does NOT create a list containing 5 distinct lists; rather, it creates a a list of 5 references to the same list (i.e. [] here)- list[0].append(10) appends 10 to the first list. But since all 5 lists refer to the same list, the output is: [[10], [10], [10], [10], [10]].
- Similarly, list[1].append(20) appends 20 to the second list. But again, since all 5 lists refer to the same list, the output is now: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]].
- In contrast, list.append(30) is appending an entirely new element to the “outer” list, which therefore yields the output: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].
List Comprehensions
- Generator Comprehension, Set Comprehension, etc
- List 推导式 深入理解
- list comprehension中,只能使用for和if这2种语句。
-
a = 5 if b > 3 else 2
(python 中没有?:
)
-
- Q:Python的List Comprehension中,可以使用无限多个for、if语句,该怎么去理解这些for、if语句呢?它们之间的关系是什么呢?
- A: Python的语法解析、字节码生成,大约分为3个阶段:
1、将.py源代码,解析成语法树
2、将语法树,解析成AST树
3、根据AST树,生成字节码- Python在从语法树生成AST的过程中,会将List Comprehension中的for分离开来,并将每个if语句,全部归属于离他最近的左边的for语句
- 如果变量x没有被使用过,那么变量x会成为一个局部变量,当列表推导式结束后,还可以访问变量x;否则,变量x原来的作用域是什么,现在还是什么。
- 后续的for语句都嵌套在之前的for语句中
List Comprehension, python-course
Set Comprehension: use curly brackets instead of square brackets to create a set.
no_primes = {j for i in range(2,sqrt_n) for j in range(i*2, n, i)}
S = [x**2 for x in range(10)]
V = [2**i for i in range(13)]
M = [x for x in S if x % 2 == 0] ## [0, 4, 16, 36, 64]
m = [x for x in [x**2 for x in range(10)] if x%2==0] ## [0, 4, 16, 36, 64]
>>> noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)] # 倘若写成 noprimes = [j for j in range(i*2, 50, i) for i in range(2, 8) ] 就不是本来的意思了,因为后续的for语句都嵌套在之前的for语句中
primes = [x for x in range(2, 50) if x not in noprimes]
>>> print primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
[(x,y,z) for x in range(1,30) for y in range(x,30) for z in range(y,30) if x**2 + y**2 == z**2]
you can nest list comprehensions inside of each other, so you could write the above example with a single statement (without the need for the temporary variable "noprimes").
Set
Data Structures (Implementations)
Trees
Decorators
A decorator is a function that expects ANOTHER function as parameter
-
- a wrapper can be seen as a wrapper of another function
- notice the arg, and what the decorator returns (a function)
Exception
-
python 异常处理
- try...except[SomeError]; try...except; raise触发异常
- e.g.
raise ShortInputException(len(s), 3)
- 处理:
except ShortInputException, xs:
- 处理:
Functions
-
python里函数定义的顺序
- 函数里的语句在函数定义时并不执行,只有在该function being called的时候才执行
- Zip(): 强大的zip
- zip([seql, ...])接受一系列可迭代对象作为参数,将对象中对应的元素打包成一个个tuple(元组),然后返回由这些tuples组成的list(列表)。若传入参数的长度不等,则返回list的长度和参数中长度最短的对象相同。
- zip()配合*号操作符,可以将已经zip过的列表对象解压
Parameters & Arguments
-
Python的函数参数传递:传值?引用?
在python中,类型属于对象,变量是没有类型的.- 所有的变量都可以理解是内存中一个对象的“引用”,或者,也可以看似c中void*的感觉。所以,希望大家在看到一个python变量的时候,把变量和真正的内存对象分开。
- “可更改”(mutable)与“不可更改”(immutable)对象:在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。
-
python中的传值和传引用
- 传递参数的时候,python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。
- 如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。
- 如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。
-
函数参数的多种传递方法
-
*
包裹传递: 所有的参数被收集,根据位置合并成一个元组(tuple) -
**
包裹关键字传递:所有的参数被收集,根据位置和关键字合并成一个字典(dict) - 解包裹传递: 就是在传递tuple时,让tuple的每一个元素对应一个位置参数; dict的解包裹类似
-
-
默认参数:
- 如果默认参数是一个mutable,而多次调用此function时,使用了该默认参数,会怎样呢?
- See question 1 8 Essential Python Interview Questions
- expressions in default arguments are calculated when the function is defined, not when it’s called.
Generators, yield
, Iterables
Generators functions allow you to declare a function that behaves like an iterator, i.e. it can be used in a for loop.
Generators are iterators, but you can only iterate over them once(第二次不会报错,但什么也不会发生). It's because they do not store all the values in memory, they generate the values on the fly
-
Yield
is a keyword that is used likereturn
, except the function will return a generator.-
IMPORTANT: when you call the function (with
yield
), the code you have written in the function body does not run. The function only returns the generator object
-
IMPORTANT: when you call the function (with
extend()
是一个迭代器方法,作用于迭代器,并把参数追加到迭代器的后面-
- yield 简单说来就是一个生成器,生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。
-
GREAT TUT: IBM Python yield 使用浅析
- 考虑可复用性,并且节省内存占用
- 带有 yield 的函数在 Python 中被称之为 generator(生成器)
Generator Comprehension
Generator comprehensions were introduced with Python 2.6. They are simply a generator expression with a parenthesis - round brackets - around it. Otherwise, the syntax and the way of working is like list comprehension, but a generator comprehension returns a generator instead of a list
Grammar/Syntax
Late Binding
I/O
-
Python Programming/Input and Output
-
input()
uses raw_input to read a string of data, and then attempts to evaluate it as if it were a Python program, and then returns the value that results.
-
-
File Objects
- File objects are implemented using C’s stdio package and can be created with the built-in
open()
function. - It is an iterator
- it can only traverse the file once.
- You may reset the file cursor with
.seek(0)
- Actually, C's stdio is also streaming
- File objects are implemented using C’s stdio package and can be created with the built-in
想要print始终显示在同一行,本身是在最后加上逗号即可,即:
print "xxx",
然后又想要实现,新打印的一行,冲掉之前旧的一行,达到显示出下载文件大小一点点增加,但是却始终保持同行,那么就再打印的内容最后添加上\r即可:
print "xxx\r",
Stream - io module
- io — Core tools for working with streams¶
- The io module provides the Python interfaces to stream handling. Under Python 2.x, this is proposed as an alternative to the built-in file object, but in Python 3.x it is the default interface to access files and streams.
Iterable
-
Python's iterator, iterable, and iteration protocols?
- An iterable is an object that has an
__iter__
method which returns an iterator, or which defines a__getitem__
method that can take sequential indexes starting from zero (and raises an IndexError when the indexes are no longer valid). So an iterable is an object that you can get an iterator from. - An iterator is an object with a
next
(Python 2) or__next__
(Python 3) method.
- An iterable is an object that has an
Whenever you use a for loop, or map, or a list comprehension, etc. in Python, the next method is called automatically to get each item from the iterator, thus going through the process of iteration.
Lambda, filter, reduce and map
Lambda functions are mainly used in combination with the functions filter(), map() and reduce(). The lambda feature was added to Python due to the demand from Lisp programmers.
-
- 只能由一条表达式组成
- 一般可以在sorted, max, 这类函数里的key用lambda.比如有一个比较复杂的数组结构,
s = [('a', 3), ('b', 2), ('c', 1)]
- 对这个数组用第二个元素排序。可以写成
sorted(s, key=lambda x:x[1])
- 对这个数组用第二个元素排序。可以写成
map
r = map(func, seq)
r=map(lambda x: x+"abc","gre") # r为['gabc', 'rabc', 'eabc']
- map() can be applied to more than one list (or sequence). The lists have to have the same length and the function or lambda should be able to take more than one args.
filter
- filter(function, list) offers an elegant way to filter out all the elements of a list, for which the function function returns True.
reduce
- reduce(func, seq) continually applies the function func() to the sequence seq. It returns a single value.
- it goes:
[ func(func(s1, s2),s3), ... , sn ]
-
reduce(lambda x,y: x+y, [47,11,42,13])
==>113 f = lambda a,b: a if (a > b) else b
reduce(f, [47,11,42,102,13])
- ==> 102
Logic
if条件语句后面需要跟随bool类型的数据,即True或者False。然而,如果不是bool类型的数据,可以(自动)将其转换成bool类型的数据,转换的过程是隐式的。
在Python中,None、空列表[]、空字典{}、空元组()、0等一系列代表空和无的对象会被转换成False。除此之外的其它对象都会被转化成True。
在命令if not 1中,1便会转换为bool类型的True。not是逻辑运算符非,not 1则恒为False。因此if语句if not 1之下的语句,永远不会执行。
- there is no
else if
in Python, onlyelif
Object and Class
Metaclass
- Stackoverflow e-satis metaclass
- 译文: 深刻理解Python中的元类(metaclass)
- Classes are objects too
- This object (the class) is itself capable of creating objects (the instances), and this is why it's a class.
- you can assign it to a variable
- you can copy it
- you can add attributes to it
- you can pass it as a function parameter
- Creating classes dynamically: like creating any object
- e.g: in a function
-
type
方法能动态的创建类: 接受一个类的描述作为参数,然后返回一个类- 为你的类增加方法? define a function with the proper signature and assign it as an attribute=>放入type的dictionary 参数中
Class variables
- in Python, class variables are internally handled as dictionaries. If a variable name is not found in the dictionary of the current class, the class hierarchy (i.e., its parent classes) are searched until the referenced variable name is found (if the referenced variable name is not found in the class itself or anywhere in its hierarchy, an AttributeError occurs).
- if any of its child classes overrides that value, then the value is changed in that child only.
- if the value is then changed in the Parent, that change is reflected also by any children that have not yet overridden the value
- see q3 8 interview qs
Class and its object
Copy
-
doc: copy — Shallow and deep copy operations
import copy
-
copy.copy(x)
- Return a shallow copy of x.
-
copy.deepcopy(x)
- Return a deep copy of x.
-
python中的深拷贝和浅拷贝理解
- 利用切片操作和工厂方法list方法拷贝就叫浅拷贝,只是拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。 id 一样
- 利用copy中的deepcopy方法进行拷贝就叫做深拷贝,外围和内部元素都进行了拷贝对象本身,而不是引用。 id 不同
-
Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
- Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块。
- copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。
- copy.deepcopy 深拷贝 拷贝对象及其子对象
Instantiation 实例化
- woodpecker 5.4. 类的实例化
-
Python 对象的实例化过程分析 init and new
- Python 的构造函数有两个,一个是我们最常用的 init ,另一个是很少用到的 new 。而从它们的函数定义 def new(cls, [...]) 和 def init(self, [...]) 可以知道, init 被调用时实例已经被创建(就是 self 参数所引用的);而 new 被调用的时候,实例不一定已被创建(暂时只能这么说),而 new 的第一个参数为当前类的引用。
Other
- Copy: python中的深拷贝和浅拷贝理解
- Swap:
- Python为什么不需要swap(a, b) Python以引用方式管理对象,你可以交换引用,但通常不能交换内存中的对象值。当然你也不需要这样做。
举例:
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
t = root.left
root.left = root.right
root.right = t
相当于:
root.left, root.right = root.right, root.left
Object Types
Assignment:
-
python赋值和拷贝----一切皆对象,参数皆引用
- 所谓“传值”也就是赋值的意思.
- Python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
- 当人们复制列表或字典时,就复制了对象列表的引用,如果改变引用的值,则修改了原始的参数
- zhihu
Basics
检查类型:
isinstance(obj, class)
-
if a Python object is a string?
+isinstance(obj, basestring)
for an object-to-test obj.
+ basestring
空对象? 检查空对象?
- 要返回空?
- return: 返回None,不是False也不是True
- return []: [],bool值为False
is vs ==
You use == when comparing values and is when comparing identities.
-
Python: "is None" vs "==None"
- "Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators."
- "is" is a quick id comparison, whereas "==" requires a dict lookup on both the "1" and "None" objects for the comparison operators
None
- None是一个特殊的常量。
- None is actually a null object!
- None和False不同。但None的布尔值是False
+** False的有None, 0, []** - None不是0。
None不是空字符串。
None和任何其他的数据类型比较永远返回False。
None有自己的数据类型NoneType。
你可以将None复制给任何变量,但是你不能创建其他NoneType对象。
number
整数取整:小数点后的都不要(所以是向0取整)(经过测试)
Operators
Division
Python 2 automatically performs integer arithmetic if both operands are integers. As a result, 5/2 yields 2, while 5./2 yields 2.5.
the “double-slash” (//) operator will always perform integer division, regardless of the operand types. That’s why 5.0//2.0 yields 2.0 even in Python 2.
Python 2中:
x = 4.5
y = 2
print x//y 结果是2.0
x = 4.5
y = 2
print x/y 结果是2.25
5//2 结果 2
5/2 结果 2
Python3中除法“/”变成了浮点除法,不默认整数除法,而//则保留仍然进行整数除法
Scope 作用域
-
Python的作用域 探讨: global name is not defined
- 在Python中,只有模块,类以及函数才会引入新的作用域,其它的代码块是不会引入新的作用域的。
- 在Python中,使用一个变量之前不必预先声明它,但是在真正使用它之前,它必须已经绑定到某个对象;而名字绑定将在当前作用域中引入新的变量,同时屏蔽外层作用域中的同名变量,不论这个名字绑定发生在当前作用域中的哪个位置。
Strings
- 用索引引用string时,string可被视为big-endian
-
str1= "1234"
, 则str1[0]=="1"
- c++也是
-
- Case 大小写
- Python string comparison is naturally case sensitive!
- 字符串操作
- 截取字符串
- str[0:3] #截取第一位到第三位的字符,即前闭后开
- 检查和匹配
- [python
- 字符串](http://blog.chinaunix.net/uid-7685522-id-2045810.html)
- s.isdigit() 所有字符都是数字
- isalpha
- str.isalpha 检查string是否全是alphabet,大写也符合!
- endswith
- 检查字符串是否为空 Most elegant way to check if the string is empty in Python?
- if not myString:
-
if a Python object is a string?
-
isinstance(obj, basestring)
for an object-to-test obj. - basestring
-
- join 字符串连接
Style
-
Python 续行符
- 当一条命令用续行符 (“\”) 分割成多行时, 后续的行可以以任何方式缩近, 此时 Python 通常的严格的缩近规则无需遵守。
- 在小括号, 方括号或大括号中的表达式 (如 定义一个 dictionary) 可以用或者不用续行符 (“\”) 分割成多行。
Variables, Objects, Types, References
python中的变量 和 引用
变量存储在内存中的值。这就意味着在创建变量时会在内存中开辟一个空间。
基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中。
因此,变量可以指定不同的数据类型,这些变量可以存储整数,小数或字符。
变量在内存中存储时,包含的信息:id,名称,数据,数据类型(由解释器决定)
Python的所有变量其实都是指向内存中的对象的一个指针/引用,所有的变量都是。此外,对象还分两类:一类是可修改的,一类是不可修改的。
函数传参
调用函数时,把参数里传入的东西对相应对象的引用依次赋给对应的内部变量。而此时,则要考虑到,外部namespace和函数内部namespace的隔离。
全局变量和本地变量
如果一个函数里面使用了一个变量,那么 Python 会先看看有没有对应的本地变量,如果没有找到,但找到一个全局变量,那么 Python 会把那个全局变量的引用赋给一个新的本地变量。所以,现在在函数里的那个变量和全局变量其实不是同一个变量,他们只不过暂时有了相同的引用。这样其实可以看作 Python 为你做了隐式的参数传递。 ==>> 局部里修改一个全局变量,全局变量会改变
强类型,弱类型?
- Python 是强类型语言?
- 是:
"1"+2
you will get traceback error - 强、弱类型
- 强类型strongly typed: 如果一种语言的所有程序都是well behaved——即不可能出现forbidden behaviors,则该语言为strongly typed。
弱类型weakly typed: 否则为weakly typed。比如C语言的缓冲区溢出,属于trapped errors,即属于forbidden behaviors..故C是弱类型
- 强类型strongly typed: 如果一种语言的所有程序都是well behaved——即不可能出现forbidden behaviors,则该语言为strongly typed。
- 弱类型语言,类型检查更不严格,如偏向于容忍隐式类型转换。譬如说C语言的int可以变成double。 这样的结果是:容易产生forbidden behaviours,所以是弱类型的
- 动态、静态类型
- 静态类型 statically: 如果在编译时拒绝ill behaved程序,则是statically typed;
动态类型dynamiclly: 如果在运行时拒绝ill behaviors, 则是dynamiclly typed。
静态类型可以分为两种:
如果类型是语言语法的一部分,在是explicitly typed显式类型;
如果类型通过编译时推导,是implicity typed隐式类型, 比如ML和Haskell
- 静态类型 statically: 如果在编译时拒绝ill behaved程序,则是statically typed;
- 例子:
- 无类型: 汇编
弱类型、静态类型 : C/C++
弱类型、动态类型检查: Perl/PHP
强类型、静态类型检查 :Java/C#
强类型、动态类型检查 :Python, Scheme
静态显式类型 :Java/C
静态隐式类型 :Ocaml, Haskell
- 无类型: 汇编
- 是:
Global vars
- 浅析Python中的Python全局变量
- 应该尽量避免使用Python全局变量。不同的模块都可以自由的访问全局变量,可能会导致全局变量的不可预知性。
With..as..
-
深入理解Python的With语句
- Python对with的处理基本思想是with所求值的对象必须有一个enter()方法,一个exit()方法。
- 理解Python中的with…as…语法
- Understanding Python's "with" statement
Topics
Commandline
-
Python Command Line Arguments
- The Python
sys
module provides access to any command-line arguments via thesys.argv
(list)
- The Python
Run programs from commandline
- learn py the hard way Exercise 50: Your First Website
- run
python bin/app.py
would go, butcd bin/
,python app.py
would go wrong.- In all Python projects you do not cd into a lower directory to run things. You stay at the top and run everything from there so that all of the system can access all the modules and files.
Concurrency
对于任何Python程序,不管有多少的处理器,任何时候都总是只有一个线程在执行。 "不要使用多线程,请使用多进程。"GIL对诸如当前线程状态和为垃圾回收而用的堆分配对象这样的东西的访问提供着保护。然而,这对Python语言来说没什么特殊的,它需要使用一个GIL。这是该实现的一种典型产物。现在也有其它的Python解释器(和编译器)并不使用GIL。虽然,对于CPython来说,自其出现以来已经有很多不使用GIL的解释器。
由于GIL,python的多线程,threading非常适合i/o密集,而不适合cpu密集。如果要利用多核,则要使用Multiprocessing。
multiprocessing pool & dummy
- multiprocessing.dummy 是 multiprocessing 模块的完整克隆,唯一的不同在于 multiprocessing 作用于进程,而 dummy 模块作用于线程; 可以针对 IO 密集型任务和 CPU 密集型任务来选择不同的库. IO 密集型任务选择multiprocessing.dummy,CPU 密集型任务选择multiprocessing.
- multiprocessing.dummy 模块与 multiprocessing 模块的区别: dummy 模块是多线程,而 multiprocessing 是多进程, api 都是通用的。 所有可以很方便将代码在多线程和多进程之间切换。
- multiprocessing.dummy replicates the API of multiprocessing but is no more than a wrapper around the threading module.
- multiprocessing.pool和dummy都可以使用map来简化多线程
- 实例:python-multi-threading使用multiprocessing.dummy
- python 进程池1 - Pool使用简介
GIL
- python 线程,GIL 和 ctypes
- Global Interpreter Lock ,意即全局解释器锁
- 在 Python 语言的主流实现 CPython 中,GIL 是一个货真价实的全局线程锁,在解释器解释执行任何 Python 代码时,都需要先获得这把锁才行,在遇到 I/O 操作时会释放这把锁。如果是纯计算的程序,没有 I/O 操作,解释器会每隔 100 次操作就释放这把锁,让别的线程有机会执行(这个次数可以通过 sys.setcheckinterval 来调整)。
- 所以虽然 CPython 的线程库直接封装操作系统的原生线程,但 CPython 进程做为一个整体,同一时间只会有一个获得了 GIL 的线程在跑,其它的线程都处于等待状态等着 GIL 的释放。
- 这也就解释了之前的实验结果:虽然有两个死循环的线程,而且有两个物理 CPU 内核,但因为 GIL 的限制,两个线程只是做着分时切换,总的 CPU 占用率还略低于 50%。
- 历史原因:多核 CPU 在 1990 年代还属于类科幻,Guido van Rossum 在创造 python 的时候,也想不到他的语言有一天会被用到很可能 1000+ 个核的 CPU 上面,一个全局锁搞定多线程安全在那个时代应该是最简单经济的设计了。简单而又能满足需求,那就是合适的设计
-
解决:
- Python 在 2.6 里新引入了 multiprocessing 这个多进程标准库,让多进程的 python 程序编写简化到类似多线程的程度,大大减轻了 GIL 带来的不能利用多核的尴尬。
- C拓展:如果不想用多进程这样重量级的解决方案,还有个更彻底的方案,放弃 Python,改用 C/C++。当然,你也不用做的这么绝,只需要把关键部分用 C/C++ 写成 Python 扩展,其它部分还是用 Python 来写,让 Python 的归 Python,C 的归 C。一般计算密集性的程序都会用 C 代码编写并通过扩展的方式集成到 Python 脚本里(如 NumPy 模块)。在扩展里就完全可以用 C 创建原生线程,而且不用锁 GIL,充分利用 CPU 的计算资源了。不过,写 Python 扩展总是让人觉得很复杂。
-
ctypes: Python 还有另一种与 C 模块进行互通的机制 : ctypes
- 利用 ctypes 绕过 GIL: ctypes 与 Python 扩展不同,它可以让 Python 直接调用任意的 C 动态库的导出函数。
- Python中开线程,用C跑
- GIL WIKI
-
Understanding GIL
- Python 3.2 -> New GIL
- 在新的GIL实现中,用一个固定的超时时间来指示当前的线程放弃全局锁。在当前线程保持这个锁,且其他线程请求这个锁的时候,当前线程就会在5ms后被强制释放掉这个锁。
Debug
-
Python 代码调试技巧
- pdb: pdb doc
- pyCharm (from JetBrains)
- PyDev
Encoding
理解unicode, utf-8
- unicode是字符集的映射(编码的映射),utf-8等等是编码方式(在计算机中怎么存储)。 gbk,ascii也是编码,不过不是对应unicode字符集。
- unicode用数字0-0x10FFFF来映射字符
- UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。一个unicode编码按16进制很明显会超过一个字节,所以如何按字节存储于计算机中,就是编码方案。
- 通用字符集(Universal Character Set, UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。
-
\u7edf\u4e00\u7801
("统一码")便是一个unicode编码序列
Python's encoding problems
Source code encoding
- PEP 0263 -- Defining Python Source Code Encodings
- Python will default to ASCII as standard encoding if no otherencoding hints are given.
- To define a source code encoding, a magic comment must be placed into the source files either as first or second line in the file, such as:
# coding=<encoding name>
#!/usr/bin/python
# -*- coding: <encoding name> -*-
- More precisely, the first or second line must match the regular expression
"coding[:=]\s*([-\w.]+)"
.-
\s
matches any whitespace character -
\w
matches any alphanumeric character and the underscore -
\W
matches any non-alphanumeric character
-
Unicode? String?
- 任何两种字符编码之间如果想完成转化,必须要通过unicode这个桥梁,先把它转化成unicode对象;+ unicode对象直接进行输出,往往会出现乱码,需要解码成str对象。
-
str.encode()
实际上就等价于str.decode(sys.defaultencoding).encode()
;而python的默认编码则是ascii -
unicode(string [, encoding[, errors]])
-> object
这个函数的作用是将string按照encoding的格式编码成为unicode对象。 -
u"xxx"
对应于unicode("xxx", 'utf-8')
(如果文件/字符串编码是utf-8)- 首先要注意区分,一个字符的不同stage,
- 在编辑器中输入时是一个stage(或者说在文件/磁盘中存在是一个stage),此时的编码由文件的encoding决定
- 而在python程序中存在为一个对象时,是第二个stage;
- 输出(比如在命令行)时,则是第三个stage。
-
u"笔记"
在python程序中,将存在为一个unicode对象(type unicode),即u'\u7b14\u8bb0'
-
print u"笔记"
将输出 笔记
-
- 而对于
string="笔记"
,则仍是一个string对象,直接输出会显示乱码。正确输出,需要先经过两步,-
string.decode("utf-8")
假定python程序文件的保存方式是utf-8, 这时候,string仍是一个str type - 然后用
newstr = unicode(string, 'utf-8')
输出,则可以得到正确输出 笔记 . 这时,newstr是一个 unicode type
-
- 首先要注意区分,一个字符的不同stage,
- u"xxx"的意思是,xxx是一个Unicode编码序列,所以xxx进入python程序时,就会被作为unicode来处理,因此print之,也是正确的输出。
- 查看系统的encoding
import sys
sys.stdout.encoding
- cp936(microsoft) => GBK
python 字符编码与解码——unicode、str和中文:UnicodeDecodeError: 'ascii' codec can't decode
- 在python中,编码:unicode-->str;解码str-->unicode.既然是编码,那么就和密码领域一样,编码和解码自然涉及到编码/解码方案(对应加密或者解密算法),unicode相当于明文。在python中,编码函数是encode(),解码函数是decode()。需要注意的一点是,如果我们调用str.encode(),这里涉及到一个隐式的类型转化,会现将str转化成unicode,才能进行编码,这也是不太容易理解的地方。所以,str.encode()实际上就等价于str.decode(sys.defaultencoding).encode().而sys.defaultencoding一般是ascii,它是不能用来编码中文字符的。
- python默认采用ascii编码,而中文编码不在ascii编码能够表示的范围之内,所以string无法将“我的”作为ascii编码保存为str类型。
- 字符编码/解码函数:
- unicode:这个是python的内建函数,位于unicode类。
unicode(string [, encoding[, errors]]) -> object
这个函数的作用是将string按照encoding的格式编码成为unicode对象。
省略参数将用python默认的ASCII来解码 - 举例:
unicode(someChineseString, "utf-8")
则是将字符按照utf8格式转换成unicode
- unicode:这个是python的内建函数,位于unicode类。
- 任何两种字符编码之间如果想完成转化,必须要通过unicode这个桥梁,先把它抓化成unicode对象;unicode对象直接进行输出,往往会出现乱码,需要解码成str对象。
- 在python中需要使用unicode需要注意:
- 程序中出现字符串时一定要加一个前缀u
- 不要用str()函数,用Unicode()代替
- 不要用过时的string模块。如果传给它非ASCII码,它会把一切搞砸。
- 不到必须时不要在你的程序里编解码Unicode字符,只在你要写入文件或者数据库或者网络时,才调用encode()函数和decode()函数。
- 使用什么字符编码,就要采用对应的字符集进行解码
- 内建的str()函数和chr()函数不能处理Unicode,它们只能处理常规ASCII编码的字符串,如果一个Unicode字符串作为参数传给了str()函数,它会首先被转换成ASCII码字符串然后交给str()函数。
Refs
- 字符集和字符编码(Charset & Encoding)
- 字符编码简介
- python 字符编码与解码——unicode、str和中文:UnicodeDecodeError: 'ascii' codec can't decode
-
Python: Processing Unicode: unicodedata Module Tutorial
-
import
unicodedata - find a character's Unicode name?
- get Unicode character's codepoint in decimal?
- get the Unicode char of a given name?
-
字符编码简介
需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码(定长码),也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。
Errors
- ValueError
- Raised when a built-in operation or function receives an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception such as IndexError.
- 例如,
str.index('\n')
或者str.index('\n')
。 如果str中没有'\n',那么raise ValueError
Errors you meet
- IndentationError
File
- Python Files I/O
- how do i read the last line of a text file?
- 逐行读取文件
- 逐行读取,每行自带 '\n' !!!
- python中逐行读取文件的最佳方式
利用迭代协议让for循环自动调用next从而前进到文件的下一行,而不是直接把文件读取到内存中,有三点原因:写法简单,运行速度快,节省内存。示例如下:
for line in open('myfile.py'):
...print line.upper()`
而不是使用readlines方法:
for line in open('myfile.py').readlines():
...print line.upper()`
-
How to read large file, line by line in python
with open(...) as f: for line in f: <do something with line>
The with statement handles opening and closing the file, including if an exception is raised in the inner block. The for line in f treats the file object f as an iterable, which automatically uses buffered IO and memory management so you don't have to worry about large files.
Garbage Collection
- CPython 使用 mark-sweep & 分代回收
-
Python垃圾回收机制
- “标记-清除”法是为了解决循环引用问题。可以包含其他对象引用的容器对象(如list, dict, set,甚至class)都可能产生循环引用,为此,在申请内存时,所有容器对象的头部又加上了PyGC_Head来实现“标记-清除”机制。
- 在为对象申请内存的时候,可以明显看到,实际申请的内存数量已经加上了PyGC_Head的大小 (// objimpl.h, gcmodule.c)
Sort
- Sorting Mini-HOW TO
- Problems
Sorted
- python sorted 例子
- 一般来说,cmp和key可以使用lambda表达式。
- cmp
sorted(L, cmp=lambda x,y:cmp(x[1],y[1]))
- Key
sorted(L, key=lambda x:x[1]))
- reverse
sorted([5, 2, 3, 1, 4], reverse=True)
- 效率key>cmp(key比cmp快)
Regular Expression
- \w alphanumerice
- \W nonalphanumeric
- Python正则表达式指南
- tutorialspoint: Python Regular Expressions
- Functions
-
re.search(pattern, string, flags=0)
- Scan through string looking for the first location where the regular expression pattern produces a match, and return a corresponding MatchObject instance.
- 从字符串开头查找,只要子串符合就可以
-
re.match(pattern, string, flags=0)
- 从字符串开头比较,必须是从头开始的匹配
re.split(pattern, string, maxsplit=0, flags=0)
-
re.findall(pattern, string, flags=0)
- Return all non-overlapping matches of pattern in string, as a list of strings.
re.sub(pattern, repl, string, count=0, flags=0)
-
Regex Lib
-
re.sub('[^0-9a-zA-Z]+', '*', s)
Replace all non-alphanumeric characters in a string re.sub('\W+', '', s)
Functions&Utilities
Sort/Sorted
sorted函数是内建函数,他接受一个序列,返回有序的副本。他与sort的唯一区别就是会返回副本 (sorted is not in place!)
问题:如何根据一个字典序列中某一项的值,来对整个序列排序?
How do I sort a list of dictionaries by values of the dictionary in Python?
Python: Sorting a List of Objects or Dictionaries by Multiple Keys Bidirectionally
Swap?
-
Python为什么不需要swap(a, b)
Python以引用方式管理对象,你可以交换引用,但通常不能交换内存中的对象值。当然你也不需要这样做。
a,b = b,a 即可
def swap(t1, t2):
t2, t1 = t1, t2
return
The code above does not do swap! 全局命名空间和局部命名空间是隔离的,所以:The calling namespace is
not changed,即交换的是局部变量。
def swap(a,b):
tmp = a
a = b
b = tmp
The code above does not do swap! 同样是因为局部namespace的隔离。
但是如果在主程序中:
tmp = swap_a
swap_a = swap_b
swap_b = tmp
则swap_a, swap_b 可以交换
Time
-
测量Python代码运行时间
- 使用timeit模块
- 使用time模块
+ Python的标准库手册推荐在任何系统下都尽量使用time.clock()
(CPU时间)
System&Software
Interaction with the system
- 如何调用windows命令
import os
os.system("dir")
Settings
-
!/usr/bin/python
-
Why do people write #!/usr/bin/env python on the first line of a Python script?
- If you have several versions of Python installed, /usr/bin/env will ensure the interpreter used is the first one on your environment's $PATH. The alternative would be to hardcode something like #!/usr/bin/python; that's ok, but less flexible.
- In Unix, an executable file that's meant to be interpreted can indicate what interpreter to use by having a #! at the start of the first line, followed by the interpreter (and any flags it may need).
Questions/Problems
重点:
多态?反射机制?
Iterator&Generator?
数据结构(set,dict, tuple)
Decorators?
内置函数,例如set___, __import等
特殊的语句yield, with
垃圾回收机制
Decorators的定义,以及用法
python线程机制以及为啥python多线程很慢。
Errors and Exceptions
8 Essential Python Interview Questions*
list = ['a', 'b', 'c', 'd', 'e']
print list[10:]
输出[],却不会引起IndexError错误
attempting to access a slice of a list at a starting index that exceeds the number of members in the list will not result in an IndexError and will simply return an empty list.
What makes this a particularly nasty gotcha is that it can lead to bugs that are really hard to track down since no error is raised at runtime.