看例子,學 Python(二)

看例子,學 Python(二)

看例子,學 Python(一)
看例子,學 Python(三)html

模塊

文件 mymath.py 定義了函數 fibfacmymath.py 就是一個模塊。python

A module is a file containing Python definitions and statements.算法

自定義模塊

導入模塊:segmentfault

>>> import mymath

mymath.py 須在當前目錄。數據結構

查看模塊幫助:函數

>>> help(mymath)
Help on module mymath:

NAME
    mymath

FUNCTIONS
    fib(n)
...

列出模塊屬性:測試

>>> dir(mymath)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fac', 'fib']

訪問模塊屬性:ui

>>> mymath.__name__
'mymath'
>>> mymath.__doc__
>>>

模塊暫時尚未 docstring,因此 mymath.__doc__ 爲空。
訪問函數屬性:命令行

>>> mymath.fac
<function fac at 0x00000000026DBA60>
>>> mymath.__dict__['fac']
<function fac at 0x00000000026DBA60>

兩種方式效果同樣。__dict__(字典)隱含於每一個對象中,模塊對象也不例外。code

爲模塊 mymath 添加 docstring

"""My math utilities."""

def fib(n):
    ...

那麼,下次調用 help 就能顯示這個 docstring 了:

>>> help(mymath)
Help on module mymath:

NAME
    mymath - My math utilities.
...

內建模塊

Python 自帶了 math 模塊,來研究一下:

>>> import math
>>> help(math)
Help on built-in module math:

NAME
    math
...

列出屬性:

>>> dir(math)
['__doc__', '__loader__', ..., 'factorial', ...]

可見內建模塊 math 也提供了階乘(factorial),看看它怎麼用:

>>> help(math.factorial)
Help on built-in function factorial in module math:

factorial(...)
    factorial(x) -> Integral

    Find x!. Raise a ValueError if x is negative or non-integral.

調用試試:

>>> math.factorial(4)
24
>>> math.factorial(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: factorial() not defined for negative values
>>>

內建函數在異常處理方面作得會比較好。
值得注意的是,內建模塊並不必定由 Python 文件定義,好比 Python 的安裝目錄下其實並無 math.py

doctest

顧名思義,docstring 裏嵌測試用例,就是 doctest
好處是,既可作文檔又可作測試,也避免了註釋裏的示例代碼失效的問題。
fac 添加 doctest

def fac(n):
    """
    >>> fac(4)
    24
    """
    ...

這就像交互環境下的輸入輸出同樣。>>> 打頭的是輸入,緊接着的即是輸出。
下面來運行試試:

$ python -m doctest -v mymath.py
Trying:
    fac(4)
Expecting:
    24
ok
2 items had no tests:
    mymath
    mymath.fib
1 items passed all tests:
   1 tests in mymath.fac
1 tests in 3 items.
1 passed and 0 failed.
Test passed.

-m 指定使用 Python 的內建模塊 doctest-v 表示顯示詳細信息。
這只是運行 doctest 的方式之一,還能夠添加代碼到 mymath.pymain 函數:

if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True)

後續就沒必要指定命令行參數 -m -v 了。

做爲練習,咱們能夠爲 fib 添加 doctest

def fib(n):
    """Get the nth Fibonacci number.
    
    >>> fib(0)
    0
    >>> fib(1)
    1
    >>> fib(2)
    1
    >>> fib(6)
    8
    """
   ...

字典

對應於官方教程 5.5. Dictionaries
前面介紹模塊時,提到了對象的特殊屬性 __dict__ ,它其實就是一個字典(dict)。
Python 的字典,相似於 C++ 或 Java 的 map,是存儲鍵值映射關係的一種數據結構。咱們且不去關心它的實現細節,是平衡二叉樹仍是哈希表,目前並不重要。

Char Counter

第一個例子,實現函數 char_counter,以字典的形式,返回字符串中每一個字符出現的次數。
函數的 doctest 已經寫出來了,你只要讓它經過便可。

def char_counter(chars):
    """Count the number of each character.

    >>> d = char_counter('banana')
    >>> d['a']
    3
    >>> d['b']
    1
    >>> d['n']
    2
    """
    pass

初版

def char_counter(chars):
    counter = {}  # 初始化爲空字典
    for c in chars:
        counter[c] += 1  # KeyError!
    return counter

counter[c] += 1 一句將引起 KeyError 異常,由於它沒有考慮字典中鍵不存在的狀況。

第二版

def char_counter(chars):
    counter = {}
    for c in chars:
        if c in counter:
            counter[c] += 1
        else:
            counter[c] = 1
    return counter

此版處理了鍵不存在的問題,可是 if...else 總歸顯得不夠優雅,Python 是一門簡潔優雅的語言,應該有更好的方法。

