1. 程式人生 > >guxh的python筆記:函式基礎

guxh的python筆記:函式基礎

1,函式的引數

1.1,檢視函式的引數型別

def run(a, *args, b, **kwargs):
    return a + b

可以通過如下方式檢視引數型別:

import inspect
k = inspect.signature(run)
for i, j in k.parameters.items():
   print('{:7}:'.format(i) , j.kind)

輸出結果為:

  a            : POSITIONAL_OR_KEYWORD
  args       : VAR_POSITIONAL
  b            : KEYWORD_ONLY
  kwargs  : VAR_KEYWORD

含義如下:

POSITIONAL_OR_KEYWORD:位置引數或者關鍵字引數,可以用位置引數或者關鍵字引數方式傳參

VAR_POSITIONAL:可變位置引數,*args

KEYWORD_ONLY:僅限關鍵字引數,*args或者*後面的,只能用關鍵字引數方式傳參

VAR_KEYWORD:可變關鍵字引數,**kwargs

POSITIONAL_ONLY:目前不支援

 

1.2,傳參方法

位置引數必須在關鍵字引數前面!

def test(x, y,z)
    .......

傳參:

位置引數:test(a, b, c)  
關鍵字接收:test(y=a, x=b, z=c)   # 關鍵字引數,可顛倒次序
混合:test(1, z=2, y=6) # 位置引數必須在關鍵字引數前面,後面2個可以顛倒

 

1.3,*args,數量可變位置引數

args:序列

*args:  序列中的值

def test(x, *args):
    print(x, *args)  # 1,2,3
    print(x, args)  # 1,(2,3)
test(1,2,3) # 或test(*[1,2,3])

  

1.4,**kwargs,數量可變的關鍵字引數

kwargs:字典

*kwargs: 字典的key

**kwargs:字典的鍵值對

 

def test(**kwargs):
    print(kwargs)   #  {'name': 'guxh', 'age': 18}
    print(*kwargs)   # name age
    print(kwargs['name'])  # 'guxh'
test(name='guxh', age=18) # 或test(**{'name':'guxh', 'age':18})

 

1.5,僅限關鍵字引數

*後面的是僅限關鍵字引數:

def test(x, *, y):
	print(x, y)

test('a', 'b')  # TypeError
test('a', y='b')  # OK

*args後面的是僅限關鍵字引數:

def test(*args, y):
	print(*args, y)

test('a', 'b')  # TypeError
test('a', y='b')  # OK

  

1.6,特殊傳參

組合傳參,如果name用關鍵字引數傳參,則age必須用關鍵字引數傳參,因為位置引數必須在關鍵字引數前面。

def test(name, age=18, *args, **kwargs):
    print(name)  # 位置引數或關鍵字引數,'guxh'
    print(age)   # 位置引數或關鍵字引數,34
    print(args)   # 可變位置引數,()
    print(kwargs)  # 可變關鍵字引數,{'sex': 'f', 'hobby': 'python'}
test('guxh', 34, sex='f',hobby='python')
test(name='guxh', age=34, sex='f',hobby='python')

 

序列傳參,字典傳參:

def test(x, y):test(*序列),或test(**字典)

def test(*args) : test(*序列)

def test(**kwargs) :test(**字典)

 

2,防禦可變引數

 

 

 

 

 

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

待修訂


5,內建函式
5.1,遞迴函式
函式內部呼叫自己,就叫遞迴函式
最大遞迴次數是999次,超過就會報錯
例如:
def cal(n):
    print(n)
    return cal(n+1)
cal(0)
列印到998就報錯
遞迴要有明確結束條件、每次呼叫要減少問題規模,效率不高
例如:
def cal(n):
    print(n)
    if int(n/2) > 0:
        return cal(int(n/2))
cal(10)

5.2,匿名函式lambda
方式一:
cacl = lambda x:x*3
cacl(3) # 9
方式二:
(lambda x:x*3)(3)  # 9 

