10函數_函數參數

 

函數、函數參數、參數解構

 

python函數與其它語言不太一樣;

 

函數:

數學定義,y=f(x)yx的函數,x是自變量;

python函數,由語句塊、函數名稱、參數列表、若干語句構成,它是組織代碼的最小單元,完成一定的功能;

 

作用:

結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼;

封裝的目的爲了複用,減少冗餘代碼;

代碼更加簡潔美觀、可讀易懂(工業化要求);

 

分類:

內建函數built-in,如max(),reversed()等;

庫函數,如math.ceil()等、第三方庫;

 

函數定義(聲明):

def語句定義函數;

def 函數名(參數列表):

         函數體(代碼塊)

         [return 返回值]

函數名,就是標識符,命名要求一樣(見明知義);

語句塊必須縮進,約定4個空格;

python的函數沒有return語句,隱式會返回一個None值;在一些語言中函數沒有返回值稱爲過程,有返回值稱爲函數;

函數中若有兩個return,只返回第一個return的結果,return a,b返回的是tuple類型;

定義中的參數列表稱爲形式參數,只是一種符號表達,簡稱形參,即y=f(x)中的x

定義要在調用前,否則拋NameError異常;

 

函數調用:

函數定義,只是聲明瞭一個函數,它不會被執行,需要調用,不調用的函數與變量一樣;

調用的方式,就是函數名加上小括號,括號內寫上參數;

調用時寫的參數是實際參數,是實實在在傳入的值,簡稱實參;

函數是可調用對象,可用callable()判斷;

 

例:

In [1]: def add(x,y):

   ...:     result = x + y

   ...:     return result

   ...:

In [2]: out=add(4,5)

In [3]: out

Out[3]: 9

In [4]: callable(add)

Out[4]: True

 

函數參數:

參數調用時傳入的參數要和定義的個數相匹配(可變參數例外,內建函數中列表是作爲整體傳入的);

位置參數 def f(x,y,z):,調用時使用f(1,3,5),按照參數定義順序傳入實參;

關鍵字參數(命名參數keyword),def f(x,y,z):,調用時使用f(x=1,y=3,z=5),使用形參的名字來傳入實參的方式,如果使用了形參名字,那麼傳參順序可和定義順序不同;

傳參,位置參數必須在關鍵字參數之前傳入,位置參數是按位置對應的(簡單的往前放,複雜的往後放);

 

例:

In [6]: def f(x,y,z):

   ...:     print(x,y,z)

   ...:    

In [7]: f(z=None,y=10,x=[1])

[1] 10 None

In [8]: f((1,),z=6,y=4.1)

(1,) 4.1 6

In [9]: f(y=5,z=6,2)   #錯誤,位置參數必須在關鍵字參數之前傳入

  File "<ipython-input-9-c873e911554f>", line 1

    f(y=5,z=6,2)

             ^

SyntaxError: positional argument follows keyword argument

 

函數參數默認值

定義時,在形參後賦一個值;

作用:參數的默認值,可在未傳入足夠的實參的時候,對沒有給定的參數賦值爲默認值;參數非常多的時候,並不需要用戶每次都輸入所有的參數,簡化函數調用;

調用時必須要傳的參數,在定義時寫在前面;

調用時可用默認值的參數,在定義時寫在後面;

定義函數時,參數超過2個,都開始用缺省值參數,把重要的參數往前放;

 

例:

In [1]: def add(x=4,y=5):   #xy類型不一樣時會異常

   ...:     return x+y

   ...:

In [2]: add()

Out[2]: 9

In [3]: add(6,10)

Out[3]: 16

In [4]: add(6,y=7)

Out[4]: 13

In [5]: add(x=5)

Out[5]: 10

In [6]: add(y=7)

Out[6]: 11

In [7]: add(x=5,6)

  File "<ipython-input-7-9f5938d26e25>", line 1

    add(x=5,6)

           ^

SyntaxError: positional argument follows keyword argument

In [8]: add(y=8,4)

  File "<ipython-input-8-013636d44ec1>", line 1

    add(y=8,4)

           ^

SyntaxError: positional argument follows keyword argument

In [9]: add(x=5,y=6)

Out[9]: 11

In [9]: add(x=5,y=6)

Out[9]: 11

In [10]: add(y=6,x=5)

Out[10]: 11

In [11]: def add(x=4,y):   #缺省值要往後放

    ...:     pass

  File "<ipython-input-11-797c4f959f43>", line 1

    def add(x=4,y):

           ^

SyntaxError: non-default argument follows default argument

In [12]: def add(x,y=5):

    ...:     return x+y

    ...:

In [13]: add()

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-13-d5d29de3ed94> in <module>()

----> 1 add()

TypeError: add() missing 1 required positional argument: 'x'

In [14]: add(10)

