Python之路,Day04-函數與模塊


 

本節內容

1、函數的定義

2、如何使用函數

3、函數的返回值

4、使用注釋改進文檔

5、傳遞任意數量的實參

6、函數與模塊

 

 

 

1、函數的定義

函數的一般定義(中學/數學):函數的近代定義是給定一個數集A,假設其中的元素為x,對A中的元素x施加對應法則f,記作f(x),得到另一數集B,假設B中的元素為y,則y與x之間的等量關系可以用y=f(x)表示,函數概念含有三個要素:定義域A、值域C和對應法則f。

 

編程語言中函數的定義(計算機):函數是邏輯結構化和過程化的一種編程方法。

函數的定義方法(案例):

>>> def fib(n):    # write Fibonacci series up to n
...     """Print a Fibonacci series up to n."""
...     a, b = 0, 1
...     while a < n:
...         print(a, end=' ')
...         a, b = b, a+b
...     print()

"""
def:定義函數的關鍵字
flb:函數名
(n):定義函數的參數
"""""":文檔描述
代碼塊:
     a, b = 0, 1
     while a < n:
        print(a, end=' ')
         a, b = b, a+b
     print()
"""

 具體學習:

下面打印一個問候的簡單函數:

1 def greet_user():    #定義一個函數,關鍵詞為"def",函數名為"greet_user",最后以“:”結尾
2     """顯示簡單的問候語"""    #描述函數的具體功能
3     print("Hello!")         #函數體的代碼塊,用於實現函數功能
4 
5 greet_user()         #調用函數

 注意:(1)在第一行定義函數中,不需要任何信息就能完成工作,因此括號是空的(即便如此,括號必不可少!)

   (2)要調用函數,可以依次指定函數名以及括號括起的必要信息。在第五行代碼中,因為此函數greet_uesr()括號中不需要任何信息,只需要輸入greet_uesr()即可。和預期效果一樣,打印Hello!:

練習:大腦P149

1 def search4vowels():
2     vowels = set('aeiou')
3     word = input("Provide a word to search for vowels:")
4     found = vowels.intersection(set(word))
5     for vowel in found:
6         print(vowel)
7 
8 search4vowels()
9 search4vowels() #可以重復多次調用
search_vowels

2、如何使用函數(傳遞實參)

函數的使用方法(先看案例)

>>> def fib2(n):  # return Fibonacci series up to n
...     """Return a list containing the Fibonacci series up to n."""
...     result = []
...     a, b = 0, 1
...     while a < n:
...         result.append(a)    # see below
...         a, b = b, a+b
...     return result
...
>>> f100 = fib2(100)    # call it
>>> f100                # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

 2.1 向函數傳遞信息

針對greet_user()只要稍作修改,就可不僅實現Hello,還可以將用戶名字作為抬頭:

1 def greet_user(username):    
2     """顯示簡單的問候語"""    
3     print("hello,"+username.title()+"!")         
4 
5 greet_user("zhichao")  

代碼greet_user("zhichao")調用函數greet_user()時,向它傳遞執行print()語句所需要的信息username。

2.2 實參和形參

greet_user(username) #username 為形參;函數完成其工作時所需要的信息。

greet_user("zhichao") #"zhichao"為實參;實參是調用函數時傳遞給函數的信息。

形參:形式參數,不是實際存在的,是虛擬變量。在定義函數和函數體的時候使用形參,目的是在函數調用時接收實參

實參:實際參數,調用函數時傳遞給函數的參數,可以是常量、變量,表達式,函數,傳給形參

區別:形參是虛擬的,不占用空間,形參變量只有在被調用時才分配內存單元,實參是一個變量,占用內存空間,數據傳遞單向,實參傳給形參,不能倒過來。

傳遞實參:

1、位置實參(基於實參的順序):

1 #zhichao
2 
3 def describe_pet(animal_type,pet_name):
4     """顯示寵物信息"""
5     print("\nI have a" + animal_type + ".")
6     print("My" + animal_type + "'s name is "+pet_name.title() + ".")
7 
8 describe_pet('hamster','harry')
9 describe_pet('cat','python')  #函數調用多次是一種效率極高的工作方式

位置實參的順序很重要,請確認函數調用中實參的順序與函數定義形參的順序一致

2 關鍵字參數