5.3,內建函式概述
1)all(iterable):全部為真返回True,否則返回False
2)any(iterable):任意為真返回Ture,否則返回False
3)ascii(object):沒什麼用
4)bin(x):將整數轉換為二進位制數
5)bool(x):判斷真假
6)bytes ('abcde', encoding='utf-8'): 把字串變成位元組碼,這時如果賦給a,a[0]會顯示97
7)bytearray('abcde', encoding='utf-8'):與bytes的區別是,位元組碼變成可以修改的了
8)callable(object):判斷物件是否可以呼叫,後面可以加()的就可以呼叫
9)chr(i):輸入一個數字,返回ascii對應的字母符號;ord(x)與其相反,輸入字元,返回數字
10)classmethod(function):
11)compile(......):用不到,底層用於編譯,結合exec可以實現動態匯入功能(相當於import)
12)complex():用不到,複數
13)delattr(object, name)
14)dir([object]):看object有哪些方法,例如a = {},  dir(a)看字典a有哪些方法
15)divmond(a, b):相除,並返回(商,餘數)
16)enumerate(iterable, start=0):迭代index和value
17)eval(expression, globals=None, locals=None):反序列化,把字串變字典/列表等,a = '{}'; eval(a) # 輸出{}
把字串變成物件,如果字串是可執行的命令,還可以執行並返回結果
例如:
s = 'locale.getpreferredencoding()'
res = eval(s)
總結:序列化是物件變字串,反序列化是字串變物件(注意函式也是物件,python中一切皆物件)
18)exec(objects[,globals[,locals]]):動態呼叫?
19)filter(function, iterable):lambda無法處理for迴圈,只能做簡單的三元運算,lambda一般都結合fiter、map、reduce使用,詳見5.4
20)float()
21)format()
22)frozenset([iterable]):把list或者集合變成不可變
23)globals():用不到,返回程式內所有key,value
24)hash(object):計算雜湊值
25)hex(x) : 轉為16進位制
26)id(object):列印ID
27)input()
28)class int
29)isinstance()
30)issubclass():判斷是否子類
31)iter()
32)len(s):判斷長度
33)locals():用不到,列印區域性變數
34)max():返回最大值
35)min():返回最小值
36)memoryview(obj):用不到
37)next():迭代器next()
38)class object:python一切皆物件
39)oct(x):轉8進位制
40)open(file, mode='r', encoding=None):開啟檔案
41)ord():與chr()相反
42)pow(2,8):返回2的8次方
43)print()
44)range()
45)repr(obj):把系統輸出的東西轉換成字串
46)reversed(seq):翻轉序列,python3中,反轉後是迭代器,可以這樣賦值獲取:lista = [1,2,3,4,5,6,7,8,9]; listb = [i for i in reversed(lista)]
47)round(1.333, 2):1.333保留2位小數
48)class set:集合
49)setattr:非常重要
50)slice:沒什麼用,切片,d=range(20);  d[slice(2,5)]  等價於 d[2:5]
51)sorted:排序,可對序列排序,如果想對字典進行排序需要先將字典轉換為列表:
    dict = {10:20, 22:2, 1:99, 50:21, 37:9}
    print(sorted(dict))  # 預設對key排序[1, 10, 22, 37, 50]
    print(sorted(dict.items()))  # 按key排序[(1, 99), (10, 20), (22, 2), (37, 9), (50, 21)]
    print(sorted(dict.items(), key=lambda x:x[1]))  # 按value排序[(22, 2), (37, 9), (10, 20), (50, 21), (1, 99)]
52)staticmethod(function):
53)class str
54)sum:求和
55)supper:非常重要,繼承
56)tupple([iterable]):轉換為元組
57)class type(obj):
58)vars([obj]):用不到,返回一個物件的所有屬性名
59)zip:多組資料一起迭代,長度如果不一致按照資料最少的來
60)import:import 'decorator' 等價於 __import__('decorator')

