天天看點

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

文章目錄

  • 一、内置函數
    • 1 作用域相關
    • 2 其他
      • Ⅰ 字元串類型代碼的執行:
      • Ⅱ 輸入輸出相關:
      • Ⅲ 資料類型相關:
      • Ⅳ 記憶體相關:
      • Ⅴ 檔案操作相關
      • Ⅵ 子產品操作相關
      • Ⅶ 幫助方法
      • Ⅷ 調用相關
      • Ⅸ 檢視參數所屬類型的所有内置方法
    • 3 數字相關
    • 4 資料結構相關
  • 二、匿名函數
    • 1 匿名函數格式的說明:
    • 2 有名函數與匿名函數的對比:
    • 3 lambda與内置函數結合使用
  • 三、遞歸函數
    • 1 遞歸調用的定義
    • 2 遞歸調用的兩個階段:遞推,回溯
    • 3 python中的遞歸
    • 4 二分法

一、内置函數

截止到python版本3.6.2,現在python一共為我們提供了68個内置函數。它們就是python提供給你直接可以拿來使用的所有函數。

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

把這些函數分成了6大類:

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

1 作用域相關

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

基于字典的形式擷取局部變量和全局變量

globals()——擷取全局變量的字典

locals()——擷取執行本方法所在命名空間内的局部變量的字典

2 其他

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

Ⅰ 字元串類型代碼的執行:

eval() 将字元串類型的代碼執行并傳回結果

print(eval('1+2+3+4'))

# 10
           

**exec()**将自字元串類型的代碼執行

print(exec("1+2+3+4"))
exec("print('hello,world')")

# None
# hello,world
           

compile 将字元串類型的代碼編譯。代碼對象能夠通過exec語句來執行或者eval()進行求值。

參數說明:

  1. 參數source:字元串或者AST(Abstract Syntax Trees)對象。即需要動态執行的代碼段。
  2. 參數 filename:代碼檔案名稱,如果不是從檔案讀取代碼則傳遞一些可辨認的值。當傳入了source參數時,filename參數傳入空字元即可。
  3. 參數model:指定編譯代碼的種類,可以指定為 ‘exec’,’eval’,’single’。當source中包含流程語句時,model應指定為‘exec’;當source中隻包含一個簡單的求值表達式,model應指定為‘eval’;當source中包含了互動式指令語句,model應指定為’single’。

流程語句使用exec

code1 = 'for i in range(0,10): print (i)'
compile1 = compile(code1, '', 'exec')
exec(compile1)

# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
           

簡單求值表達式用eval

code2 = '1 + 2 + 3 + 4'
compile2 = compile(code2, '', 'eval')
eval(compile2)

           

互動語句用single

code3 = 'name = input("please input your name:")'
compile3 = compile(code3,'','single')
name #執行前name變量不存在

#
Traceback (most recent call last):
  File "D:\pystudy\fullstack\作業練習\腳本.py", line 3, in <module>
    name #執行前name變量不存在
NameError: name 'name' is not defined
           
>>> exec(compile3) #執行時顯示互動指令,提示輸入
please input your name:'psych'
>>> name #執行後name變量有值
"'psych'"
           

Ⅱ 輸入輸出相關:

input() 輸入

s = input("請輸入内容 : ")  #輸入的内容指派給s變量
print(s)  #輸入什麼列印什麼。資料類型是str
           

print() 輸出

print源碼剖析

def print(self, *args, sep=' ', end='\n', file=None): # known special case of print
    """
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    file:  預設是輸出到螢幕,如果設定為檔案句柄,輸出到檔案
    sep:   列印多個值之間的分隔符,預設為空格
    end:   每一次列印的結尾,預設為換行符
    flush: 立即把内容輸出到流檔案,不作緩存
    """
           

file關鍵字的說明

f = open('tmp_file','w')
print(123,456,sep=',',file = f,flush=True)
           

Ⅲ 資料類型相關:

type(o) 傳回變量o的資料類型

Ⅳ 記憶體相關:

id(o) o是參數,傳回一個變量的記憶體位址

hash(o) o是參數,傳回一個可hash變量的哈希值,不可hash的變量被hash之後會報錯。

t = (1,2,3)
l = [1,2,3]
print(hash(t))  #可hash
print(hash(l))  #會報錯

'''
結果:
TypeError: unhashable type: 'list'
'''
           

hash函數會根據一個内部的算法對目前可hash變量進行處理,傳回一個int數字。

注:每一次執行程式,内容相同的變量hash值在這一次執行過程中不會發生改變。

Ⅴ 檔案操作相關

open() 打開一個檔案,傳回一個檔案操作符(檔案句柄)

操作檔案的模式有r,w,a,r+,w+,a+ 共6種,每一種方式都可以用二進制的形式操作(rb,wb,ab,rb+,wb+,ab+)

可以用encoding指定編碼.

Ⅵ 子產品操作相關

__import__導入一個子產品

導入子產品:

import time
           

__import __:

os = __import__('os')
print(os.path.abspath('.'))
           

Ⅶ 幫助方法

在控制台執行help()進入幫助模式。可以随意輸入變量或者變量的類型。輸入q退出

或者直接執行help(o),o是參數,檢視和變量o有關的操作。。。

Ⅷ 調用相關

callable(o),o是參數,看這個變量是不是可調用。

如果o是一個函數名,就會傳回True

def func():pass
print(callable(func))  #參數是函數名,可調用,傳回True
print(callable(123))   #參數是數字,不可調用,傳回False
           

Ⅸ 檢視參數所屬類型的所有内置方法

dir() 預設檢視全局空間内的屬性,也接受一個參數,檢視這個參數内的方法或變量

print(dir(list))  #檢視清單的内置方法
print(dir(int))  #檢視整數的内置方法
           

3 數字相關

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

數字——資料類型相關:bool,int,float,complex

數字——進制轉換相關:bin,oct,hex

數字——數學運算:abs,divmod,min,max,sum,round,pow

4 資料結構相關

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

序列——清單和元組相關的:list和tuple

序列——字元串相關的:str,format,bytes,bytearry,memoryview,ord,chr,ascii,repr

bytearray:

ret = bytearray('psych',encoding='utf-8')
print(id(ret))
print(ret[0])
ret[0] = 65
print(ret)
print(id(ret))

# 2074162046256
# 97
# bytearray(b'Psych')
# 2074162046256
           

memoryview:

ret = memoryview(bytes('你好',encoding='utf-8'))
print(len(ret))
print(bytes(ret[:3]).decode('utf-8'))
print(bytes(ret[3:]).decode('utf-8'))

# 6
# 你
# 好

           

format:

  1. 函數功能将一個數值進行格式化顯示。
  2. 如果參數format_spec未提供,則和調用str(value)效果相同,轉換成字元串格式化。
>>> format(3.1415936)
'3.1415936'
>>> str(3.1415926)
'3.1415926'
           
  1. 對于不同的類型,參數format_spec可提供的值都不一樣
#字元串可以提供的參數,指定對齊方式,<是左對齊, >是右對齊,^是居中對齊
print(format('test', '<20'))
print(format('test', '>20'))
print(format('test', '^20'))

#整形數值可以提供的參數有 'b' 'c' 'd' 'o' 'x' 'X' 'n' None
>>> format(3,'b') #轉換成二進制
'11'
>>> format(97,'c') #轉換unicode成字元
'a'
>>> format(11,'d') #轉換成10進制
'11'
>>> format(11,'o') #轉換成8進制
'13'
>>> format(11,'x') #轉換成16進制 小寫字母表示
'b'
>>> format(11,'X') #轉換成16進制 大寫字母表示
'B'
>>> format(11,'n') #和d一樣
'11'
>>> format(11) #預設和d一樣
'11'