1 def describe_pet(pet_name,animal_type="dog",):
2     """顯示寵物信息"""
3     print("\nI have a " + animal_type + ".")
4     print("My" + animal_type + "'s name is "+pet_name.title() + ".")
5 
6 describe_pet(pet_name='harry',animal_type='hamster')  #關鍵字實參
7 describe_pet(pet_name='python',animal_type='cat')  #關鍵字實參

思考1:關鍵字參數是否需要與形參順序一致?

思考2:關鍵字參數和位置參數能否同時存在?

例:

#eg1
def func_test(x,y):
    print(x)
    print(y)
    
func_test(x=1,2)      #

#eg2
def func_test(x,y):
    print(x)
    print(y)
    
func_test(1,y=2)      #

#eg3
def func_test(x,y,z):
    print(x)
    print(y)
    
func_test(1,y=2,3)      #

#結論?

****關鍵參數是不可以寫在位置參數前面的

2.3 默認值

編寫函數時,可以給形參指定默認值。

1 def describe_pet(pet_name,animal_type="dog",):
2     """顯示寵物信息"""
3     print("\nI have a " + animal_type + ".")
4     print("My" + animal_type + "'s name is "+pet_name.title() + ".")
5 
6 describe_pet('harry','hamster')
7 describe_pet('python','cat')

 2.4 像函數中傳遞列表:

eg:

 1 #Zhichao
 2 
 3 def greet_users(names):
 4     """向列表中的每位用戶都發出簡單的問候"""
 5     for name in names:
 6         msg = "Hello, "+name.title() +"!"
 7         print(msg)
 8 
 9 usernames = ['hannah','ty','margot']
10 greet_users(usernames)
greet_users

 

3、函數的返回值

 函數返回的值被稱為函數的返回值;

在函數中,可用return語句將值返回到調用函數的代碼行;

返回值能將你程序的大部分繁重工作移到函數中去完成,從而簡化主程序。

3.1 返回簡單值

eg(formatted_name1):

1 #zhichao
2 
3 def get_formatted_name(first_name,last_name):
4     """返回整潔的姓名"""
5     full_name = first_name + ' '+ last_name
6     return full_name.title()
7 
8 musician = get_formatted_name('jimi','hendrix') #調用返回值的函數時,需要提供一個變量,用於存儲返回的值
9 print(musician)

 

3.2 讓實參變成可選的

有時候,需要讓實參變成可選的,這樣使用函數的人就只需要在必要時候才提供額外信息。