5.4,filter、map、reduce 
map/filter + lambda = 列表推導式
foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
1)filter濾出符合的資料(基於bool過濾)
過濾出來的內容,python2裡是iterable,python3裡是iterator,列表推導式都是iterable
例子一:foo中過濾出x % 3 == 0 的資料:
filter(lambda x:x%3 == 0,  foo)    # 3是iterator,2是iterable,[18, 9, 24, 12, 27]
例子二,將大於10的過濾出來
filter(lambda x:x>10,  foo)  # 3是iterator,2是iterable,[18, 22, 17, 24, 12, 27]
等價的列表推導式:
[i for i in foo if i >10]  # 3和2都是iterable
2)map對每項都運算下
同filter,python2裡是iterable,python3裡是iterator,列表推導式都是iterable
例子一,foo中所有資料執行x*2+10:
map方法:map(lambda x: x * 2 + 10,  foo)   # [14, 46, 28, 54, 44, 58, 26, 34, 64]
列表推導式方法:[i:i*2+10  for i in foo]
例子二:將列表數值轉為字串:
map方法:map(str,foo)    # ['2', '18', '9', '22', '17', '24', '8', '12', '27']
列表推導式方法:[str(i) for i in foo]
注意:map函式返回的是一個class map,可以通過list(map)把結果打印出來
3)reduce不停迭代
python2.7可以直接用,python3需要import functools
functools.reduce(lambda x,y:x+y, foo)   /不停迭代運算,得到139
4)filter和map應用差別舉例
filter滿足條件的過濾出來,map所有專案全都會運算一邊,例如有一個text,需要有一個list裡去匹配的話,
fdx_list_temp=filter(lambda x:re.search(r'\D(%s)(\Z|\D)'%x,element).group(1) if re.search(r'\D(%s)(\Z|\D)'%x,element) else None,list)
list=['301','302','303','304','305']
element='aaaaaa.303.aaaaaaaaaa'
如果是filter,得到['303']
如果是map,得到[None,None,303,None,None]

5)map、filter的列表推導等價
要求找出list中能被2整除的數,並且執行平方運算
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
q1 = []         # 方法一:最原始方法
for element in list:
    if element % 2 == 0:
        q1.append(element**2)
q2 = [x**2 for x in list if x % 2 == 0]     # 方法二:推導列表
q3 = map(lambda x: x**2,  filter(lambda x: x%2 == 0, list))    # 方法三:map/filter

5.5,input和raw_input
1)輸入
input():只有python2.x有,使用者輸入什麼就是什麼,比如輸入abc,python2.x當作是abc變數,除非輸入“abc”才當字串,雞肋不要去用它
raw_input():將使用者輸入任何內容作為原始資料,在python3.x中,input就是raw_input的意思
例如如果要輸入字串,用input需要加“”,用raw_input不需要加
如果向讓輸入不可見,可以import getpass,然後password = getpass.getpass("password:")  # 注意pycharm中getpass不管用,要在cmd環境下執行
2)格式化輸出
輸出方法一:字串拼接,例如:
'''name is''' + name 

輸出方法二:%s佔位符,先佔位,再補上,例如:
"my name is %s, age is %s"%('guxh', '19')
常用的引數有,%s字串,%d 整數,%f 浮點數

輸出方法三:用{name},例如:
"my name is {name}, age is {age}".format(name='guxh', age=19) # {age: .2f}可以設定輸出age格式,浮點保留2位
"my name is {name}, age is {age}".format(**{'name': 'guxh', 'age': 19})

輸出方法四,用{}或者{index},例如:
"my name is {}, age is {}".format('guxh', 19) # {:.2f},age浮點保留2位
"my name is {0}, age is {1}".format('guxh', 19) # {1:.2f},age浮點保留2位

格式化引數:
^, <, > 分別是居中、左對齊、右對齊,後面頻寬度,
: 號後面帶填充的字元,只能是一個字元,不指定則預設是用空格填充。
+ 表示在正數前顯示 +,負數前顯示 -;  (空格)表示在正數前加空格
b、d、o、x 分別是二進位制、十進位制、八進位制、十六進位制
舉例: '{:@>18,.2f}'.format(70305084.0) # >右對齊,@缺失部分用@填充,18固定寬度,','千分位,'.2'浮點精度2,f浮點數宣告
輸出:@@@@@70,305,084.00

5.6,替換函式
str.replace
strip
re.sub

 

 

