1. 程式人生 > >重新學習python系列(一)? WTF?

重新學習python系列(一)? WTF?

repl sin .so enumerate ram generator false ica 不變

重新學習python:
兩年前學了點python之後就一直沒做做過啥項目, 基本上全忘光了,復習一下搞點事情

or |
and &

ord() ascii轉16進制

chr() 16進制轉ascii

>>> u‘ABC‘.encode(‘utf-8‘)
‘ABC‘
>>> u‘中文‘.encode(‘utf-8‘)
‘\xe4\xb8\xad\xe6\x96\x87‘
>>> ‘abc‘.decode(‘utf-8‘)
u‘abc‘
>>> ‘\xe4\xb8\xad\xe6\x96\x87‘.decode(‘utf-8‘)
u‘\u4e2d\u6587‘
>>> print ‘\xe4\xb8\xad\xe6\x96\x87‘.decode(‘utf-8‘)
中文

數組list:

append(‘a‘) 插到後面
insert(1,‘a‘) 指定位置
pop() 刪除末尾 刪除指定

元組tuple:
只有1個元素的tuple定義時必須加一個逗號,,來消除歧義:

>>> t = (1,)
>>> t
(1,)

“可變的”tuple:
t = (‘a‘, ‘b‘, [‘A‘, ‘B‘])

dict:key-value存儲方式
通過in判斷key是否存在:

iteritems
>>> ‘Thomas‘ in d
False

通過dict提供的get方法:如果key不存在,可以返回None,或者自己指定的value(不改變dict)

dict = {
    ‘a‘ : "this a",
    ‘b‘ : "this b",
    ‘c‘ : "this c",
    ‘d‘ : "this d"
}
print dict.get(‘f‘,"hello")
print dict

hello
{‘a‘: ‘this a‘, ‘c‘: ‘this c‘, ‘b‘: ‘this b‘, ‘d‘: ‘this d‘}

pop(key)方法,對應的value也會從dict中刪除

和list比較,dict有以下幾個特點:

  1. 查找和插入的速度極快,不會隨著key的增加而增加;
  2. 需要占用大量的內存,內存浪費多。

而list相反:

  1. 查找和插入的時間隨著元素的增加而增加;
  2. 占用空間小,浪費內存很少

set:一組key的集合,但不存儲value。由於key不能重復,所以,在set中,沒有重復的key。
通過add(key)方法可以添加元素到set中,可以重復添加,但不會有效果
通過remove(key)方法可以刪除元素:

>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
set([2, 3])
>>> s1 | s2
set([1, 2, 3, 4])

再議不可變對象

上面我們講了,str是不變對象,而list是可變對象。

對於可變對象,比如list,對list進行操作,list內部的內容是會變化的,比如:

>>> a = [c, b, a]
>>> a.sort()
>>> a
[a, b, c]

而對於不可變對象,比如str,對str進行操作呢:

>>> a = abc
>>> a.replace(a, A)
Abc
>>> a
abc

雖然字符串有個replace()方法,也確實變出了Abc,但變量a最後仍是abc,應該怎麽理解呢?

我們先把代碼改成下面這樣:

>>> a = abc
>>> b = a.replace(a, A)
>>> b
Abc
>>> a
abc

要始終牢記的是,a是變量,而abc才是字符串對象!有些時候,我們經常說,對象a的內容是abc,但其實是指,a本身是一個變量,它指向的對象的內容才是abc

調用函數

http://docs.python.org/2/library/functions.html#abs

如何判斷一個對象是可叠代對象呢?方法是通過collections模塊的Iterable類型判斷:

>>> from collections import Iterable
>>> isinstance(‘abc‘, Iterable) # str是否可叠代
True
>>> isinstance([1,2,3], Iterable) # list是否可叠代
True
>>> isinstance(123, Iterable) # 整數是否可叠代
False

Python內置的enumerate函數可以把一個list變成索引-元素對

>>> for i, value in enumerate([‘A‘, ‘B‘, ‘C‘]):
...     print i, value
...
0 A
1 B
2 C
>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
...     print x, y
...
1 1
2 4
3 9

for循環其實可以同時使用兩個甚至多個變量,比如dictiteritems()可以同時叠代key和value

>>> d = {‘x‘: ‘A‘, ‘y‘: ‘B‘, ‘z‘: ‘C‘ }
>>> for k, v in d.iteritems():
...     print k, ‘=‘, v
... 
y = B
x = A
z = C

列表生成式則可以用一行語句代替循環生成上面的list:

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

>>> [m + n for m in ‘ABC‘ for n in ‘XYZ‘]
[‘AX‘, ‘AY‘, ‘AZ‘, ‘BX‘, ‘BY‘, ‘BZ‘, ‘CX‘, ‘CY‘, ‘CZ‘]

