Python3 函數


1.定義函數

  函數代碼塊以 def 關鍵詞開頭,后接函數標識符名稱和圓括號 ()。

  任何傳入參數和自變量必須放在圓括號中間,圓括號之間可以用於定義參數。

  函數的第一行語句可以選擇性地使用文檔字符串—用於存放函數說明。

  函數內容以冒號起始,並且縮進。

  return [表達式] 結束函數,選擇性地返回一個值給調用方。不帶表達式的return相當於返回 None。

  可以返回多個值,其實就是一個tuple。

def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

  空函數:如果想定義一個什么事也不做的空函數,可以用來占位,可以用pass語句:

def nop():
    pass

2.參數傳遞 

  可更改(mutable)與不可更改(immutable)對象
  在 python 中,strings, tuples, 和 numbers 是不可更改的對象,而 list,dict 等則是可以修改的對象。

  不可變類型:變量賦值 a=5 后再賦值 a=10,這里實際是新生成一個 int 值對象 10,再讓 a 指向它,而 5 被丟棄,不是改變a的值,相當於新生成了a。

  可變類型:變量賦值 la=[1,2,3,4] 后再賦值 la[2]=5 則是將 list la 的第三個元素值更改,本身la沒有動,只是其內部的一部分值被修改了。

  python 函數的參數傳遞:

  不可變類型:類似 c++ 的值傳遞,如 整數、字符串、元組。如fun(a),傳遞的只是a的值,沒有影響a對象本身。比如在 fun(a)內部修改 a 的值,只是修改另一個復制的對象,不會影響 a 本身。

  可變類型:類似 c++ 的引用傳遞,如 列表,字典。如 fun(la),則是將 la 真正的傳過去,修改后fun外部的la也會受影響

  python 中一切都是對象,嚴格意義我們不能說值傳遞還是引用傳遞,我們應該說傳不可變對象和傳可變對象。

3.參數

  調用函數時可使用的正式參數類型:必需參數,關鍵字參數,默認參數,不定長參數等,參數類型也可以組合。

  a. 必須參數,也叫位置參數

  必需參數須以正確的順序傳入函數。調用時的數量必須和聲明時的一樣。

  b.關鍵字參數

  關鍵字參數和函數調用關系緊密,函數調用使用關鍵字參數來確定傳入的參數值。

  使用關鍵字參數允許函數調用時參數的順序與聲明時不一致,因為 Python 解釋器能夠用參數名匹配參數值。

def printinfo( name, age ):
   "打印任何傳入的字符串"
   print ("名字: ", name)
   print ("年齡: ", age)
   return
 
#調用printinfo函數
printinfo( age=50, name="runoob" )

  c.默認參數

  調用函數時,如果沒有傳遞參數,則會使用默認參數。默認參數要放在最后。默認參數必須指向不可變對象。

def printinfo( name, age = 35 ):
   "打印任何傳入的字符串"
   print ("名字: ", name)
   print ("年齡: ", age)
   return
 
#調用printinfo函數
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )

  d.不定長參數,可變參數,收集參數

  需要一個函數能處理比當初聲明時更多的參數。

  加了星號 * 的參數會以元組(tuple)的形式導入,存放所有未命名的變量參數。

  果在函數調用時沒有指定參數,它就是一個空元組。我們也可以不向函數傳遞未命名的變量。

  如果* 后,還有參數,參數必須用關鍵字傳入。

  加了兩個星號 ** 的參數會以字典的形式導入。允許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝為一個dict。

def printinfo( arg1, *vartuple ):
   "打印任何傳入的參數"
   print ("輸出: ")
   print (arg1)
   for var in vartuple:
      print (var)
   return
 
# 調用printinfo 函數
printinfo( 10 )
printinfo( 70, 60, 50 )

>>> nums = [1, 2, 3] >>> calc(*nums) 14

def fun(**kwargs):
for x, y in kwargs.items():
print(x,y)