6,高階函式
滿足下面兩個條件之一的就叫高階函式:
    a,把一個函式名當作實參傳給另外一個函式(在不修改被裝飾函式原始碼的情況下為其新增功能)
例如:def add(-5, 6, abs) # abs是內建函式取絕對值
    b,返回值中包含函式名(不修改函式的呼叫方式)
例如:return abs
即:高階函式 = 引數是函式名,或者返回值包含函式名
這2個條件都嚴格遵循函式即變數
備註:函式的門牌號就是記憶體地址,有了門牌號(記憶體地址)加上小括號就可以執行記憶體裡的函式體,獲取其返回值,有()傳的是返回值,沒有()傳的是門牌號

def bar():
    print('the result...')
test(bar)   # 把門派號,即地址傳給test()函式
test(bar())  # 把bar()的返回值,即None傳給test()函式

條件a - 列印函式變數地址:
def bar():  # bar是個門牌號,bar()是執行門牌號指向的函式體
    print('in the bar')
def test(func):  
    print(func)  # 打印出了bar的門牌號(地址)
    func()  # 執行bar()
test(bar)   # 把bar作為變數傳遞給test()函式

條件b - 列印函式變數地址:
def bar():
    time.sleep(3)
    print('in the bar')
def test2(func):
    print(func)   # 列印了bar的門牌號
    return func  
bar=test2(bar)  # 新的bar覆蓋了原來舊的bar,新的bar去test2執行了2步:列印舊bar門牌號,返回舊bar的門牌號
bar()  # 執行新的bar,共2步:列印舊bar門牌號,執行舊bar程式,等同於test2(bar)()
test2相當於裝飾器作用,不改變bar呼叫方式,不改變bar原始碼

條件a - 統計函式執行時間:
def bar():
    time.sleep(3)
    print('in the bar')
def test(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print('the running time of func is %s'%(stop_time - start_time)) 
test(bar)  # test有點類似於裝飾器,給bar()附加了其他功能,統計其執行時間,但因為呼叫方式改變了,用的是test(bar),而不是bar(),所以不是裝飾器

條件b - 統計函式執行時間:
def deco(func):
    start_time = time.time()
    func()   # 第一遍列印in the test2
    stop_time = time.time()
    print(('running time of func is %s')%(stop_time - start_time))
    return func
def test2():
    time.sleep(2)
    print('in the test2')  # 第二遍列印in the test2
test2 = deco(test2) # 這時呼叫deco函式時列印第一遍
test2() # 這時呼叫test函式時列印第二遍
本來想統計下test2執行的時間,但存在的問題是,in the test列印了2遍

7,巢狀函式
函式內部再定義一個函式,即def內部再def一個函式
函式內部呼叫一個函式不算函式巢狀
 
8,函數語言程式設計
注意函數語言程式設計不是我們認為的函式
更接近數學運算,通過一堆函式來回呼叫,得到結果
函數語言程式設計只要輸入是確定的,輸出也是確定的
程式碼簡介,但是難以閱讀
eg:var result = subtract(multiply(add(1,2), 3), 4);

9,外接函式
9.1,時間戳
def timeformat(item):  # 改時間戳
    local_timeArray = time.strptime(item, "%Y-%m-%d %H:%M:%S")
    local_timeStamp = int(time.mktime(local_timeArray))
    return round(float(local_timeStamp)/3600, 2)   # 對時間戳換算到小時並保留2位

9.2,SYS和OS庫檔案
sys.path # 列印python環境變數
sys.argv # pycharm列印絕對路徑,cmd列印相對路徑
os.system("dir")  # 呼叫windows dir命令,列印當前目錄,不儲存結果,成功則返回0
os.popen('dir')  # 呼叫windows dir命令,列印當前目錄,並儲存結果,成功則返回地址,可以通過read()去取內容
os.mkdir('new_dir')  # 呼叫windows mkdir命令,建立新目錄
 
9.3,Sys.argv[ ]
是一個列表,裡面的專案為使用者輸入的引數
例如 python  test.py 1 2 3  
argv = ['test.py', '1', '2', '3']