>>> import os # 導入os模塊,模塊的概念後面講到
>>> [d for d in os.listdir(‘.‘)] # os.listdir可以列出文件和目錄
[‘.emacs.d‘, ‘.ssh‘, ‘.Trash‘, ‘Adlm‘, ‘Applications‘, ‘Desktop‘, ‘Documents‘, ‘Downloads‘, ‘Library‘, ‘Movies‘, ‘Music‘, ‘Pictures‘, ‘Public‘, ‘VirtualBox VMs‘, ‘Workspace‘, ‘XCode‘]

list中所有的字符串變成小寫:
list.lower()

>>> L = [‘Hello‘, ‘World‘, ‘IBM‘, ‘Apple‘]
>>> [s.lower() for s in L]
[‘hello‘, ‘world‘, ‘ibm‘, ‘apple‘]

使用內建的isinstance函數可以判斷一個變量是不是字符串:

>>> x = ‘abc‘
>>> y = 123
>>> isinstance(x, str)
True
>>> isinstance(y, str)
False

生成器generator: 只要把一個列表生成式的[]改成(),就創建了一個generator:

g = (x * x for x in range(10))

用 g.next() 打印
正確的方法是使用for循環,因為generator也是可叠代對象

>>> g = (x * x for x in range(10))
>>> for n in g:
...     print n
...
0
1
4
9

print b改為yield b就可以變成生成器generator:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b             #print b
        a, b = b, a + b
        n = n + 1

這就是定義generator的另一種方法。如果一個函數定義中包含yield關鍵字,那麽這個函數就不再是一個普通函數,而是一個generator:

>>> fib(6)
<generator object fib at 0x104feaaa0>

這裏,最難理解的就是generator和函數的執行流程不一樣。函數是順序執行,遇到return語句或者最後一行函數語句就返回。而變成generator的函數,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。

舉個簡單的例子,定義一個generator,依次返回數字1,3,5:

>>> def odd():
...     print ‘step 1‘
...     yield 1
...     print ‘step 2‘
...     yield 3
...     print ‘step 3‘
...     yield 5
...
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

可以看到,odd不是普通函數,而是generator,在執行過程中,遇到yield就中斷,下次又繼續執行。執行3次yield後,已經沒有yield可以執行了,所以,第4次調用next()就報錯。

回到fib的例子,我們在循環過程中不斷調用yield,就會不斷中斷。當然要給循環設置一個條件來退出循環,不然就會產生一個無限數列出來。

同樣的,把函數改成generator後,我們基本上從來不會用next()來調用它,而是直接使用for循環來叠代:

>>> for n in fib(6):
...     print n
...
1
1
2
3
5
8

map()

>>> def f(x):
...     return x * x
...
>>> map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

>>> def add(x, y):
...     return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

upper()——所有字母大寫

lower()——所有字母小寫

capitalize()——首字母大寫,其他字母小寫

title()——所有單詞首字母大寫,其他小寫


filter()把傳入的函數依次作用於每個元素,然後根據返回值是True還是False決定保留還是丟棄該元素

def is_odd(n):
    return n % 2 == 1

filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])
# 結果: [1, 5, 9, 15]

Python內置的sorted()函數就可以對list進行排序:
它還可以接收一個比較函數來實現自定義的排序。比如,如果要倒序排序,我們就可以自定義一個reversed_cmp函數:

def reversed_cmp(x, y):
    if x > y:
        return -1
    if x < y:
        return 1
    return 0

傳入自定義的比較函數reversed_cmp,就可以實現倒序排序:

>>> sorted([36, 5, 12, 9, 21], reversed_cmp)
[36, 21, 12, 9, 5]

忽略大小寫來比較兩個字符串,實際上就是先把字符串都變成大寫(或者都變成小寫),再比較。

返回閉包時牢記的一點就是:返回函數不要引用任何循環變量,或者後續會發生變化的變量。

閉包

註意到返回的函數在其定義內部引用了局部變量args,所以,當一個函數返回了一個函數後,其內部的局部變量還被新函數引用,所以,閉包用起來簡單,實現起來可不容易。

另一個需要註意的問題是,返回的函數並沒有立刻執行,而是直到調用了f()才執行。我們來看一個例子:

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()

在上面的例子中,每次循環,都創建了一個新的函數,然後,把創建的3個函數都返回了。

你可能認為調用f1(),f2()和f3()結果應該是1,4,9,但實際結果是:

>>> f1()
9
>>> f2()
9
>>> f3()
9

匿名函數lambda x: x * x實際上就是:

def f(x):
    return x * x


裝飾器:
def log(func):
    def wrapper(*args, **kw):
        print ‘call %s():‘ % func.__name__
        return func(*args, **kw)
    return wrapper
@log
def now():
    print ‘2013-12-25

now()

@log放到now()函數的定義處,相當於執行了語句:now = log(now)


偏函數
import functools
def func(x,y):
    print x+y
func2 = functools.partial(func, y=‘fuck‘)
func2("hello ")


模塊別名:
try:
    import cStringIO as StringIO
except ImportError: # 導入失敗會捕獲到ImportError
    import StringIO

重新學習python系列(一)? WTF?