fun(city = "asdasd",beijing = "sadasdw")

 

4.匿名函數

  python 使用 lambda 來創建匿名函數。

  所謂匿名,意即不再使用 def 語句這樣標准的形式定義一個函數。

  lambda 只是一個表達式,函數體比 def 簡單很多。
  lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
  lambda 函數擁有自己的命名空間,且不能訪問自己參數列表之外或全局命名空間里的參數。
  雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,后者的目的是調用小函數時不占用棧內存從而增加運行效率。

sum = lambda arg1, arg2: arg1 + arg2

  請參考:https://www.cnblogs.com/kaishirenshi/p/8611358.html

  two_sum = (lambda x, y: x + y)(34)

  匿名函數也是一個函數對象,也可以把匿名函數賦值給一個變量,再利用變量來調用該函數:

>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25

   也可以把匿名函數作為返回值返回,

def build(x, y):
    return lambda: x * x + y * y

 

5.高階函數

  一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數。

def add(x, y, f):
    return f(x) + f(y)

def zheng(n):
    if n > 0:
        return n
    else:
        return -n

x = -5
y = 10
f = zheng  #變量指向函數,函數名就是變量
print(add(x, y, f))

 

5.1 map()reduce()函數

map()函數接收兩個參數,一個是函數,一個是Iterablemap將傳入的函數依次作用到序列的每個元素,並把結果作為新的Iterator返回。

>>> def f(x):
...     return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

再看reduce的用法。reduce把一個函數作用在一個序列[x1, x2, x3, ...]上,這個函數必須接收兩個參數,reduce把結果繼續和序列的下一個元素做累積計算:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
>>> from functools import reduce >>> def add(x, y): ... return x + y ... >>> reduce(add, [1, 3, 5, 7, 9]) 25

  作業:

  利用mapreduce編寫一個str2float函數,把字符串'123.456'轉換成浮點數123.456

  摘選了一個答案:

def str2float(str):

    d = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,
         '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

    def s2n(s):
        return d[s]

    def fn(a, b):
        return reduce(lambda x, y: x * 10 + y, map(s2n, a)) + reduce(lambda x, y: x * 10 + y, map(s2n, b)) * (10 ** -len(b))

    theS = str.split('.')

    return fn(theS[0], theS[1])

 

 5.2 filter

Python內建的filter()函數用於過濾序列。

map()類似,filter()也接收一個函數和一個序列。和map()不同的是,filter()把傳入的函數依次作用於每個元素,然后根據返回值是True還是False決定保留還是丟棄該元素。

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 結果: [1, 5, 9, 15]

用filter求素數

def _odd_iter():  #構造一個從3開始的奇數序列,這是一個生成器,並且是一個無限序列。
    n = 1
    while True:
        n = n + 2
        yield n
def _not_divisible(n): #定義一個篩選函數 return lambda x: x % n > 0
def primes(): #定義一個生成器,不斷返回下一個素數 yield 2 it = _odd_iter() # 初始序列 while True: n = next(it) # 返回序列的第一個數 #每次循環,it會改變,n取新序列的第一個數。 yield n it = filter(_not_divisible(n), it) # 構造新序列 #循環一次,就將n及n倍數的值去掉返回新的Iterator
#將lambda函數寫在filter中,篩選有問題,沒搞懂是怎么回事,應該是閉包的問題。
# 打印1000以內的素數: for n in primes(): if n < 1000: print(n) else: break

 

5.3 stored

sorted()函數也是一個高階函數,可以接收一個key函數來實現自定義的排序,例如按絕對值大小排序:

 先將序列輸入key函數,獲取新序列,然后再排序。

>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]

>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)  #反向排序
['Zoo', 'Credit', 'bob', 'about']

key指定的函數將作用於list的每一個元素上,並根據key函數返回的結果進行排序。

序列中的元素是一個個傳入key函數,再返回一個新序列。

 

max,min