我們對:formatted_name1 進行擴展(函數的可擴展性

eg(formatted_name2):

1 def get_formatted_name(first_name,middle_name,last_name):
2     """返回整潔的姓名"""
3     full_name = first_name + ' '+middle_name+' '+ last_name
4     return full_name.title()
5 
6 musician = get_formatted_name('jimi','lee','hendrix') #有些人有中間名
7 print(musician)

有些人不一定有中間名,那么對函數進行優化:

eg(formatted_name2):

#zhichao

def get_formatted_name(first_name,last_name,middle_name=''):  #復習關鍵字實參放后面
    """返回整潔的姓名"""
    if middle_name:
        full_name = first_name + ' '+middle_name+' '+ last_name
    else:
        full_name = first_name + ' ' + last_name
    return full_name.title()

musician = get_formatted_name('jimi','lee','hendrix')
musician1 = get_formatted_name('jimi','hendrix')
print(musician)
print(musician1)

 

3.3 返回多個值

函數可以返回任意類型的值,包括列表、字典和集合等較為復雜的數據結構。

大腦P159:

返回一個值:

return_bool

返回一個集合:

1 # Zhichao
2 
3 def search4vowels(word):
4     """Return a boolean based on any vowels found"""
5     vowels = set('aeiou')
6     found = vowels.intersection(set(word))
7     return found
8 word = search4vowels('hello Zhichao')
9 print(word)
return_set

返回數據:

1 #Zhichao
2 
3 def search4vowels(word):
4     """Return a boolean based on any vowels found"""
5     vowels = set('aeiou')
6     return vowels.intersection(set(word))
7 word = search4vowels('hello Zhichao')
8 print(word)
return_value

返回字典:

1 #Zhichao
2 
3 def build_person(first_name,last_name):
4     """返回一個字典,其中包含有關一個人的信息"""
5     person = {'first':first_name,'last':last_name}
6     return person
7 
8 musician = build_person('jimi','hendrix')
9 print(musician)
return_dict

 

4.使用注釋改進文檔

復習python的四種數據類型。

當我們調用函數時,才知道我們需要輸入的參數和返回值的類型“type”

對此,我們的一種解決辦法是把這個信息增加到docstring

python3 注解的記法

1.函數注解是可選的。

2.函數注解可以提供信息。

 

eg:

1 #zhichao
2 
3 def search4vowels(word:str) ->set:
4     """Return a boolean based on any vowels found"""
5     vowels = set('aeiou')
6     return vowels.intersection(set(word))
7 
8 help(search4vowels)

 

 5.傳遞任意數量的實參

1. *args,傳入多個參數,轉化成元組。

假如一個函數定義一個披薩的配料,但並不知道有多少配料需要加入,在參數不確定的情況下,我們引入任意數量的實參。

eg:

#Zhichao

def make_pizza(*toppings):  
    """打印顧客點的所有配料"""
    print(toopings)

make_pizza("peperoni")
make_pizza("mushroom","green peppers","extra cheese")

注意:*toppings的值是一個封裝好的空元組,並將所有接收到的值都封裝在這個元組里。

 

2.**kwargs,把關鍵字參數,轉化成字典。

eg:

1 # -*- coding:utf-8 -*-
2 # Author:Zhichao
3 
4 def infos(**kwargs):
5     """打印個人信息"""
6     print(kwargs)
7 
8 infos(name="Zhichao",age="24",job="IT")

 

 

 

 設計一個對顧客點披薩進行描述:

 1 #Zhichao
 2 
 3 def make_pizza(*toopings):
 4     """概述要制作的披薩"""
 5     print("\nMaking a pizza with the following toppings")
 6     for topping in toopings:
 7         print("--"+topping)
 8 
 9 make_pizza("peperoni")
10 make_pizza("mushroom","green peppers","extra cheese")

 

結合位置實參和任意數量實參:

#Zhichao

def make_pizza(size,*toopings):  #回顧位置實參應放在前面
    """概述要制作的披薩"""
    print("\nMaking a "+str(size)+"-inch pizza with the following toppings")
    for topping in toopings:
        print("--"+topping)

make_pizza(14,"peperoni")
make_pizza(12,"mushroom","green peppers","extra cheese")

 

6.函數與模塊

函數的優點之一是將代碼與主程序分離;

我們可以更進一步,將函數存儲在被稱為“模塊”的獨立文件中,再將模塊導入主程序;

import語句允許我們在當前運行的程序文件中使用模塊中的代碼。

優勢:

1.通過將函數存儲在獨立的文件中,可隱藏程序代碼的細節,將重點放在程序的高層邏輯上;

2.可以讓不同的程序中重用函數;

3.可與其他程序員共享這些文件而不是整個程序;

4.知道如何導入函數能讓你使用其他程序員編寫的函數庫。

 

6.1 導入整個模塊

模塊是擴展名為.py的文件(如一些內置的模塊:C:\ProgramData\Anaconda3\Lib)

下面我們來創建一個模包含函數make_pizza()的模塊。

pizza.py

1 #Zhichao
2 
3 def make_pizza(size,*toopings):
4     """概述要制作的披薩"""
5     print("\nMaking a "+str(size)+"-inch pizza with the following toppings")
6     for topping in toopings:
7         print("--"+topping)

 

接下來,我們在pizza.py所在目錄下創建一個另外的名為making_pizzas.py文件,這個文件導入剛創建的模塊,在調用make_pizza()兩次:

making_pizzas.py

1 import pizza #調用模塊
2 
3 pizza.make_pizza(16,'pepperoni')  #調用模塊的函數
4 pizza.make_pizza(12,"mushroom","green peppers","extra cheese")

 

 

 

 6.2 導入特定的函數

可以導入模塊中的特定函數,方法如下:

1 from module_name import function_name

通過用逗號分開函數名可以同時導入多個函數:

1 from module_name import function_0,function_1,function_2

對於前面的pizza案例,我們可以導入模塊中的特定函數:

1 from pizza import make_pizza
2 make_pizza(16,'pepperoni')  #調用模塊的函數
3 make_pizza(12,"mushroom","green peppers","extra cheese")

若使用此種方法,調用函數時不需要用句點。

 

6.3 使用as 給函數指定別名

思考:如果你導入的函數名與程序中現有的名稱沖突怎么辦?或者你調用的函數名稱太長怎么辦?

 

我們可以指定函數的另一個名稱,類似於外號。

下面我們根據make_pizza指定名稱

1 from pizza import make_pizza as mp
2 mp(16,'pepperoni')  #調用模塊的函數
3 mp(12,"mushroom","green peppers","extra cheese")

通用語法格式:

1 from moudle_name import function_name as fn

 

6.4 使用as給模塊指定別名

eg:

1 import pizza as p
2 
3 p.make_pizza(16,'pepperoni')  
4 p.make_pizza(12,"mushroom","green peppers","extra cheese")

通用語法格式:

import moudle_name as mn

 

6.5 導入模塊中的所有函數

使用星號(*)運算符可以讓Python導入模塊中的所有函數:

1 #Zhichao
2 from pizza import*
3 
4 make_pizza(16,'pepperoni')
5 make_pizza(12,"mushroom","green peppers","extra cheese")

通用語法格式:

from moudle_name import *

 

Head First Python

大腦P162

使用注解改進文檔:

 

關於注解更多詳細內容參見PEP3107

(https://www.python.org/dev/peps/pep-3107)

大腦 P164

函數:我們已經知道些什么

* 函數是命名的代碼塊。

* def關鍵字用來命名函數,函數代碼在def關鍵字下(相對於def關鍵字)縮進

* Python的三重引號字符串可以用來函數增加多行注釋。如果采用這種方式,他們稱之為docstring

* 函數可以接受任意多個命名參數

* return語句允許函數返回任意值(也可以不反回任何值)

*函數注解可以用來描述函數參數的類型

 

建立一個通用的函數:

 1 #Zhichao
 2 
 3 def search4vowels(phrase: str) -> set:
 4     """return any vowels found in a supplied phrase"""
 5     vowels = set('aeiou')
 6     return vowels.intersection(set(phrase))
 7 
 8 def search4letters(phrase:str,letters:str)->set:
 9     """return a set of the 'letters' found in 'phrase'. """
10     return set(letters).intersection(set(phrase))
11 
12 help(search4letters)
13 print(search4letters('hitch-hiker','aeiou'))
14 print(search4letters('galaxy','xyz'))

 

 

函數補充:

函數可以調用函數嗎?

函數引用

eg:

 1 # Author:Zhixhao
 2 
 3 def search4letters(phrase:str,letters:str)->set:
 4     """return a set of the 'letters' found in 'phrase'. """
 5     logger("search4letters")
 6     return set(letters).intersection(set(phrase))
 7 
 8 def logger(source):
 9     print("from %s"%source)
10 help(search4letters)
11 
12 print(search4letters('hitch-hiker','aeiou'))
13 print(search4letters('galaxy','xyz'))

 

局部變量與全局變量以及其作用域:

 1 #Zhichao
 2 
 3 school = "中山大學"
 4 
 5 def change_name(name:str):
 6     """修改名字"""
 7     # global school
 8     school = "中山大學南方學院"
 9     print("before change",name,school)
10     name = name.title()         #局部變量,可以理解這個函數就是這個變量的作用域
11     # age = 18
12     print("after change",name)
13 
14 # print("age",age)
15 name = "zhichao"
16 change_name(name)
17 print(name,school)

 

不建議使用  global 在函數內部修改全局變量,容易導致邏輯混亂不清

再來看一個例子:

1 # Author:Zhichao
2 
3 names = ["Marry","Jack","Lin"]
4 def change_name():
5     names.append("Zhichao")
6     print("inside func",names)
7 
8 change_name()
9 print(names)

請閱讀大腦P185-p187

並嘗試理解:

 

 

總結:

可變:列表、字典和集合

不可變:字符串、整數和元組

(回顧字典的key命名)

 

遞歸:

1 def calc(n):
2     print(n)
3     if int(n/2) == 0:
4         return n
5     return calc(int(n/2))
6 
7 calc(10)

 

遞歸特性:

1.必須有一個明確的結束條件

2.每次進入更深一層遞歸時,問題規模相比上次遞歸應有所減少。

3.遞歸效率不高,遞歸次數過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會多加一層棧幀,每當函數返回,棧就會減少一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出。)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

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



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