看例子,學 Python(三)

看例子,學 Python(三)

看例子,學 Python(一)
看例子,學 Python(二)python

建立一個目錄 myutil,把 mymath.py 挪到裏面,再添加一個空文件 __init__.pysegmentfault

myutil/
    __init__.py
    mymath.py

myutil 即是一個包(package)。ide

import

最直接的用法:函數

>>> import myutil.mymath
>>> myutil.mymath.fac(4)
24

缺點是調用 fac 時太長,包和模塊做爲前綴都要寫全。可是寫成 import myutil.mymath.fac 也是不對的。
經過 import 的語法(syntax):優化

import <包>.<包>.<包|模塊>

能夠看出:code

  • 最後一項(item)能夠是包也能夠是模塊,前面的必須是包;對象

  • 最後一項不能夠是類、函數或變量的定義。ip

根據語法來看,能夠 import 一個包:內存

>>> import myutil
>>> help(myutil)
...

可是這樣並無什麼實際用處,由於沒法就此調用具體的函數(類、變量):ci

>>> myutil.mymath.fac(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'myutil' has no attribute 'mymath'

from...import

若是要避免調用時帶着一串前綴,能夠用 from...import

>>> from myutil.mymath import fac
>>> fac(4)  # 再也不須要前綴
24

一次 import 多個時以逗號分割:

>>> from myutil.mymath import fib, fac

一次 import 全部:

>>> from myutil.mymath import *

from...import... 避免了前綴,可是也污染了名字,使用時需權衡。

高階函數

高階函數(higher-order)就是操做或返回其它函數的函數。
下面是幾個經典的高階函數,其它稍微函數式一點的語言裏通常也有。

reduce(規約)

reduce 重寫階乘:

import operator, functools
def fac(n):
    return functools.reduce(operator.mul, range(1, n+1))

reduce 求和:

def sum(n):
    return functools.reduce(operator.add, range(1, n+1))

Python 的 reduce 就至關於 C++ 的 accumulate(C++17 已經新增 reduce)。

std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = std::accumulate(v.begin(), v.end(), 0);  // 求和
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());  // 求積

map(映射)

>>> list(map(bool, [None, 0, "", u"", list(), tuple(), dict(), set(), frozenset()]))
[False, False, False, False, False, False, False, False, False]

None、0、空字符串、以及沒有元素的容器對象均可視爲 False,反之爲 True

filter(過濾)

>>> list(filter(bool, [None, 0, "", 1]))
[1]

數據模型

== vs. is

== 判斷值是否相等,is 判斷兩個變量是否爲同一個對象。
這就好像 Java 裏的 ==equals 同樣。
下面是一些例子:

>>> a, b = 1, 1
>>> a == b
True
>>> a is b
True

a == b 比較好理解,a is b 是由於 Python 對整數作了優化,ab 都指向同一個預先分配的對象(其值爲 1)。
能夠理解爲 is 比較的是對象的內存地址。
內建函數 id() 返回對象的惟一標識,能夠理解爲內存地址。

>>> id(a), id(b)
(35169392, 35169392)

甚至能夠拿到一個對象的引用計數(reference count):

>>> import sys
>>> sys.getrefcount(a)
99
>>> sys.getrefcount(b)
99

引用計數爲 99 有點意外,實際上是由於不少裝載的內建模塊都用到了整數 1。
不妨看看其它整數如何:

>>> sys.getrefcount(0)
169
>>> sys.getrefcount(255)
4

對 Python 來講,變量只是名字,它的類型和值取決於它所綁定的對象。咱們能夠把 a b 綁定到其它對象:

>>> a, b = "hello", "hello"
>>> a is b
True

一樣,a is b 是由於 Python 對字符串作了優化。

值得一提的是,這種優化(也即引用計數)可能只針對 CPython,對於 Python 的其它實現可能就不是這樣了。你的程序不應依賴於這些特定於解釋器的實現。

整數和字符串有一個共同點,即它們都是不可變的(immutable),如今來看看可變對象,好比列表:

>>> c, d = [a, b], [a, b]
>>> c == d
True
>>> c is d
False

可見雖然 cd 具備相等的值,但對象是不一樣的兩個。

這些就是 Python 的數據模型(Data Model),雖然不是所有。

對象

Python 的每個對象(object)都有如下三個部分:

  • 身份(identity)

  • 類型(type)

  • 值(value)

身份:

  • 不可改變(unchangeable)(一旦對象建立了就不會改變)

  • 對應於內存地址

  • 經過操做符 is 進行比較: a is b

  • 函數 id() 返回對象惟一的整形標識(內存地址)

類型:

  • 不可改變(unchangeable)

  • 函數 type() 返回對象類型

值:

  • 可變的(mutable):字典,列表

  • 不可變的(immutable):數字,字符串,元組

最後,對象不會被顯式地銷燬(explicitly destroyed)。
對 CPython 來講,對象由引用計數管理,計數爲 0 時對象會自動銷燬。

練習

最後留一道練習。

給定:

>>> c = []
>>> d = []
>>> c is d
False

請問:

>>> e = f = []
>>> e is f
???

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

相關文章
相關標籤/搜索