salaries={
    'siry':3000,
    'tom':7000,
    'lili':10000,
    'jack':2000
}
# 需求1:找出薪資最高的那個人=》lili
# res=max([3,200,11,300,399])
# print(res)

# res=max(salaries)
# print(res)


salaries={
    'siry':3000,
    'tom':7000,
    'lili':10000,
    'jack':2000
}
# 迭代出的內容    比較的值
# 'siry'         3000
# 'tom'          7000
# 'lili'         10000
# 'jack'         2000

# def func(k):
#     return salaries[k]

# ========================max的應用
# res=max(salaries,key=func) # 返回值=func('siry')
# print(res)

# res=max(salaries,key=lambda k:salaries[k])
# print(res)

# ========================min的應用
# res=min(salaries,key=lambda k:salaries[k])
# print(res)

 

5.4 函數作為返回值

  閉包

  https://blog.csdn.net/qq_37616069/article/details/79646905

  在函數內部再定義一個函數,並且這個函數用到了外邊函數的變量,那么將這個函數以及用到的一些變量稱之為閉包

  函數lazy_sum中又定義了函數sum,並且,內部函數sum可以引用外部函數lazy_sum的參數和局部變量,當lazy_sum返回函數sum時,相關參數和變量都保存在返回的函數中,這種稱為“閉包

  #形成閉包的條件
    #1、必須要有一個內嵌函數
    #2、內嵌函數中要對外層函數變量的引用
    #3、外部函數必須返回內嵌函數

 返回閉包時牢記一點:返回函數不要引用任何循環變量,或者后續會發生變化的變量。

如果一定要引用循環變量怎么辦?方法是再創建一個函數,用該函數的參數綁定循環變量當前的值,無論該循環變量后續如何更改,已綁定到函數參數的值不變:

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被執行,因此i的當前值被傳入f()
    return fs

 

 5.5 裝飾器

  可以在不修改原有代碼的情況下,為被裝飾的對象增加新的功能或者附加限制條件或者幫助輸出,這種在代碼運行期間動態增加功能的方式,稱之為“裝飾器”(Decorator)

  要先理解閉包。

    def outer(func):  # 裝飾函數
        def inner():
            print("認證成功!")
            result = func()
            print("日志添加成功")
            return result
        return inner

    @outer
    def f1():  # 被裝飾函數
        print("業務部門1數據接口......")

  a.程序開始運行,從上到下開始解釋。讀到def outer(func)時,發現這是一個函數的定義,將其函數體放入內存中,然后跳過。

  b.跳到@outer時,程序被@這個python語法糖吸引住,知道這是個裝飾器,按規矩要立即執行,於是程序開始運行@后面那個名字outer所定義的函數。

  c.程序返回到outer函數,開始執行裝飾器的語法規則。規則是:被裝飾函數的名字會被當作函數形參傳遞給裝飾函數。裝飾函數執行它自己內部的代碼后,會將它的返回值賦值給被裝飾函數。原來f1函數被當作參數傳遞給了func,而f1這個函數名之后會指向inner函數。 注意:@outer和outer()是有區別的。沒有括號時,outer函數會被立即執行。這個與傳統的用括號才能調用函數不同。

  d.程序開始執行outer函數內部的內容,一開始它又碰到了一個函數inner,inner函數定義塊被程序觀察到后不會立刻執行,而是讀入內存中(這是默認規則)。

  e.再往下,碰到return inner,返回值是個函數名,並且這個函數名會被賦值給f1這個被裝飾函數,也就是f1 = inner。此時,f1函數被新的函數inner覆蓋了(實際上是f1這個函數名更改成指向inner這個函數名指向的函數體內存地址,f1不再指向它原來的函數體的內存地址),再往后調用f1的時候將執行inner函數內的代碼,而不是先前的函數體。那么先前的函數體去哪了?還記得我們將f1當做參數傳遞給func這個形參么?func這個變量保存了老的函數在內存中的地址,通過它就可以執行老的函數體,你能在inner函數里看到result = func()這句代碼,它就是這么干的!

  f.接下來,還沒有結束。當業務部門,依然通過f1()的方式調用f1函數時,執行的就不再是舊的f1函數的代碼,而是inner函數的代碼。在本例中,它首先會打印個“認證成功”的提示,很顯然你可以換成任意的代碼,這只是個示例;然后,它會執行func函數並將返回值賦值給變量result,這個func函數就是舊的f1函數;接着,它又打印了“日志添加成功”的提示,這也只是個示例,可以換成任何你想要的;最后返回result這個變量。我們在業務部門的代碼上可以用r = f1()的方式接收result的值。

  g.以上流程走完后,你應該看出來了,在沒有對業務部門的代碼和接口調用方式做任何修改的同時,也沒有對基礎平台部原有的代碼做內部修改,僅僅是添加了一個裝飾函數,就實現了我們的需求,在函數調用前進行認證,調用后寫入日志。這就是裝飾器的最大作用。

 

  f1._name_    輸出inner。Python內置functools.wraps(),可以解決它們的__name__已經從原來的'f1'變成了'inner'的問題

 