第三版

def char_counter(chars):
    counter = {}
    for c in chars:
        counter[c] = counter.get(c, 0) + 1
    return counter

經過字典的 get 方法,保證當鍵不存在時,也能獲得妥善初始化了的值。

Word Counter

Word Counter 與 Char Counter 相似,以字典形式返回一段文本中每一個單詞出現的次數。

給定一段文本以下:

text = """Remember me when I am gone away,
Gone far away into the silent land;
When you can no more hold me by the hand,
Nor I half turn to go yet turning stay.
Remember me when no more day by day
You tell me of our future that you plann'd:
Only remember me; you understand
It will be late to counsel then or pray.
Yet if you should forget me for a while
And afterwards remember, do not grieve:
For if the darkness and corruption leave
A vestige of the thoughts that once I had,
Better by far you should forget and smile
Than that you should remember and be sad."""

首先經過 str.splittext 分割成單詞的列表,而後計數的過程就跟 Char Counter 同樣了,各位能夠當作練習。

不難發現,Char Counter 和 Word Counter 在算法上有類似的地方,因此 Python 其實已經提供了這樣一個算法。

>>> import collections
>>> help(collections.Counter)
Help on class Counter in module collections:

class Counter(builtins.dict)
 |  Dict subclass for counting hashable items.  Sometimes called a bag
 |  or multiset.  Elements are stored as dictionary keys and their counts
 |  are stored as dictionary values.
...

根據幫助信息,Counter 是一個類,而且繼承自 dict。姑且跳過類定義的語法,篇幅所限。
使用 collections.Counter

from collections import Counter
counter = Counter(text.split())
print(counter['you'])  # 6

既然繼承自字典,Counter 一定提供了一些額外的方法,好比獲取出現頻率最高的幾個鍵值對:

print(counter.most_common(3))
# [('you', 6), ('me', 5), ('the', 4)]

這就涉及了一個對字典以值來排序的問題。
怎麼對字典以值來排序呢?確實有幾種方式,下面以 Char Counter 爲例。

使用 dict.get

首先,排序用 sorted

>>> help(sorted)
...
sorted(iterable, key=None, reverse=False)

輸入是一個 iterable,能夠用 for 迭代的即是 iterable 的,字典固然也是。
可是若是直接對字典排序,即是以鍵來排序:

counter = char_counter('banana')
print(sorted(counter))
# ['a', 'b', 'n']

爲了以值來排序,能夠爲 sorted 指定 key

counter = char_counter('banana')
print(sorted(counter, key=counter.get))
# ['b', 'n', 'a']

這樣 sorted 在比較時,就不是比較鍵,而是比較 counter.get(鍵)
然而這樣的排序結果並非咱們想要的,由於它只有鍵而沒有值。

使用 itemgetter

字典的 items 方法返回「鍵值對」列表,咱們能夠對這個列表按值排序。

print(counter.items())
# dict_items([('b', 1), ('a', 3), ('n', 2)])

這個列表裏的每一個元素都是一個鍵值對,由元組(tuple)表示。元組至關於只讀的列表,後面會有介紹。

from operator import itemgetter
print(sorted(counter.items(), key=itemgetter(1)))
# [('b', 1), ('n', 2), ('a', 3)]

指定 sortedkeyitemgetter(1),便以每一個鍵值對元組下標爲 1 的元素進行排序。

最後,不妨來看一下 dict.items 的幫助:

>>> help(dict.items)

items(...)
    D.items() -> list of D's (key, value) pairs, as 2-tuples

使用 lambda

除了 itemgetter,還能夠用 lambda
簡單來講,lambda 就是匿名函數(沒有名字的函數),短小精悍,臨時建立臨時使用,通常做爲參數傳遞,不必有名字。

方式一:

sorted(counter.items(), key=lambda x: x[1])

x 爲鍵值對元組。

方式二:

sorted(counter.items(), key=lambda (k,v): v)

直接在參數上把元組展開。

方式三:

sorted(counter.items(), key=lambda (k,v): (v,k))

交互鍵值順序,元組在比較時,依次比較裏面的每一個元素。

降序排序

降序排序,只需指定 reverse 參數便可:

sorted(counter.items(), key=itemgetter(1), reverse=True)

元組

元組(tuple)是隻讀的列表,雖然在底層實現上有很大不一樣。

>>> a = (1, "hello")
>>> a[0]
1
>>> a[0] = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

可將其它序列類型(str, list)轉換成元組:

>>> s = tuple("abcde")
>>> s
('a', 'b', 'c', 'd', 'e')

看例子,學 Python(一)
看例子,學 Python(三)

相關文章
相關標籤/搜索