#浮點數可以提供的參數有 'e' 'E' 'f' 'F' 'g' 'G' 'n' '%' None
>>> format(314159267,'e') #科學計數法,預設保留6位小數
'3.141593e+08'
>>> format(314159267,'0.2e') #科學計數法,指定保留2位小數
'3.14e+08'
>>> format(314159267,'0.2E') #科學計數法,指定保留2位小數,采用大寫E表示
'3.14E+08'
>>> format(314159267,'f') #小數點計數法,預設保留6位小數
'314159267.000000'
>>> format(3.14159267000,'f') #小數點計數法,預設保留6位小數
'3.141593'
>>> format(3.14159267000,'0.8f') #小數點計數法,指定保留8位小數
'3.14159267'
>>> format(3.14159267000,'0.10f') #小數點計數法,指定保留10位小數
'3.1415926700'
>>> format(3.14e+1000000,'F')  #小數點計數法,無窮大轉換成大小字母
'INF'

#g的格式化比較特殊,假設p為格式中指定的保留小數位數,先嘗試采用科學計數法格式化,得到幂指數exp,如果-4<=exp<p,則采用小數計數法,并保留p-1-exp位小數,否則按小數計數法計數,并按p-1保留小數位數
>>> format(0.00003141566,'.1g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留0位小數點
'3e-05'
>>> format(0.00003141566,'.2g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留1位小數點
'3.1e-05'
>>> format(0.00003141566,'.3g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留2位小數點
'3.14e-05'
>>> format(0.00003141566,'.3G') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留0位小數點,E使用大寫
'3.14E-05'
>>> format(3.1415926777,'.1g') #p=1,exp=0 ==》 -4<=exp<p成立,按小數計數法計數,保留0位小數點
'3'
>>> format(3.1415926777,'.2g') #p=1,exp=0 ==》 -4<=exp<p成立,按小數計數法計數,保留1位小數點
'3.1'
>>> format(3.1415926777,'.3g') #p=1,exp=0 ==》 -4<=exp<p成立,按小數計數法計數,保留2位小數點
'3.14'
>>> format(0.00003141566,'.1n') #和g相同
'3e-05'
>>> format(0.00003141566,'.3n') #和g相同
'3.14e-05'
>>> format(0.00003141566) #和g相同
'3.141566e-05'
           

序列:reversed,slice

reversed:

l = (1,2,23,213,5612,342,43)
print(l)
print(list(reversed(l)))

# (1, 2, 23, 213, 5612, 342, 43)
# [43, 342, 5612, 213, 23, 2, 1]
           

slice:

l = (1,2,23,213,5612,342,43)
sli = slice(1,5,2)
print(l[sli])

# (2, 213)
           

資料集合——字典和集合:dict,set,frozenset

資料集合:len,sorted,enumerate,all,any,zip,filter,map

filter:

filter()函數接收一個函數 f 和一個list,這個函數 f 的作用是對每個元素進行判斷,傳回 True或 False,filter()根據判斷結果自動過濾掉不符合條件的元素,傳回由符合條件元素組成的新list。

例如,要從一個list [1, 4, 6, 7, 9, 12, 17]中删除偶數,保留奇數,首先,要編寫一個判斷奇數的函數:

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

然後,利用filter()過濾掉偶數:

list(filter(is_odd, [1, 4, 6, 7, 9, 12, 17]))

# [1, 7, 9, 17]
           

利用filter(),可以完成很多有用的功能,例如,删除 None 或者空字元串:

def is_not_empty(s):
    return s and len(s.strip()) > 0
>>>list(filter(is_not_empty, ['test', None, '', 'str', '  ', 'END']))
           

結果:

注意: s.strip(rm) 删除 s 字元串中開頭、結尾處的 rm 序列的字元。

當rm為空時,預設删除空白符(包括’\n’, ‘\r’, ‘\t’, ’ '),如下:

>>> a = ' 123'
>>> a.strip()
'123'

>>> a = '\t\t123\r\n'
>>> a.strip()
'123'
           

map:

Python中的map函數應用于每一個可疊代的項,傳回的是一個結果list。如果有其他的可疊代參數傳進來,map函數則會把每一個參數都以相應的處理函數進行疊代處理。map()函數接收兩個參數,一個是函數,一個是序列,map将傳入的函數依次作用到序列的每個元素,并把結果作為新的list傳回。

有一個list, L = [1,2,3,4,5,6,7,8],我們要将f(x)=x^2作用于這個list上,那麼我們可以使用map函數處理。

>>> L = [1,2,3,4,] 
>>> def pow2(x): 
... return x*x 
... 
>>> list(map(pow2,L))
[1, 4, 9, 16] 
           

sorted:

對List、Dict進行排序,Python提供了兩個方法

對給定的List L進行排序:

  • 方法1.用List的成員函數sort進行排序,在本地進行排序,不傳回副本
  • 方法2.用built-in函數sorted進行排序(從2.4開始),傳回副本,原始輸入不變

參數說明:

  • iterable:是可疊代類型;
  • key:傳入一個函數名,函數的參數是可疊代類型中的每一項,根據函數的傳回值大小排序;
  • reverse:排序規則. reverse = True 降序 或者 reverse = False 升序,有預設值。
  • 傳回值:有序清單

例:

清單按照其中每一個值的絕對值排序

l1 = [1,3,5,-2,-4,-6]
l2 = sorted(l1,key=abs)
print(l1)
print(l2)

# [1, 3, 5, -2, -4, -6]
# [1, -2, 3, -4, 5, -6]
           

二、匿名函數

為了解決那些功能很簡單的需求而設計的一句話函數

有名函數:

def calc(n):
    return n**n
print(calc(10))
           

換成匿名函數:

calc = lambda n:n**n
print(calc(10))
           
Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

1 匿名函數格式的說明:

函數名 = lambda 參數 :傳回值

1.參數可以有多個,用逗号隔開

2.匿名函數不管邏輯多複雜,隻能寫一行,且邏輯執行結束後的内容就是傳回值

3.傳回值和正常的函數一樣可以是任意資料類型

2 有名函數與匿名函數的對比:

有名函數:循環使用,儲存了名字,通過名字就可以重複引用函數功能

匿名函數:一次性使用,随時随時定義

3 lambda與内置函數結合使用

字典的運算:最小值,最大值,排序
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}

疊代字典,取得是key,因而比較的是key的最大和最小值
>>> max(salaries)
'yuanhao'
>>> min(salaries)
'alex'

可以取values,來比較
>>> max(salaries.values())
>>> min(salaries.values())

但通常我們都是想取出,工資最高的那個人名,即比較的是salaries的值,得到的是鍵
>>> max(salaries,key=lambda k:salary[k])
'alex'
>>> min(salaries,key=lambda k:salary[k])
'yuanhao'



也可以通過zip的方式實作
salaries_and_names=zip(salaries.values(),salaries.keys())

先比較值,值相同則比較鍵
>>> max(salaries_and_names)
(100000000, 'alex')


salaries_and_names是疊代器,因而隻能通路一次
>>> min(salaries_and_names)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence



sorted(iterable,key=None,reverse=False)
           

三、遞歸函數

1 遞歸調用的定義

遞歸調用是函數嵌套調用的一種特殊形式,函數在調用時,直接或間接調用了自身,就是遞歸調用

直接調用本身:

def f1():
    print('from f1')
    f1()
f1()
           

間接調用本身:

def f1():
    print('from f1')
    f2()

def f2():
    print('from f2')
    f1()
f1()
           

調用函數會産生局部的名稱空間,占用記憶體,因為上述這種調用會無需調用本身,python解釋器的記憶體管理機制為了防止其無限制占用記憶體,對函數的遞歸調用做了最大的層級限制

可以修改遞歸最大深度;

import sys
sys.getrecursionlimit()
sys.setrecursionlimit(2000)

def f1(n):
    print('from f1',n)
    f1(n+1)
f1(1)
           

雖然可以設定,但是因為不是尾遞歸,仍然要儲存棧,記憶體大小一定,不可能無限遞歸,而且無限制地遞歸調用本身是毫無意義的,遞歸應該分為兩個明确的階段,回溯與遞推

2 遞歸調用的兩個階段:遞推,回溯

回溯就是從外向裡一層一層遞歸調用下去,回溯階段必須要有一個明确地結束條件,每進入下一次遞歸時,問題的規模都應該有所減少(否則,單純地重複調用自身是毫無意義的)

遞推就是從裡向外一層一層結束遞歸

3 python中的遞歸

python中的遞歸效率低且沒有尾遞歸優化

python中的遞歸效率低,需要在進入下一次遞歸時保留目前的狀态,在其他語言中可以有解決方法:尾遞歸優化,即在函數的最後一步(而非最後一行)調用自己,尾遞歸優化:http://egon09.blog.51cto.com/9161406/1842475

但是python又沒有尾遞歸,且對遞歸層級做了限制

遞歸的使用:

  1. 必須有一個明确的結束條件
  2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
  3. 遞歸效率不高,遞歸層次過多會導緻棧溢出(在計算機中,函數調用是通過棧(stack)這種資料結構實作的,每當進入一個函數調用,棧就會加一層棧幀,每當函數傳回,棧就會減一層棧幀。由于棧的大小不是無限的,是以,遞歸調用的次數過多,會導緻棧溢出)

例:遞歸函數實作三級菜單

menu = {
    '北京': {
        '海澱': {
            '五道口': {
                'soho': {},
                '網易': {},
                'google': {}
            },
            '中關村': {
                '愛奇藝': {},
                '汽車之家': {},
                'youku': {},
            },
            '上地': {
                '百度': {},
            },
        },
        '昌平': {
            '沙河': {
                '老男孩': {},
                '北航': {},
            },
            '天通苑': {},
            '回龍觀': {},
        },
        '朝陽': {},
        '東城': {},
    },
    '上海': {
        '闵行': {
            "人民廣場": {
                '炸雞店': {}
            }
        },
        '閘北': {
            '火車戰': {
                '攜程': {}
            }
        },
        '浦東': {},
    },
    '山東': {},
}
           
def threeLM(dic):
     while True:
         for k in dic:print(k)
         key = input('input>>').strip()
         if key == 'b' or key == 'q':return key
         elif key in dic.keys() and dic[key]:
             ret = threeLM(dic[key])
             if ret == 'q': return 'q'
 
threeLM(menu)
           

4 二分法

想從一個按照從小到大排列的數字清單中找到指定的數字,周遊的效率太低,用二分法(算法的一種,算法是解決問題的方法)可以極大低縮小問題規模

例如:

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

觀察這個清單,這是不是一個從小到大排序的有序清單?

如果這樣,假如要找的數比清單中間的數還大,是不是直接在清單的後半邊找就行了?

Python基礎—内置函數、匿名函數、遞歸函數一、内置函數二、匿名函數三、遞歸函數

這就是二分查找算法!

簡單版二分法:

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

def func(l,aim):
    mid = (len(l)-1)//2
    if l:
        if aim > l[mid]:
            func(l[mid+1:],aim)
        elif aim < l[mid]:
            func(l[:mid],aim)
        elif aim == l[mid]:
            print("bingo",mid)
    else:
        print('找不到')
func(l,66)
func(l,6)
           

更新版二分法:

def search(num,l,start=None,end=None):
    start = start if start else 0
    end = end if end is not None else len(l) - 1
    mid = (end - start)//2 + start
    if start > end:
        return None
    elif l[mid] > num :
        return search(num,l,start,mid-1)
    elif l[mid] < num:
        return search(num,l,mid+1,end)
    elif l[mid] == num:
        return mid