import functools

def log(text):    ###now = log('execute')(now)
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
@log('execute') ###decorator本身需要傳入參數
def now():
    print('2015-3-25')

 

#帶參數
def outer(func):
    def inner(*args, *kwargs):
        print("認證成功")
        result = func(*args, **kwargs)
        print("日志添加成功")
        return result
    return inner
@outer
def f1(name, age):
    print("{}正在調用業務部門1的數據接口".format(name))
# 調用方法
f1("jack", 19)
#有多個裝飾器
def outer1(func):
    def inner(*args,**kwargs):
        print("認證成功!")
        result = func(*args,**kwargs)
        print("日志添加成功")
        return result
    return inner


def outer2(func):
    def inner(*args,**kwargs):
        print("一條歡迎信息。。。")
        result = func(*args,**kwargs)
        print("一條歡送信息。。。")
        return result
    return inner


@outer1
@outer2
def f1(name,age):
    print("%s 正在連接業務部門1數據接口......"%name)

# 調用方法
f1("jack",18)
###裝飾器中形參是函數   
 # 認證函數
    def  auth(request,kargs):
        print("認證成功!")
        
    # 日志函數
    def log(request,kargs):
        print("日志添加成功")
        
    # 裝飾器函數。接收兩個參數,這兩個參數應該是某個函數的名字。
    def Filter(auth_func,log_func):
        # 第一層封裝,f1函數實際上被傳遞給了main_fuc這個參數
        def outer(main_func):
            # 第二層封裝,auth和log函數的參數值被傳遞到了這里
            def wrapper(request,kargs):
                # 下面代碼的判斷邏輯不重要,重要的是參數的引用和返回值
                before_result = auth(request,kargs)
                if(before_result != None):
                    return before_result;
    
                main_result = main_func(request,kargs)
                if(main_result != None):
                    return main_result;
    
                after_result = log(request,kargs)
                if(after_result != None):
                    return after_result;
            return wrapper
        return outer
    # 注意了,這里的裝飾器函數有參數哦,它的意思是先執行filter函數。然后將filter函數的返回值作為裝飾器函數的名字返回到這里。所以,Filter(auth,log) = outer , @Filter(auth,log) =  @outer
    @Filter(auth,log)
    def f1(name,age):
        print("%s 正在連接業務部門1數據接口......"%name)
    
    # 調用方法
    f1("jack",18)

 

 5.6 偏函數

  functools.partial的作用就是,把一個函數的某些參數給固定住(也就是設置默認值),返回一個新的函數。

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

固定參數,返回新的函數。

 

 

 參考:菜鳥教程和廖雪峰Python3

 https://www.jianshu.com/p/affeb6acf1c9


免責聲明!

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



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