Python學習筆記4(函數與模塊)


1.Python程序的結構

Python的程序由包(package)、模塊(module)和函數組成。

模塊是處理一類問題的集合,由函數和類組成。

包是由一系列模塊組成的集合。包是一個完成特定任務的工具箱。

2.函數

2.1函數的定義

def sayHello(): 
   print 'Hello World!'        # block belonging to the function 
sayHello()

2.2函數的參數
Python中任何東西都是對象,所以參數只支持引用傳遞的方式。Python通過名稱綁定的機制,把實際參數的值和形式參數的名稱綁在一起。即形參與實參指向內存中同一個儲存空間。

def arithmetic (x = 1, y =  1, operator = "+"):
    result = {
        "+" : x + y,
        "-" : x - y,
        "*" : x * y,
        "/" : x / y
    }
    return result.get(operator)

print (arithmetic(1,2))
print (arithmetic(y = 2, operator = "-")
print (arithmetic(y = 3, x = 1, operator = "*")       #  使用賦值表達式傳遞參數,可以顛倒參數列表的順序
# 列表作為參數
def arithmetic (args = [], operator = "+"):
    x = args[0]
    y = args[1]         
    result = {
        "+" : x + y,
        "-" : x - y,
        "*" : x * y,
        "/" : x / y
    }
    return result.get(operator)

print (arithmetic([1,2]))
#  使用默認參數出現預期外結果
def append(args = []):
    args.append(0)
    print (args)

append()                        # [0]
append([1])                   # [1,0]
append()                        # [0,0] , 使用的仍是第一次調用的args

# 避免重復問題
def append(args = []):
    if len(args) <= 0                 # 若args中沒有元素,將其列表置空
        args = []
    args.append(0)
    print(args)

append()                        # [0]
append([1])                   # [1,0]
append()                        # [0] 
#  傳遞可變參數
def func(*args):                  #  傳入的實參被“打包”到一個args元組中
    print args
func(1,2,3)
 1 # 傳遞可變參數——字典
 2 def search (*t, **d):             #  在形參前加"**",可以引用一個字典
 3     keys = d.keys()
 4     values = d.values()
 5     print (keys)
 6     print (values)
 7     for args in t:
 8         for key in keys:
 9             if args == key:
10                 print ("find:", d[key])
11 
12 search("one", "three", one = "1", two = "2", three = "3")

2.3函數的返回值
返回值用return語句,其后可為變量或表達式。Python中即使函數無返回值,依舊可以獲得返回值None。或者return不帶任何參數時,也返回None。

# return返回多個值,打包到元組內
def func(x,y,z):
    l = [x,y,z]
    l.reverse()
    numbers = tuple(l)                 # a,b,c = tuple(l)
    return numbers                      # return a,b,c

x,y,z = func(0,1,2)
print (x,y,z)

2.4函數的嵌套
Python不僅支持函數體內嵌套,還支持函數定義的嵌套。

#  在函數體內部定義函數
def func():
    x=1
    y=2
    m=3
    n=4
    def sun(a,b): 
        return a+b
    def sub(a,b):;
        return a-b
    return sum(x,y) * sub(m,n)

print(func())
#  嵌套函數,直接使用外層函數的變量
def func():
    x=1
    y=2
    m=3
    n=4
    def sun(): 
        return x+y
    def sub():;
        return m-n
    return sum() * sub()

print(func())

PS:盡量不要在函數內部定義函數,不便於程序維護
2.5遞歸函數

#  計算階乘
def refunc(n):
    i=1
    if n > 1:
        i = n
        n = n * refunc(n-1)
    print ("%d! =" %i,n)
    return n

refunc(5)

# output:
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
#  使用reduce計算階乘
From functools import reduce
print ("5! =", reduce(lambda x, y: x * y, range(1,6)))

2.6lambda函數
用於創建一個匿名函數,函數名未和標識符進行綁定。使用lambda函數可以返回一些簡單的運算結果。通常把lambda賦值給一個變量,該變量就可以作為函數使用。

func = lambda 變量1,變量2,... : 表達式

func()

 

# lambda
def func():
    x=1
    y=2
    m=3
    n=4
    sum = lambda x, y : x + y 
    print (sum)
    sub() = lambda m, n : m - n 
    print (sub)
    return sum(x,y) * sub(m,n)

print(func())
# lambda的函數用法
print ( (lambda x : -x) (-2))        #給x賦值-2

PS:lambda中只能使用表達式,不能使用判斷、循環等多重語句。
2.7Generator函數

生成器(Generator)的作用是一次產生一個數據項,並把數據項輸出。Generator函數可以用在for循環中遍歷。Generator函數每次返回一個數據項的特性,使得迭代器的性能更佳。

# 定義Generator函數
def func(n):
    for i in range(n):
        yield i
# 在for循環中輸出
for i in func(3):             
    print (i)                                           # 0 1 2
# 使用next()輸出
r = func(3)
print (r.next())                                    # 0
print (r.next())                                    # 1
print (r.next())                                    # 2
print (r.next())                                    # 已無數據生成,拋出異常StopIteration
# yield 與 return的區別
def func(n):
    for i in range(n):
        return i                                          # return 函數運行到此為止
def func2(n):
    for i in range(n):
        yield i                                            # 循環生成n個數,不會被終止

print (func(3))                                        # 0
f = func2(3)
print (f)                                                  #  返回函數func2的地址
print (f.next())                                        # 0
print (f.next())                                        # 1

Generator函數依次只趕回一個數據項,占用更少的內存。每次生成數據都要記錄當前的狀態,便於生成下一次數據。數據的訪問通過next()實現。當 訪問越界時,拋出異常StopIteration。

2.8global語句

如果你想要為一個定義在函數外的變量賦值,那么你就得告訴Python這個變量名不是局部的,而是 全局 的。我們使用global語句完成這一功能。沒有global語句,是不可能為定義在函數外的變量賦值的。

def func():
    global x
    print 'x is', x                                     # 50
    x = 2
    print 'Changed local x to', x                # 2
x = 50 
func()
 print 'Value of x is', x                             # 2

3.模塊

3.1使用sys模塊

import sys                                  # from sys import argv
print 'The command line arguments are:' 
for i in sys.argv:
    print i 
print '\n\nThe PYTHONPATH is', sys.path,  '\n' 

# output
The command line arguments are: 
using_sys.py 
we 
are 
arguments

The PYTHONPATH is ['/home/swaroop/byte/code',
 '/usr/lib/python23.zip', '/usr/lib/python2.3', 
'/usr/lib/python2.3/plat-linux2', '/usr/lib/python2.3/lib-tk', '/usr/lib/python2.3/libdynload', '/usr/lib/python2.3/site-
packages', '/usr/lib/python2.3/site-packages/gtk-2.0'] 

Python中的import語句可以置於程序的任何位置。
sys模塊包含了與Python解釋器和它的環境有關的函數。

sys.argv變量是一個字符串的列表 。特別地,sys.argv包含了命令行參數的列表,即使用命令行傳遞給你的程序的參數。

這里,當我們執行python using_sys.py we are arguments的時候,我們使用python命令 運行using_sys.py模塊,后面跟着的內容被作為參數傳遞給程序。Python為我們把它存儲 在sys.argv變量中。

腳本的名稱總是sys.argv列表的第一個參數。所以,在這里,'using_sys.py'是sys.argv[0]、'we'是sys.argv[1]、'are'是sys.argv[2]以 及'arguments'是sys.argv[3]。

sys.path包含輸入模塊的目錄名列表。我們可以觀察到sys.path的第一個字符串是空的——這個空的字符串表示當前目錄也是sys.path的一部分,這與PYTHONPATH環境變量是相同的。這意味着你可以直接輸入位於當前目錄的模塊。否則,你得把你的模塊放在sys.path所列的目錄之一。

3.2.pyc文件

使輸入模塊更加快的方法:

創建字節編譯的文件 ,這些文件以.pyc作為擴展名。字節編譯的文件與Python變換程序的中間狀態有關。當你在下次從別的程序輸入這個模塊的時候,.pyc文件是十分有用的——它會快得多,因為一部分輸入模塊所需的處理已經完成了。另外,這些 字節編譯的文件也是與平台無關的。

3.3模塊的__name__

當一個模塊被第一次輸入的時候,這個模塊的主塊將被運行。假如我們只想在程序本身被使用的時候運行主塊,而在它被別的模塊輸入的時候不運行主塊,這可以通過模塊的 __name__屬性完成。

_name_用於判斷當前模塊是否是程序的入口,如果當前程序正在被使用,_name_的值為"_main_"。

if __name__ == '__main__':
    print 'This program is being run by itself'
 else:
    print 'I am being imported from another module'
# output
This program is being run by itself 
$ python 
>>> import using_name
 I am being imported from another module 

每個Python模塊都有它的__name__,如果它是'__main__',這說明這個模塊被用戶單獨運行,我們 可以進行相應的恰當操作。

3.4模塊的創建

模塊把一組相關的函數或代碼組織到一個文件中。一個文件即是一個模塊。模塊由代碼、函數或類組成。創建一個名為myModule.py的文件,即定義了一個名為myModule的模塊。

#  自定義模塊
def func():
    print ("MyModule.func()" )

class MyClass:
    def myFunc(self):
        print ("MyModule.MyClass.myFunc()")

#  在myModule.py所在目錄下創建一個call_myModule.py的文件。在該文件中調用myModule模塊的函數和類

import myModule
myModule.func()
myClass = myModule.MyClass()
myClass.myFunc()

 另一個例子:

# Filename: mymodule.py 
def sayhi():
    print 'Hi, this is mymodule speaking.' 

version = '0.1' 

#  調用mymodule模板
import mymodule                                             #  from mymodule import sayhi, version 
mymodule.sayhi()
print 'Version', mymodule.version 

# output
$ python mymodule_demo.py 
Hi, this is mymodule speaking. 
Version 0.1

3.5模塊的內置函數

Python提供了一個內聯模板buildin。內聯模板定義了一些開發中經常使用的函數,利用這些函數可以實現數據類型的轉換、數據的計算、序列的處理等功能。

  • filter()

對某個序列做過濾處理,判斷自定義函數的參數返回的結果是否為真來過濾,並一次性返回處理結果。

# 聲明
class filter(object)
    filter(function or None, iterable)  --> filter object
# 功能
def func(x):
    if x > 0:
        return x

#  使用range()生成待處理的列表,然后把該列表的值依次傳入func(),func()返回結果給filter(),最后將結果yield成一個iterable對象返回,依次遍歷
#  output <filter object at 0x1022b2750>
#  直接打印出filter對象。最后一行將其轉換為列表
print ( filter (func,range(-9,10)) )                   # 調用filter函數,返回filter對象
print ( list(filter(func,range(-9,10)))               # 將filter對象轉換為列表

filter()中的過濾函數func()的參數不能為空。否則,沒有可以存儲sequence元素的變量,func()也不能處理過濾

  • reduce()

實現連續處理的功能,存在於functools模塊中。

#  聲明
reduce(func,sequence[, initial])  -> value

# func()是自定義函數,在其中實現對參數sequence即待處理序列的連續操作
# 參數initial可以省略,若不為空,則initial的值首先傳入func()進行計算。若sequence為空,則對initial的值進行處理
# reduce()返回值為func()計算后的結果
#  功能
def sun(x,y):
    return x+y
from functools import reduce
print  (reduce(sum,range(0,10)))               # 0加到9,結果45
print  (reduce(sum,range(0,10),10))          # 10加0加到9,結果55
print  (reduce(sum,range(0,0),10))            # 結果10

如果用reduce()進行累計計算,必須在sum中定義兩個參數,分別對應加法運算符兩側的操作數。

  • map()

可對多個序列的每個元素都執行相同的操作,並返回一個map對象。

#  聲明
class map(object)
    map(func, *iterables)  --> map object

# func自定義函數,實現對每個元素的操作
# iterables是待處理序列,其個數可以是多個
# map返回值為處理后的列表

若map中提供多個序列,則每個序列中元素一一對應計算。若長度不等,短的后補None
3.6dir()函數

你可以使用內建的dir函數來列出模塊定義的標識符。標識符有函數、類和變量。

當你為dir()提供一個模塊名的時候,它返回模塊定義的名稱列表。如果不提供參數,它返回當前模塊中定義的名稱列表。

import sys 
 dir(sys)             # 輸出sys模塊上的屬性列表。 ['__displayhook__', '__doc__', '__excepthook__', '__name__',
 '__stderr__', '__stdin__', '__stdout__', '_getframe', 'api_version',
 'argv', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 
'copyright', 'displayhook', 'exc_clear', 'exc_info', 'exc_type', 'excepthook', 
'exec_prefix', 'executable', 'exit', 'getcheckinterval', 'getdefaultencoding',
 'getdlopenflags', 'getfilesystemencoding', 'getrecursionlimit', 'getrefcount',
 'hexversion', 'maxint', 'maxunicode', 'meta_path','modules', 'path', 
'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 
'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'settrace', 
'stderr', 'stdin', 'stdout', 'version', 'version_info', 'warnoptions'] 

 dir()                 # 返回當前模塊的屬性列表,輸入的模塊同樣是列表的一部分。 ['__builtins__', '__doc__', '__name__', 'sys'] 
a = 5            # create a new variable 'a' 
 dir()
 ['__builtins__', '__doc__', '__name__', 'a', 'sys'] 
del a           # delete/remove a name 
dir()
 ['__builtins__', '__doc__', '__name__', 'sys']

為了觀察dir的作用,定義一個新的變量a並且給它賦一個值,檢驗dir,在列表中增加了以上相同的值。

我們使用del語句刪除當前模塊中的變量/屬性,這個變化再一次反映在dir的輸出中。

PS:del語句在運行后被用來 刪除一個變量/名稱。在這個例子中,del a,你將無 法再使用變量a——它就好像從來沒有存在過一樣。

3.7自定義包

包就是一個至少包含_init_.py文件的文件夾。包為了實現程序的重用,把實現一個常用功能的代碼組合到一個包中,調用包提供的服務從而實現重用。

# 包的_init_.py程序
if _name_ == '_main_':
    print ('作為主程序運行')
else:
    print ('pack初始化')
# 包的myModule模塊
def func():
    print ("pack.myModule.func()")

if _name_ == '_main_':
    print ('myModule作為主程序運行')
else:
    print ('pack被另一模塊調用)
#  main模板調用pack中的函數
from pack import myModule                              

myModule.func()

# output:
pack初始化
myModule被另一個模板調用

pack.myModule.func()

_init_.py也可用於提供當前包的模塊列表。eg.在pack包的_init_.py文件前添加一行代碼

_all_ = ["myModule"]

_all_用於記錄當前pack包所含的模板。其中方括號中的內容是模板名的列表,如果模塊數量超過2個,使用逗號分開。

這樣就可以在main模板中一次導入pack包中的所有模塊。

from pack import *   

myModule.func()

# 首先執行pack包的_init_.py文件,然后在屬性中查找pack包含有的模塊。如果pack包的_init_.py文件不適用_all_屬性記錄模塊名,main模塊調用時將不能識別myModule模塊。Python將提示如下錯誤:
NameError:name 'myModule' is not defend

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM