python--有關函數的問題

      前段時間學習過python,但是隻是學了個皮毛。現在想用它來做數據分析,因此決定好好學習!本篇文章是在閱讀python官方文檔的過程中抽取出來的一些知識點。


python 函數調用過程中,變量的引用過程:


   The execution of a function introduces a new symbol table used for the local variables of the function. More precisely, all variable assignments in a function store the value in the local symbol table; whereas variable references first look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names. Thus, global variables cannot be directly assigned a value within a function (unless named in a global statement), although they may be referenced.


其翻譯如下:

        python的函數 調用會爲函數局部變量生成一個新的符號表。確切的說,所有函數中的變量賦值都是將值存儲在局部符號表。變量引用首先在局部符號表中查找,然後是包含函數的局部符號表,然後是全局符號表,最後是內置名字表。因此,全局變量不能在函數中直接賦值(除非用 global 語句命名),儘管他們可以被引用。


其中,“包含函數的局部符號表”,就是調用函數的那個塊的局部符號表


       被調用的函數(callee)引用的實參在它被調用時引入局部符號表,因此,實參總是 傳值調用 (這裏的  總是一個 對象引用 ,而不是該對象的值)。一個函數被另一個函數調用時,一個新的局部符號表在調用過程中被創建。


有關python 函數參數傳遞的一些問題:


例子:

i = 5

def f(arg=i):
    print(arg)

i = 6
f()
f ( ) 仍會打印5


對應list、dictionary這些可變的數據結構,又有所不同:

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))
輸出爲:

[1]
[1, 2]
[1, 2, 3]


       你可能會有疑問,明明每次調用函數f 的時候,都讓 L=[]了,爲什麼還是累計了。

這是因爲:在python的實現中,如果賦值方是可變類型(mutable type)的話,這個可變類型的變量是存在於 “包含函數f的局部符號表中的”,並不是在函數f的局部符號表中。

     [],列表類型,是可變的,因此“[]”對應一個在函數外部定義的列表。而L=[],實際上是將這個外部列表的指針賦給L,並不是真的把一個空列表賦給L。調用f(1)、f(2)、f(3)的過程中,這個外部定義的列表的內容就會增加。

       這種情況當且僅當函數參數列表裏賦給L的是一個可變參數類型(mutable type)的時候,纔會如此實現。

       python內部這樣的實現讓人費解,不知道它爲什麼要這樣做。



如果不想讓L累計元素,可以這樣寫:(None是空類型)

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

出爲:

[1]
[2]
[3]

      和上一個例子的解釋互補,因爲None是一個不可變的類型(immutable type),所以None定義在函數 f 的局部符號表中。每次調用函數的時候,都真的會使L=None。進而,每次調用都會使L=[]。



python裏邊,函數的調用可能需要傳遞參數,有多種方式:default arguments、keyword arguments ...


default arguments 就不說了


Keyword Arguments


調用函數的時候,傳參方式爲:"argName=xxx"的參數,就是Keyword Arguments。不是這樣傳參的參數就叫做Positional Arguments,顧名思義,它們是看位置來對號入座的。有幾點要注意:

        keyword arguments一定要放在positional arguments後面

        keyword arguments指定的argName一定是函數的prototype中有定義的

        keyword arguments之間的位置可以隨意

        一個argument不能被傳多於一個的值


此外,所有傳參的方法都要遵守的規則就是 “參數個數不能傳多”


在python函數的prototype中,參數名前加了" * " 則說明需要傳入一個元組(tuple),參數名前加了“ ** " 則說明需要傳入一個字典(dictionary)。規定函數的prototype中,元組類型參數 *name 要在 字典類型參數**name之前。比如這樣:

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    keys = sorted(keywords.keys())
    for kw in keys:
        print(kw, ":", keywords[kw])


Arbitrary Argument Lists


       python裏邊比較少用的是這種“任意參數列表”。使用一個元組 *argName 來接受任意多個參數,如果後面有一個沒有設置默認參數的參數,則須用‘Keyword-only'即Keyword argument的方式來表明, "argName=xxx"。


例子:

>>> def concat(*args, sep="/"):
...    return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'

上面這個例子給sep設置了默認參數"/",所以可以不用Keyword方式來表明。

如果沒設默認參數,在調用函數的時候,也沒有用Keyword方式來表明,就會出錯:




Unpacking Argument Lists

這個講的是當要給函數傳的參數蘊含在元組、列表、字典中的時候,如何把它們從這些數據結構裏面拆出來並傳給函數--用 * 來拆list、tuple,用 ** 來拆dictionary。具體的例子,請參考python官方文檔。


Lambda Expressions

這個講的是python的lambda表達式。lambda表達式一行寫就,主要有兩個用途:


1. 充當一個簡短的匿名函數     2. 在1的基礎上,作爲一個函數傳遞給別的函數


作用1例子:

>>> def make_incrementor(n):      #函數make_incrementor(n),返回一個lambda函數
...     return lambda x: x + n    #返回的lambda函數->參數列表: x;返回值: x+n
...
>>> f = make_incrementor(42)      #得到一個lambda函數->參數列表: x;返回值: x+42
>>> f(0)
42
>>> f(1)
43


作用2例子:

>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]



文檔字符串:

在函數體的前面用文檔字符串來描述函數是一個很好的習慣,具體請看官方文檔


函數批註:

這個是大概是用來描述函數的參數,還有傳參情況的。


編程風格:

python提供了PEP-8這個風格標準供程序員參考,具體請看官方文檔。個人感覺只要簡潔美觀就是好的風格。


References:

[1] https://docs.python.org/3/tutorial/controlflow.html

[2] http://www.pythondoc.com/pythontutorial3/controlflow.html#range

發佈了36 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章