Out[14]: 15

 

例:

定義一個函數login,參數名稱爲host,port,username,password

In [17]: def login(host='127.0.0.1',port='8080',username='jowin',password='chai'):

    ...:     print('{}:{}@{}/{}'.format(host,port,username,password))

    ...:    

In [18]: login()

127.0.0.1:8080@jowin/chai

In [19]: login('127.0.0.1',80,'jerry','jerry')

127.0.0.1:80@jerry/jerry

In [20]: login('localhost',port=80,password='test')

localhost:80@jowin/test

In [21]: login(port=80,password='test',host='localhost')

localhost:80@jowin/test

 

可變參數:

一個形參可以匹配任意個(包括0個)參數(實參);

 

位置可變參數

在形參前使用*,表示該形參是可變參數,可以接收多個實參,函數名約定用*args

收集多個實參爲一個tuple

關鍵字參數也能傳遞任意多個嗎?不能

 

關鍵字可變參數

形參前使用**,表示可接收多個關鍵字參數,參數名約定用**kwargs

收集的實參名稱和值組成一個字典;

 

可變參數總結:

有位置可變參數和關鍵字可變參數;

位置可變參數在形參前使用*

關鍵字可變參數在形參前使用**

位置可變參數和關鍵字可變參數都可收集若干個實參,位置可變參數收集形成一個tuple,關鍵字可變參數收集形成一個dict

混合使用參數時,可變參數要放到參數列表的最後(普通參數需放到參數列表前面),位置可變參數需要在關鍵字可變參數之前;

 

keyword-only參數

python3加入;

如果在一個星號參數後,或者一個位置可變參數後,出現的普通參數,實際上已經不是普通參數了,而是keyword-only參數;

使用方式一,def fn(*args,x):def fn(*args,x,y,**kwargs):

使用方式二,def fn(*,x,y):def fn(z,*,x,y),只允許x,y兩個參數,且這兩個參數只能是keyword-only參數,*之後,普通形參都變成了必須給出的keyword-only參數;

def fn(**kwargs,x):SyntaxError**kwargs後不需要再跟keyword,多此一舉,可理解爲**kwargs會截取所有的關鍵字參數,就算有x=5x也永遠得不到這個值,所以語法錯誤;

 

例:

In [22]: def add(nums):   #需求,多個數累加求和

    ...:     sum=0

    ...:     for i in nums:

    ...:         sum+=i

    ...:     return sum

    ...:

In [23]: add([1,3,5])   #傳入一個可迭代對象,迭代元素求和

Out[23]: 9

In [24]: add((2,4,6))

Out[24]: 12

In [27]: def add(*args):

    ...:     sum=0

    ...:     print(type(args))   #tuple,傳進後是不可變類型

    ...:     for i in args:

    ...:         sum+=i

    ...:     print(sum)

    ...:     return sum

    ...:

In [28]: add(3,6,7)

<class 'tuple'>

16

Out[28]: 16

In [29]: val=add(3,5,7)   #函數中若無returnval的值爲None;不認關鍵字參數

<class 'tuple'>

15

In [30]: val

Out[30]: 15

 

例:

In [31]: def showconfig(**kwargs):

    ...:     print(type(kwargs))

    ...:     for k,v in kwargs.items():   #dict.items()python3中叫dictionary view

    ...:         print('{}={}'.format(k,v))

    ...:        

In [32]: showconfig(host='localhost',port=8080,username='joiwn',password='chai')

<class 'dict'>

password=chai

port=8080

username=joiwn

host=localhost

 

可變參數混合使用:

def showconfig(username,password,**kwargs):

def showconfig(username,*args,**kwargs):

def showconfig(username,password,**kwargs,*args):   #錯誤,位置可變參數需在關鍵字可變參數之前

 

例:

In [33]: def fn(x,y,*args,**kwargs):

    ...:     print(x)

    ...:     print(y)

    ...:     print(args)

    ...:     print(kwargs)

    ...:    

In [34]: fn(3,5,7,9,10,a=1,b='python')

3

5

(7, 9, 10)

{'a': 1, 'b': 'python'}

In [35]: fn(3,5)

3

5

()

{}

In [36]: fn(3,5,7)

3

5

(7,)

{}

In [37]: fn(3,5,a=1,b='python')

3

5

()

{'a': 1, 'b': 'python'}

In [38]: fn(7,9,y=5,x=3,a=1,b='python')   #y=5,x=3與前面的7,9重複了,multiple values

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-38-58efe90dffe9> in <module>()

----> 1 fn(7,9,y=5,x=3,a=1,b='python')

TypeError: fn() got multiple values for argument 'y'

 

例:

In [39]: def fn(*args,x,y,**kwargs):   #此種方式定義屬keyword-only,在調用傳參時x,y要用關鍵字參數形式,要先滿足keyword-only,即x,y,其它的纔有着落

    ...:     print(args)

    ...:     print(x)

    ...:     print(y)

    ...:     print(kwargs)

    ...:    

In [40]: fn(7,9,y=5,x=3,a=1,b='python')   #*args後的x,ykeyword-only參數,要先滿足它倆

(7, 9)

3

5

{'a': 1, 'b': 'python'}

In [41]: fn(3,5)

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-41-c5325f4c0ff0> in <module>()

----> 1 fn(3,5)

TypeError: fn() missing 2 required keyword-only arguments: 'x' and 'y'

In [42]: fn(3,5,7)

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-42-da5434142bea> in <module>()

----> 1 fn(3,5,7)

TypeError: fn() missing 2 required keyword-only arguments: 'x' and 'y'

In [43]: fn(3,5,a=1,b='python')

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-43-018d4ba64920> in <module>()

----> 1 fn(3,5,a=1,b='python')

TypeError: fn() missing 2 required keyword-only arguments: 'x' and 'y'

 

例:

In [44]: def fn(*args,x):   #args可以看作已經截獲了所有的位置參數,x不使用關鍵字參數就不可能拿到實參

    ...:     print(args)

    ...:     print(x)

    ...:    

In [45]: fn(3,5,x=7)   #fn(3,5)fn(3,5,7)均是錯的

(3, 5)

7

 

例:

In [47]: def fn(*,x,y):

    ...:     print(x,y)

    ...:    

In [48]: fn(x=1,y=2)   #fn(4,5)fn(6,x=1,y=2)錯誤

1 2

In [49]: def fn(z,*,x,y):   #x,y必須是keyword-only參數,z不作要求

    ...:     print(x,y)

    ...:    

In [50]: fn(1,x=2,y=3)

2 3

 

例(可變參數和參數默認值):

In [1]: def fn(*args,x=5):

   ...:     print(args)

   ...:     print(x)

   ...:    

In [2]: fn()

()

5

In [3]: fn(5)   #25不一樣

(5,)

5

In [4]: fn(x=6)

()

6

In [5]: def fn(y,*args,x=5):

   ...:     print('x={},y={}'.format(x,y))

   ...:     print(args)

   ...:    

In [6]: fn(5)   #fn()fn(x=6)錯誤,至少要給y一個位置參數

x=5,y=5

()

In [7]: fn(y=17,2,3,x=10)   #關鍵字參數一定要放到位置參數後面

  File "<ipython-input-7-89c585e00820>", line 1

    fn(y=17,2,3,x=10)

           ^

SyntaxError: positional argument follows keyword argument

In [8]: fn(1,2,y=3,x=10)   #y重複了

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-8-ca712b8f6fdb> in <module>()

----> 1 fn(1,2,y=3,x=10)

TypeError: fn() got multiple values for argument 'y'

In [9]: fn(1,2,3,x=10)

x=10,y=1

(2, 3)

In [10]: def fn(x=5,**kwargs):

    ...:     print('x={}'.format(x))

    ...:     print(kwargs)

    ...:    

In [11]: fn()

x=5

{}

In [12]: fn(5)

x=5

{}

In [13]: fn(x=6)

x=6

{}

In [14]: fn(y=3,x=10)

x=10

{'y': 3}

In [15]: fn(3,y=10)

x=3

{'y': 10}

 

參數規則:

參數列表一般順序是,普通參數-->缺省參數-->可變位置參數-->keyword-only參數(可帶缺省值)-->可變關鍵字參數

注:

代碼應該易讀易懂,而不是爲難別人;

要按照書面習慣,定義函數;

 

例:

In [16]: def fn(x,y,z=3,*args,m=4,n,**kwargs):   #def fn(x,y,z=3,*,n,m=4,**kwargs):這樣最好

    ...:     print(x,y,z,m,n)

    ...:     print(args)

    ...:     print(kwargs)

    ...:    

In [17]: fn(1,2,n=3)

1 2 3 4 3

()

{}

In [18]: fn(1,2,10,11,t=7,n=5)

1 2 10 4 5

(11,)

{'t': 7}

In [19]: fn(1,2,10,11,n=5,t=100)

1 2 10 4 5

(11,)

{'t': 100}

In [20]: fn(1,2,10,11,x=3,n=4)   #x重複

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-20-05ecc476ee5d> in <module>()

----> 1 fn(1,2,10,11,x=3,n=4)

TypeError: fn() got multiple values for argument 'x'

 

例:

In [22]: def connect(host='localhost',port='3306',user='admin',passwd='admin',**kwargs):

    ...:     print(host,port)

    ...:     print(user,passwd)

    ...:     print(kwargs)

    ...:    

In [23]: connect(db='cmdb')

localhost 3306

admin admin

{'db': 'cmdb'}

In [24]: connect(host='192.168.7.47',db='cmdb')

192.168.7.47 3306

admin admin

{'db': 'cmdb'}

In [25]: connect(host='192.168.7.47',db='cmdb',passwd='myadmin')

192.168.7.47 3306

admin myadmin

{'db': 'cmdb'}

 

 

 

參數解構:

給函數提供實參的時候,可在集合類型前使用***,把集合類型的結構解開,提取出所有元素作爲函數的實參;

非字典類型使用*,解構成位置參數;

字典類型使用**,解構成關鍵字參數;

提取出來的元素數目要和參數的要求匹配,也要和參數的類型匹配;

 

例:

In [26]: def add(x,y):

    ...:     return x+y

    ...:

In [27]: add(4,5)

Out[27]: 9

In [28]: add((4,5))

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-28-42490dde0648> in <module>()

----> 1 add((4,5))

TypeError: add() missing 1 required positional argument: 'y'

In [29]: t=(4,5)

In [30]: add(t[0],t[1])

Out[30]: 9

In [31]: add(*t)

Out[31]: 9

In [32]: add(*range(4,6))

Out[32]: 9

 

例:

In [1]: def add(x,y):

   ...:     return x+y

   ...:

In [2]: d={'x':5,'y':6}

In [3]: add(**d)

Out[3]: 11

In [4]: add(**{'a':5,'b':6})   #關鍵字參數中沒有a,b

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-4-33098ef826f4> in <module>()

----> 1 add(**{'a':5,'b':6})

TypeError: add() got an unexpected keyword argument 'a'

In [6]: add(*d.keys())

Out[6]: 'yx'

In [7]: add(*d.values())

Out[7]: 11

 

參數解構和可變參數:

例:

In [8]: def add(*iterable):

   ...:     result=0

   ...:     for i in iterable:

   ...:         result+=i

   ...:     return result

   ...:

In [9]: add(1,2,3)

Out[9]: 6

In [10]: add(*[1,2,3])   #常用

Out[10]: 6

In [11]: add(*range(10))

Out[11]: 45

 

例:

In [13]: def fn(a,b):

    ...:     return a,b

    ...:

In [14]: type(fn(4,5))   #return a,b返回的tuple類型,若函數中有多個return語句,只返回第一個return的結果

Out[14]: tuple

 

習題:

1、編寫一個函數,能接受至少2個參數,返回最小值和最大值?

def double_values(*args):

    print(args)

    return max(args),min(args)

 

fn(3,2,22,2,1)

#####################

import random

 

def double_values(*args):

    print(args)

    return max(args),min(args)

 

print(*double_values(*[random.randint(10,20) for _ in range(10)]))   #兩處解構,double_values前面若無*則打印tupleprint()函數有隱式轉換str(),即使是print(1,2)也會把1,2轉爲string類型再打印

 

2、編寫一個函數,接受一個參數nn爲正整數),左右兩種打印方式,要求數字必須對齊?

1.jpg

################################

2.jpg

#############################

方一:

lst = [str(i) for i in range(12,0,-1)]

strs = ' '.join(lst)

length = len(strs)

 

print(strs,length,sep='\n')

 

for i in range(1,12):

    print('{:>{}}'.format(' '.join([str(j) for j in range(i,0,-1)]),length))

print(strs)

#################

lst = [str(i) for i in range(12,0,-1)]

strs = ' '.join(lst)

length = len(strs)

 

for col in range(1,12):

    row = ' '.join([str(j) for j in range(col,0,-1)])

    #print(row)

    print('{}{}'.format(' '*(length-len(row)),row))

print(strs)

#################

def show(num):

    tail = ' '.join([str(i) for i in range(num,0,-1)])

    width = len(tail)

    for i in range(1,num):

        print('{:>{}}'.format(' '.join([str(j) for j in range(i,0,-1)]),width))

    print(tail)

 

show(12)

#################

lst = [str(i) for i in range(12,0,-1)]

strs = ' '.join(lst)

length = len(strs)

 

print(strs)

for col in range(11,0,-1):

    row = ' '.join([str(j) for j in range(col,0,-1)])

    #print(row)

    print('{}{}'.format(' '*(length-len(row)),row))

####################

方二:

def show(num):

    tail = ' '.join([str(i) for i in range(num,0,-1)])

    print(tail)

    for i in range(len(tail)):   #無需再次生成列表

        if tail[i] == ' ':

            print(' '*i,tail[i+1:])

 

show(15)

#####################

方三:

def show(num):

    for i in range(1,num+1):

        for j in range(num,0,-1):

            if i < j:

                print(' '*len(str(j)),end=' ')

            else:

                print(j,end=' ')

        print()

 

show(15)

#########################

 

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章