Python3之函數


 

函數目錄:



一、初識函數
1.內置函數
len()
s = 'felix'
len(s)

2.自定義函數
def my_len(): #自定義函數 聲明函數 函數名定義方法跟變量規則相同
i = 0
for k in s:
i += 1
print(i)

length = my_len()
print(length)

函數
定義了之后,可以在任何需要它的地方調用
沒有返回長度,只是單純的打印

返回的重要性
a,b
len(a) #內置函數
len(b)

def my_len(): #自定義函數
i = 0
for k in s:
i += 1
return i #返回值

length = my_len() #自定義的函數進行調研
print(length)

len()
1.不能變,只能計算s字符串的長度
2.只是輸出了結果

二、返回值
返回值的3種情況
(1)沒有返回值 —— 默認返回None
1.不寫return
2.只寫return:結束一個函數的繼續,代碼塊遇到return就結束后面的代碼
3.return None —— 不常用

(2)返回1個值
1.可以返回任何數據類型
2.只要返回就可以接收到
3.如果在一個程序中有多個return,那么只執行第一個

(3)返回多個值
用多個變量接收:有多少返回值就用多少變量接收
用一個變量接收: 得到的是一個元組
 實例:
def func():
    l = ['張老板','小黑']
    for i in l:
        print(i)
        if i=='小黑':
            return None
    print('='*10)
ret = func()
print(ret)

def func():
    return [1,2,3]
print(func())

def func():
    return {'k':'v'}
print(func())

def func2():
    return 1,2,3  #return 1,2,3

r= func2()
print(r)

a,b,c = 1,2,3
a = 1
b = 2
c = 3  python自動進行解構
a,b = [1,2]
a = 1
b = 2

三、參數
1.什么叫參數?
參數的語法
形參和實參的概念
函數與函數的代碼不會相互影響

def my_len(s):  # 自定義函數只需要0個參數,接收參數,形式參數,形參
    i = 0
    for k in s:
        i += 1
    return i  # 返回值


ret = my_len('A')  # 傳遞參數:傳參,實際參數,實參
ret = my_len([1, 2, 3, 4, 5])  # 傳遞參數:傳參
ret = my_len({'k1': 'v1', 'k2': 'v2'})
print(ret)


def f2(l1):
    f1(l1)
    for i in l1:
        print(i)


def f1(l1):
    for i in l1:
        print(i)


f2([1, 2, 3, 4])

2.參數
(1)沒有參數
定義函數和調用函數時括號里都不寫內容
(2)有一個參數
傳什么就是什么
(3)有多個參數
位置參數

exp: 傳遞2個參數


def my_sum(a, b):
    print(a, b)
    res = a + b  # result
    return res


ret = my_sum(1, 2)
print(ret)

  

    3.站在實參的角度上:
按照位置傳參:位置參數
按照關鍵字傳參:關鍵字參數
混着用可以:但是 必須先按照位置傳參,再按照關鍵字傳參數
不能給同一個變量傳多個值

4.站在形參的角度上
位置參數:必須傳,且有幾個參數就傳幾個值
默認參數: 可以不傳,如果不傳就是用默認的參數,如果傳了就用傳的

exp:

def classmate(name, sex='男'):
    print('%s : %s' % (name, sex))

classmate('A')
classmate('B')
classmate('C')
classmate('D', '女')

  

    5.只有調用函數的時候
按照位置傳 : 直接寫參數的值
按照關鍵字: 關鍵字 = 值

6.定義函數的時候:
位置參數 : 直接定義參數
默認參數,關鍵字參數 -> 參數名 = '默認的值'
動態參數 : 可以接受任意多個參數
參數名之前加*,習慣參數名args, 元組
參數名之前加**,習慣參數名kwargs 字典
順序:必須先定義位置參數,*args,默認參數,**kwargs

def classmate(name, sex):
    print('%s : %s' % (name, sex))


classmate('二狗哥', '男')
classmate(sex='男', name='二狗哥')


def classmate(name, sex='男'):
    print('%s : %s' % (name, sex))


classmate('二狗哥')
classmate('小花', sex='女')


def sum(*args):
    n = 0
    for i in args:
        n += i
    return n

print(sum(1, 2))
print(sum(1, 2, 3))
print(sum(1, 2, 3, 4))


def func(**kwargs):
    print(kwargs)


func(a=1, b=2, c=3)
func(a=1, b=2)
func(a=1)

  

    7.動態參數有兩種:可以接受任意個參數
*args : 接收的是按照位置傳參的值,組織成一個元組
**kwargs: 接受的是按照關鍵字傳參的值,組織成一個字典
args必須在kwargs之前

def func(*args, default=1, **kwargs):
    print(args, kwargs)

func(1, 2, 3, 4, 5, default=2, a='aaaa', b='bbbb', )

  

    8.動態參數的另一種傳參方式
def func(*args):  # 站在形參的角度上,給變量加上*,就是組合所有傳來的值。  封裝
    print(args)


func(1, 2, 3, 4, 5)
l = [1, 2, 3, 4, 5]
func(*l)  # 站在實參的角度上,給一個序列加上*,就是將這個序列按照順序打散  解構


def func(**kwargs):
    print(kwargs)


func(a=1, b=2)
d = {'a': 1, 'b': 2}  # 定義一個字典d
func(**d)

  

    9.函數的注釋
def func():
'''
這個函數實現了什么功能
參數1:
參數2:
:return: 是字符串或者列表的長度
'''
pass

  10.默認參數的陷阱

如果默認參數的值是一個可變的數據類型,那么每一次調用函數的時候,
如果不傳值就公用這個數據類型的資源

def func( 1 = [] ):
    l.append(1)
    print(l)

func()
func()
func()
func()
func()

執行后:

[1]
[1, 1]
[1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1, 1]


def func(k,l = {}):
    #l.append(1)
    l[k] = 'v'
    print(l)

func(1)
func(2)
func(3)
func(4)
func(5)

執行結果:
{1: 'v'}
{1: 'v', 2: 'v'}
{1: 'v', 2: 'v', 3: 'v'}
{1: 'v', 2: 'v', 3: 'v', 4: 'v'}
{1: 'v', 2: 'v', 3: 'v', 4: 'v', 5: 'v'}

 

四、命名空間和作用域

  1.三種命名空間   

  (1)內置命名空間---‘Python解釋器’   可以使用全局、內置命名空間的名字
就是python解釋器一啟動就可以使用的名字存儲在內置命名空間中
內置的名字在啟動解釋器的時候被加載進內存里

  (2)全局命名空間---‘我們寫的代碼單不是函數中的代碼’ 可以使用內置命名空間的名字 但是不能用局部中的名字
 是在程序從上到下被執行的過程中一次加載進內存的
 放置了我們設置的所有變量名和函數名

  (3)局部命名空間---‘函數’ 不能使用局部和全局的名字
 就是函數內部定義的名字
 當調用函數的時候 才產生這個名稱空間 隨着函數執行的結束 這個命名空間就消失了

  三種命名空間之間的加載與取值順序:

  加載順序:內置命名空間(程序運行前加載)->全局命名空間(程序運行中:從上到下加載)->局部命名空間(程序運行中:調用時才加載)

exp1:

def input():
    print('in input now')

def func():
    input()

func()
執行結果:
in input
now

exp2:

def input():
    print('in input now')

def func():
    input = 1
    print(input)

func()
執行結果:
1

注意:func --> 函數的內存地址
        函數名() 函數的調用
        函數的內存地址()  函數的調用
   
注意:
  • 在正常情況,直接使用內置的名字;當我們在全局定義了和內置名字空間中同名的名字是,會使用全局的名字
  • 當我自己有名字的時候,不去找我的上級要了;如果自己沒有 就找上一級要,上一級沒有再找上一級,如果內置的名字空間都沒有 就報錯
  • 多個函數應該擁有多個獨立的局部名字空間,不互相共享

  2.兩種作用域

 

1.全局作用域    作用在全局    內置和全局名字空間的名字屬於全局作用域
   查看全局作用域方法:
     print(globals())

2.局部作用域    作用在局部    函數(局部名字空間的名字屬於局部作用域)
   查看局部作用域方法:
   print(locals())


exp:

a = 1
def func():
    a += 1

func()
print(a)
執行結果:
1


a = 1
b = 2
def func():
    x = 'aaa'
    y = 'bbb'
    print(locals())

func()
執行結果:
{'x': 'aaa', 'y': 'bbb'}

globals()
永遠打印全局的名字
locals()
輸出什么根據locals所在的位置確定

對於不可變數據類型,在局部可以查看全局作用域的變量
但是不能直接修改
如果想要修改,需要在程序的一開始增加
global 聲明
如果在一個局部(函數)內聲明了一個global變量,那么這個變量在局部的所有操作將對全局的變量有效

global關鍵字

a = 10
def func():
    global a
    a = 20

print(a)
func()
print(a

  

  3.函數的嵌套和作用域鏈

(1)函數的嵌套定義
def max(a,b):
    return a if a > b else b

def the_max(x,y,z)
    c = max(x,y)

the_max(111,222,333)

(2)內部函數可以使用外部函數的變量
exp1:

def outer():
    a = 1

    def inner():
        print(a)
        print('inner')

    inner()

outer()

exp2:

def outer():
    a = 1

    def inner():
        print(a)
        print('inner')
        
        def inner2():
            print('inner2')
            
        inner2()
        
    inner()


outer()

  

    nonlocal關鍵字

# 1.外部必須有這個變量
# 2.在內部函數聲明nonlocal變量之前不能再出現同名變量
# 3.內部修改這個變量如果想在外部有這個變量的第一層函數中生效
exp3:

a = 1
def outer():
    a = 2
    def inner():
        a = 3
        def inner2():
            nonlocal a #聲明了一個上面第一層局部變量
            a += 1     #不可改變數據類型的修改
        inner2()
        print('###a###',a)
    inner()
    print('***a***', a)
outer()
print('全局',a)
執行結果
###a### 4
***a*** 2
全局 1

def func():
    print(123)

func() #函數名就是內存地址
func2 = func #函數名可以賦值
func2()

l = [func,func2] #函數名可以作為容器類型的元素
for i in l:
    i()

def func():
    print(123)

def test(f):
    f()
    return f         #函數名可以作為函數的返回值

a = test(func) #函數名可以作為函數的參數

  

五、閉包函數和裝飾器

  1.閉包函數

內部函數包含對外部作用域而非全劇作用域名字的引用,該內部函數稱為閉包函數
#函數內部定義的函數稱為內部函數

def outer():
    a = 1
    def inner():
        print(a)
    inner()
outer()

   def outer():
    a = 1
    def inner():
        print(a)
    return inner
outer()

判斷閉包函數的方法__closure__

#輸出的__closure__有cell元素 :是閉包函數
def func():
    name = 'felix'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f = func()
f()

#輸出的__closure__為None :不是閉包函數
name = 'alina'
def func2():
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f2 = func2()
f2()

  

#閉包嵌套

def wrapper():
    money = 1000
    def func():
        name = 'felix'
        def inner():
            print(name,money)
        return inner
    return func

f = wrapper()
i = f()
i()

 

#應用

from urllib.request import urlopen

def index():
    url = "http://www.xiaohua100.cn/index.html"
    def get():
        return urlopen(url).read()
    return get

xiaohua = index()
content = xiaohua()
print(content)

  

  2.裝飾器

  (1)裝飾器的本質:就是一個閉包函數,是在不修改主體代碼(函數)的情況下,需要在執行之前或者執行之后實現的功能。

    (2)形成過程 

    

#裝飾器——簡單版1
import time

def func1():
    print('in func1')

def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

func1 = timer(func1)
func1()

#裝飾器——語法糖
import time
def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

@timer   #==> func1 = timer(func1)
def func1():
    print('in func1')


func1()

#裝飾器——帶參數的裝飾器
import time
def timmer(f):
    def inner(*args,**kwargs):
        start =time.time()
        ret = f(*args,**kwargs)
        end = time.time()
        print(end -start)
        return ret
    return inner

@timmer  #語法糖 等同於 func = timmer(func)
def func(L):
    time.sleep(1)
    dic = {'num':0,'alpha':0,'space':0,'other':0}
    for i in L:
        if i.isdigit():
            dic['num'] += 1
        elif i.isalpha():
            dic['alpha'] += 1
        elif i.isspace():
            dic['space'] += 1
        else:
            dic['other'] += 1
    return dic

s = input('>>>')
print(func(s))

#裝飾器——成功hold住所有函數傳參
import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func1 = timer(func1)
def func1(a,b):
    print('in func1')

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))


#裝飾器——帶返回值的裝飾器

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func2('aaaaaa')
print(func2('aaaaaa'))

#查看函數信息的一些方法

def index():
    '''這是一個主頁信息'''
    print('from index')

print(index.__doc__)    #查看函數注釋的方法
print(index.__name__)   #查看函數名的方法

#裝飾器的固定模式

def wrapper(fn):   #裝飾器函數,fn為被裝飾的函數
    def inner(*args,**kwargs):
        #before  #執行前的裝飾功能
        ret = fn(*args,**kwargs)  #被裝飾的函數
        #after   #執行后的裝飾功能
        return ret
    return inner  #返回增強版的fn (函數)
@wrapper  #語法糖  @裝飾器函數名

 

#多個裝飾器裝飾一個函數
def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')
        ret = func()
        print('wrapper1 ,after func')
        return ret
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        ret = func()
        print('wrapper2 ,after func')
        return ret
    return inner2

def wrapper3(func):
    def inner3():
        print('wrapper3 ,before func')
        ret = func()
        print('wrapper3 ,after func')
        return ret
    return inner3

@wrapper3
@wrapper2
@wrapper1
def f():
    print('in f')
    return '哈哈哈'

print(f())
執行結果:
wrapper3 ,before func
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
wrapper3 ,after func
哈哈哈

  (3)裝飾器進階

  實例1.查看原函數的名稱

def wrapper(func):  #執行順序 1
    def inner(*args,**kdargs):  #執行順序 4
        print('在被執行函數之前增加的功能')  #執行順序 8
        ret = func(*args,**kdargs)     #func(*args,**kdargs)執行順序 9   #ret執行順序 12
        print('在被執行函數之后增加的功能')  #執行順序 13
        return ret  #執行順序 14
    return inner  #執行順序 5    inner執行順序 11

@wwapper  #執行順序 2  #holidy = wrapper(holidy)  #wrapper(holidy)執行順序 3    #holidy執行順序 6
def holiday(day):
    print('全體放假%s天'%day)
    return '好開心'   #執行順序 10

ret = holiday(3)   #holiday(3)執行順序 7   #ret執行順序 15
print(ret)   執行順序 16

取函數中函數的名字-字符串格式

print(fanc.__name__) #查看字符串格式的函數名字   兩個下划線 __

結合上面裝飾器 打印結果為 inner  在全局作用域下已找不到func函數,已經傳給inner了

print(fanc.__doc__)  #document   查看函數的注釋


通過以下方式 向裝飾器里的inner函數增加裝飾器可得到原來holiday的字符串函數名字


from functools import wraps
def wrapper(func):
    @wraps(func)
    def inner(*args,**kdargs):
        print('在被執行函數之前增加的功能')
        ret = func(*args,**kdargs)
        print('在被執行函數之后增加的功能')
        return ret
    return inner

@wrapper   #holidy = wrapper(holidy)
def holiday(day):
    '''這是一個放假通知!'''
    print('全體放假%s天'%day)
    return '好開心'
print(holiday(3))
# ret = holiday(3)
# print(ret)

print(holiday.__name__)
print(holiday.__doc__)

執行結果:

在被執行函數之前增加的功能
全體放假3天
在被執行函數之后增加的功能
好開心
holiday
這是一個放假通知!

  實例2:給N個函數加同一個裝飾器,如何實現裝飾器的開和關?

#帶參數的裝飾器
#500個函數
import time
FLAGE = False  #通過設置標志的True 或 False 實現裝飾器的開和關
def timmer_out(flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func(*args,**kwargs)
                end = time.time()
                print(end-start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return timmer
# timmer = timmer_out(FLAGE)
@timmer_out(FLAGE)    #test1 = timmer(test1)
def test1():
    time.sleep(0.1)
    print('test1test1test1')

@timmer_out(FLAGE)
def test2():
    time.sleep(0.1)
    print('test2test2test2')

test1()
test2()

執行結果:
test1test1test1
0.10920047760009766
test2test2test2
0.10920000076293945

  實例3:計算10萬以內的所有質數個數

import time
import datetime

flag = True
# flag = False
def timmer_out(flag):
    def timmer(f):
        def inner(*args, **kwargs):
            if flag:
                # start =time.time()
                start = datetime.datetime.now()
                ret = f(*args, **kwargs)
                # end = time.time()
                end = datetime.datetime.now()
                delta = end - start
                #print( end -start )
                print(delta.total_seconds())
                return ret
            else:
                ret = f(*args, **kwargs)
                return ret
        return inner
    return timmer

@timmer_out(flag)  # 語法糖 等同於 func = timmer(func)
def prime_num1(n):
    prime_number = [2]
    count = 1
    for i in range(3, n, 2):
        for j in prime_number:
            if i % j == 0:
                break
        else:
            prime_number.append(i)
            count += 1
    # print('質數數量為:',count)
    # print(prime_number)
    return count
print(prime_num1(100000))

@timmer_out(flag)
def prime_num2(n):
    count = 2
    for i in range(4, n):  # 排除偶數,偶數都是2的倍數
        if i % 6 != 1 and i % 6 != 5:
            continue
        else:
            for j in range(5, int(i ** 0.5) + 1, 2):  # 奇數除以奇數可以除盡,但奇數除以偶數不能除盡,又一次排除一部分偶數,加快程序速度
                if not i % j:
                    break
            else:
                count += 1
            # print(count,i,end='\n')
    return count
print(prime_num2(100000))

@timmer_out(flag)
def prime_num3(n):
    count = 1
    # print(1,2)  2也是質數
    for i in range(3, n + 1, 2):  # 排除偶數,偶數都是2的倍數
        if i > 10 and i & 10 == 5:
            continue
        for j in range(3, int(i ** 0.5) + 1, 2):  # 奇數除以奇數可以除盡,但奇數除以偶數不能除盡,又一次排除一部分偶數,加快程序速度
            if i % j == 0:
                break
        else:
            count += 1
            # print(count,i,end='\n')
    return count
print(prime_num3(100000))

執行結果:
4.447008
9592
0.1248
9592
0.171601
9592

  

    2.原則

  

  (1)對擴展是開放的

    為什么要對擴展開放呢?

    我們說,任何一個程序,不可能在設計之初就已經想好了所有的功能並且未來不做任何更新和修改。所以我們必須允許代碼擴展、添加新功能。

  (2)對修改是封閉的

    為什么要對修改封閉呢?

    就像我們剛剛提到的,因為我們寫的一個函數,很有可能已經交付給其他人使用了,如果這個時候我們對其進行了修改,很有可能影響其他已經在使用該函數的用戶。

裝飾器完美的遵循了這個開放封閉原則。

 

六、生成器和迭代器

  1.可迭代協議和迭代器協議:

   可迭代協議:可迭代協議的定義非常簡單,就是內部實現了__iter__方法。

print(dir([1,2]))
print(dir((2,3)))
print(dir({1:2}))
print(dir({1,2}))

執行結果:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']

  可以被for循環的都是可迭代的,要想可迭代,內部必須有一個__iter__方法。

 

   迭代器協議:迭代器協議 —— 內部含有__next__和__iter__方法的就是迭代器

'''
dir([1,2].__iter__())是列表迭代器中實現的所有方法,dir([1,2])是列表中實現的所有方法,都是以列表的形式返回給我們的,為了看的更清楚,我們分別把他們轉換成集合,
然后取差集。
'''
#print(dir([1,2].__iter__()))
#print(dir([1,2]))
print(set(dir([1,2].__iter__()))-set(dir([1,2])))

結果:
{'__length_hint__', '__next__', '__setstate__'}

  

iter_l = [1,2,3,4,5,6].__iter__()
#獲取迭代器中元素的長度
print(iter_l.__length_hint__())
#根據索引值指定從哪里開始迭代
print('*',iter_l.__setstate__(4))
#一個一個的取值
print('**',iter_l.__next__())
print('***',iter_l.__next__())
執行結果:
6
* None
** 5
*** 6

  

在for循環中,就是在內部調用了__next__方法才能取到一個一個的值。

l = [1,2,3,4]
l_iter = l.__iter__()
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)

執行結果:
1
2
3
4
StopIteration

  最后一個代碼會報錯,如果我們一直取next取到迭代器里已經沒有元素了,就會拋出一個異常StopIteration,告訴我們,列表中已經沒有有效的元素了。

  這個時候,我們就要使用異常處理機制來把這個異常處理掉。

l = [1,2,3,4]
l_iter = l.__iter__()
while True:
    try:
        item = l_iter.__next__()
        print(item)
    except StopIteration:
        break

  

  2.生成器:本質是迭代器

生成器
生成器的表現形式:
生成器函數
生成器表達式

生成器函數:
還有yield關鍵字的函數就是生成器函數
特點:
調用函數之后函數不執行,返回一個生成器
每次調用__next__方法的時候會取到一個值
直到取萬最后一個,在執行__next__會報錯
迭代器(所以自帶了__iter__方法和__next__方法,不需要我們去實現)
# 生產200萬個娃哈哈
# def generator():
#     for i in range(2000001):
#         yield  '娃哈哈%s' %i  #生成器函數 關鍵字 yield
# g = generator()
#
# for i in g:
#     print(i)

#只取50個
def generator():
    for i in range(2000001):
        yield  '娃哈哈%s' %i  #生成器函數 關鍵字 yield
g = generator()

count = 0
for i in g:
    count += 1
    print(i)
    if count > 50:
        break

#繼續取50個
for i in g:
    count += 1
    print(i)
    if count > 100:
        break

  

  3.生成器進階

def genrator():
    print(123)
    yield 1
    print(456)
    yield 2
    print(789)

g = genrator()
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)

執行結果:
123
1
456
2
789
Traceback (most recent call last):
  File "D:/Python_learn/Study/9.26/生成器進階.py", line 14, in <module>
    ret = g.__next__()
StopIteration


exp2:

def genrator():
    print(123)
    yield 1
    print(456)
    yield 2


g = genrator()
ret = g.__next__()
print(ret)
ret = g.send(None)  #send效果和 next一樣
print(ret)

執行結果:
123
1
456
2

exp3:

def genrator():
    print(123)
    content = yield 1
    print('#####',content)
    print(456)
    yield 2


g = genrator()
ret = g.__next__()
print(ret)
ret = g.send('hello,python')
print(ret)

執行結果:
123
1
##### hello,python
456
2

  

send的獲取下一個值的使用效果和next基本一致,只是在獲取下一個值的時候,
給上一個yield的位置傳遞一個數據

使用send的注意事項:
1.第一次使用生成器的時候,是使用next獲取下一個值
2.最后一個yield不能接受外部的值

實例:計算動態平均值
#計算動態平均數

普通寫法:
def avg():
    avg = sum = count = 0
    while True:
        s = int(input('>>>'))
        count += 1
        sum += s
        avg = sum / count
        print(avg)
print(avg())


生成器寫法:
def average():
    count = 0
    sum = 0
    avg = 0
    while True:
        num = yield avg
        count += 1
        sum = sum + num
        avg = sum / count

g = average()
g.__next__()
print(g.send(10))
print(g.send(20))
print(g.send(30))
print(g.send(30))

  

預激生成器的裝飾器的例子
#省略執行時的第一步g.__next__()

def wrapper(f):
    def inner(*args,**kdargs):
        g = f(*args,**kdargs)
        g.__next__()
        return g
    return inner

@wrapper
def average():
    count = 0
    sum = 0
    avg = 0
    while True:
        num = yield avg
        count += 1
        sum = sum + num
        avg = sum / count

g = average()
print(g.send(10))
print(g.send(20))
print(g.send(30))
print(g.send(30))

 

七、遞歸函數

遞歸函數
了解什么是遞歸:在函數中調用自己
exp:
    def wuliao():
        print('從前有座山,山里有座廟')
        wuliao()
    wuliao()

    RecursionError: maximum recursion depth exceeded while calling a Python object
    #遞歸的錯誤,超過了遞歸的最大深度,最大遞歸深度默認是997/998 是python從內存角度做的限制

 

導入sys模塊,修改遞歸函數限制的次數,sys.setrecursionlimit(n)
但是遞歸的次數還是根據電腦的配置而定 python就執行多少次。如果遞歸次數太多,就不太適合用
遞歸函數來解決問題
    exp:
    import sys
    sys.setrecursionlimit(1000000)
    n = 0
    def story():
        global n
        n += 1
        print('從前有座山,山里有座廟')
        print(n)
        story()
    story()
    執行:
    3924
    從前有座山,山里有座廟
    3925

  

遞歸函數的特點:
缺點:太占內存 優點:會讓代碼變簡單
# A 多大       n = 1   age(1) = age(2)+2 = age(n+1) + 2
# A比B大兩歲
# B多大?      n = 2   age(2) = age(3) + 2 = age(n+1) +2
# B比C大兩歲
# C多大       n = 3   age(3) = age(4) + 2 = age(n+1) +2
# C比D大兩歲
# D多大?
# D今年40了      n = 4   age(4) = 40

# n = 4 age(4) = 40
# n <4  age(n) = age(n+1) +2

def age(n):
    if n == 4:
        return 40
    elif n >0 and n < 4:
        age(n+1) + 2
#
print(age(4))

# # 教你看遞歸

def age(1):
    if 1 == 4:
        return 40
    elif 1 >0 and n < 4:
        age(1+1) + 2  #age(2)+2 = 46


def age(2):
    if n == 4:
        return 40
    elif 2 >0 and n < 4:
        age(2+1) + 2  #age(3)+2 = 42 + 2 = 44

def age(3):
    if n == 4:
        return 40
    elif n >0 and n < 4:
        age(3+1) + 2  #age(4)+2 = 42


 def age(4):
    if n == 4:
        return 40
    elif n >0 and n < 4:
        age(n+1) + 2

  實例:利用二分查找法(折半思想)查找某個數

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 find(L,target,start=0,end=None):
    end = len(L) if end is None else end
    mid_index = ((end - start) // 2 )+ start
    if start <= end:
        if L[mid_index] < target:
            return find(L,target,start=mid_index+1,end=end)
        elif L[mid_index] > target:
            return find(L,target,start=start,end=mid_index-1)
        elif L[mid_index] == target:
            return L[mid_index],L.index(target)
    else:
        return '查找的值不存在'

ret = find(L,69)  #查找69所在的索引
print(ret)
執行結果:
(69, 19)

  

八、推導式

1、生成器表達式 (i for i in range(10))
    返回一個生成器
 
    exp1:
    g = (i for i in range(10))
    print(g)
    執行結果:
    <generator object <genexpr> at 0x00000000020A4F48>
 
    for i in g:
        print(i)
 
    生成器表達式和列表推導式區別:
    1.括號不一樣,生成器表達式為括號(),列表推導式為中括號[]
    2.返回的值不一樣,生成器表達式返回 一個生成器 生成器節省內存 列表表達式 返回列表所有結果,
 
 
    老母雞 = ('雞蛋%s'%i for i in range(10) )
    print(老母雞)
    for 雞蛋 in 老母雞:
        print(雞蛋)
 
    10以內的數字的平方
    square = ( i**2 for i in range(10))
    for num in square:
        print(num)
 
 
2、列表推導式  [i for i in range(10)]
    [每一個元素或者是和元素相關的操作 for i in 可迭代數據]
 
    [ 滿足條件的元素相關的操作 for 元素 in 可迭代數據類型 if 元素相關的條件] 篩選元素
 
    egg_list = []
    for i in range(10):
        egg_list.append('雞蛋%s'%i)
    print(egg_list)
 
    執行結果:
    ['雞蛋0', '雞蛋1', '雞蛋2', '雞蛋3', '雞蛋4', '雞蛋5', '雞蛋6', '雞蛋7', '雞蛋8', '雞蛋9']
 
    列表推導式
    egg_list = [ '雞蛋%s'%i for i in range(10) ]
    print(egg_list)
 
    執行結果:
    ['雞蛋0', '雞蛋1', '雞蛋2', '雞蛋3', '雞蛋4', '雞蛋5', '雞蛋6', '雞蛋7', '雞蛋8', '雞蛋9']
 
    列表推導式:[ i for i in range(10) ]
 
    exp:找到嵌套列表中名字含有兩個‘e’的所有名字
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
 
    print([name for name_lst in names for name in name_lst if name.count('e') == 2])
    執行結果:
    ['Jefferson', 'Wesley', 'Steven', 'Jennifer']
 
 
 
 
    exp:
    30以內所有能被3整除的數
    [i for i in range(1,30) if i % 3 == 0]
    g = ( i for i in range(1,30) if i % 3 == 0)
    for i in g:
        print(i)
 
3、字典推導式
 
    例一:將一個字典的key和value對調
 
 
    mcase = {'a': 10, 'b': 34}
    mcase_frequency = {mcase[k]: k for k in mcase}
    print(mcase_frequency)
 
    {10: 'a', 34: 'b'}
 
    exp2:合並大小寫對應的value值,將k統一成小寫
    mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
    mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
    print(mcase_frequency)
    {'a': 17, 'b': 34, 'z': 3}
 
4、集合推導式
 
    squared = {x**2 for x in [1, -1, 2]}
    print(squared)
 
    {1, 4}

  

九、內置函數

 

內置函數
一、內置函數定義及總數
    python里的內置函數。截止到python版本3.6.2,現在python一共為我們提供了68個內置函數。
 
            Built-in Functions
    abs()       dict()  help()  min()   setattr()
    all()       dir()   hex()   next()  slice()
    any()       divmod()    id()    object()    sorted()
    ascii()     enumerate() input() oct()   staticmethod()
    bin()       eval()  int()   open()  str()
    bool()      exec()  isinstance()    ord()   sum()
    bytearray() filter()    issubclass()    pow()   super()
    bytes()     float() iter()  print() tuple()
    callable()  format()    len()   property()  type()
    chr()       frozenset() list()  range() vars()
    classmethod()   getattr()   locals()    repr()  zip()
    compile()   globals()   map()   reversed()  __import__()
    complex()   hasattr()   max()   round()
    delattr()   hash()  memoryview()    set()
 
二、分類
 
(1)作用域相關
 
    1.locals()    #返回本地作用域中的所有名字  函數會以字典類型返回當前位置的全部局部變量。
 
    2.globals()   #返回全局作用域中的所有名字  函數會以字典類型返回當前位置的全部全局變量。
 
    與local、global不同
    local 變量  #聲明變量作用域
    global 變量 #聲明變量作用域
 
(2)迭代器
 
    1.next(iterator[, default])  返回迭代器的下一個項目
        迭代器.__next__()  效果都一樣,實際執行迭代器.__next__()
 
    2.iter(可迭代的) 函數用來生成迭代器。
        可迭代的.__iter__()
 
    3.range(start, stop[, step]) 函數可創建一個整數列表,一般用在 for 循環中。
        是一個可迭代的,不是一個迭代器
        range(10),range(1,10),range(1,10,2)
 
        print(dir(range(10)) )
        print( '__next__' in dir(range(10)) )   #False
        print( '__next__' in dir(iter(range(10))) )    #False  將可迭代的轉化成迭代器
 
(3)其他:
 
    1.dir() 不帶參數時,返回當前范圍內的變量、方法和定義的類型列表;帶參數時,返回參數的屬性、方法列表。
            如果參數包含方法__dir__(),該方法將被調用。如果參數不包含__dir__(),該方法將最大限度地收集參數信息。
        print(dir(1))
 
    2.callable()  用於檢查一個對象是否是可調用的。如果返回True,object仍然可能調用失敗;但如果返回False,調用對象ojbect絕對不會成功。
                對於函數, 方法, lambda 函式, 類, 以及實現了 __call__ 方法的類實例, 它都返回 True。
        print(callable('alina')) -> False
 
        def func():pass
        print(callable(func))    ->   True
 
    3.help()  用於查看函數或模塊用途的詳細說明。
        help(list)
 
    4.import 模塊名稱    調用__import__()  函數
        __import__()  一般不用
        # import datetime
        test_time = __import__('datetime')
        print(test_time.datetime.now())
            2018-09-27 14:28:46.529354
 
    5.open() 打開文件
 
    6.id() 查看內存地址
 
    7.hash()
        print(hash(1234))
            1234
        print(hash('felix'))
            6020047598959426572
        字典的尋址方式
 
    某個方法屬於某個數據類型的變量,就用 .調用
    如果某個方法不依賴於任何數據類型,就直接調用 ----內置函數 和 自定義函數
 
    8.input()  輸入,字符串接受
 
    9.print()  輸出
 
        end=  指定輸出的結束符
            print('test',end='\t')
 
        sep=  指定輸出的分隔符
           print('test',sep='|')
 
        file=  指定輸出位置文件   默認輸出到屏幕
            with open('file','w',encoding='utf-8') as f:
                print('測試print函數輸出位置',file=f)
        flush:立即把內容輸出到流文件,不作緩存
 
 
        #打印進度條
        import time
        for i in range(0,100000,2):
             time.sleep(0.1)
             char_num = i//2      #打印多少個'*'
             per_str = '\r%s%% : %s\n' % (i, '*' * char_num) if i == 100 else '\r%s%% : %s'%(i,'*'*char_num)
             print(per_str,end='', flush=True)
        #小越越  : \r 可以把光標移動到行首但不換行
        打印進度條模塊  progress Bar
 
    10.exec()
    11.eval() 用來執行一個字符串表達式,並返回表達式的值。
        exec和eval都可以執行 字符串類型的代碼
        eval() 有返回值 ---有結果的簡單運算
        exec() 無返回值 ----簡單的流程控制
        eval()只能用在你明確知道你要執行的代碼是什么
 
        exec('print(123)')
        eval('print(123)')
        print(exec('print(123)'))  #沒有返回值
        print(eval('print(123)'))   #有返回值
 
        code = """[(print(i*'*')) for i in range(10)]"""
        exec(code)
        123
        123
        123
        None
        123
        None
 
        *
        **
        ***
        ****
        *****
        ******
        *******
        ********
        *********
 
    12.compile(source, filename, mode[, flags[, dont_inherit]]) 將一個字符串編譯為字節代碼。
        code3 = """name = input('請輸入你的名字:')"""
        compile3 = compile(code3,'','single')
 
        exec(compile3)
        print(name)
 
(4)數據類型相關
 
    1.complex([real[, imag]]) 用於創建一個值為 real + imag * j 的復數或者轉化一個字符串或數為復數。如果第一個參數為字符串,則不需要指定第二個參數。。
        復數 —— complex
        實數 : 有理數
                無理數
        虛數 :虛無縹緲的數
        5 + 12j  === 復合的數 === 復數
        6 + 15j
 
    2.float() 用於將整數和字符串轉換成浮點數。
        浮點數(有限循環小數,無限循環小數)  != 小數 :有限循環小數,無限循環小數,無限不循環小數
        浮點數
            354.123 = 3.54123*10**2 = 35.4123 * 10
        f = 1.781326913750135970
        print(f)
 
    3.bin()  返回一個整數 int 或者長整數 long int 的二進制表示
    4.oct()  將一個整數轉換成8進制字符串。
    5.hex()  函數用於將10進制整數轉換成16進制,以字符串形式表示。
 
        print(bin(10))    0b1010
        print(oct(10))    0o12
        print(hex(10))    0xa
 
    6.abs()  求絕對值
 
    7.divmod(x,y)   把除數和余數運算結果結合起來,返回一個包含商和余數的元組(a // b, a % b)。
        Return the tuple (x//y, x%y)
        print(divmod(100,15))
            (6, 10)
        實際應為舉例:100條新聞,每15條方1頁,可以放多少頁
 
 
    8.round()  四舍五入
 
    9.pow(x,y[,z])  方法返回 xy(x的y次方) 的值。
        當有2個參數時候,為x的y次方,等價於 x**y
            print(pow(9,2))     ->  81
        當有3個參數是,為x的y次方,再對z取余
            print(pow(9,2,4))  ->  1
 
    10.sum(iterable[, start])  求和
 
    11.max(iterable, *[, default=obj, key=func]) -> value
       max(arg1, arg2, *args, *[, key=func]) -> value
        print(max([1,22,9],[2,11,23]))
            [2, 11, 23]
        print(max(1,22,-100,key=abs))
            -100
    12.min(iterable, *[, default=obj, key=func]) -> value
       min(arg1, arg2, *args, *[, key=func]) -> value
 
 
    13.reversed()  保留原列表,反轉數據,返回一個可迭代的
 
        lst = [1,5,9,2,7,3]
        lst.reverse()
        print(lst)
 
        lst1 = []
        for i in reversed(lst):
            lst1.append(i)
        print(lst1)
 
    14.slice(start, stop[, step]) 實現切片對象,主要用在切片操作函數里的參數傳遞。
        exp:
        lst = [1,5,9,2,7,3]
        slst = slice(0,4,2)
        print(lst[slst])
            [1, 9]
 
 
    15.format() 格式化
        #字符串可以提供的參數,指定對齊方式,<是左對齊, >是右對齊,^是居中對齊
            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'
 
 
    16.bytes()  轉換成bytes類型(轉換成二進制類型)
        s = '王秋華'
        print(bytes('王秋華',encoding='utf-8')) #unicode轉換成utf-8的bytes
        print(bytes('王秋華',encoding='gbk'))   #unicode轉換成gbk的bytes
        print(s.encode('utf-8'))   #unicode轉換成utf-8的bytes
        print(s.encode('gbk'))     #unicode轉換成gbk的bytes
 
        網絡編程:只能傳二進制
        照片和視頻也是以二進制存儲
        html網頁爬取到的也是編碼
 
 
    17.bytearray([source[, encoding[, errors]]]) 返回一個bytes數組,對數組進行取值,得到轉化為十進制的數
                                    返回一個新字節數組。這個數組里的元素是可變的,並且每個元素的值范圍: 0 <= x < 256。
        bytearray('王王王',encoding='utf')
            bytearray(b'\xe7\x8e\x8b\xe7\xa7\x8b\xe5\x8d\x8e')
 
        new_s = bytearray('王王王',encoding='utf')
        new_s_lst = []
        for i in new_s:
            new_s_lst.append(i)
        print(new_s_lst)
            [231, 142, 139, 231, 167, 139, 229, 141, 142]
 
    18.memoryview(bytes('hello,eva',encoding='utf-8'))  返回給定參數的內存查看對象(Momory view)。
                        所謂內存查看對象,是指對支持緩沖區協議的數據進行包裝,在不需要復制對象基礎上允許Python代碼訪問。
                        針對bytes類型進行字節類型的切片
        切片  ---- 字節類型的切片 不占內存
 
        s = memoryview(bytes('王王王',encoding='utf-8'))
        print(s[1])
 
 
    19.ord()  將unicode的1個字符轉換成unicode的1個數字
        chr() 函數(對於8位的ASCII字符串)或 unichr() 函數(對於Unicode對象)的配對函數,它以一個字符(長度為1的字符串)
        作為參數,返回對應的 ASCII 數值,或者 Unicode 數值,如果所給的 Unicode 字符超出了你的 Python 定義范圍,則會引發一個 TypeError 的異常。
        print(ord('f'))
            102
        print(ord('王'))
            29579
    20.chr()  將unicode的1個數字轉換成unicode的1個字符
              用一個范圍在 range(256)內的(就是0~255)整數作參數,返回一個對應的字符。
        print(chr(97))
            a
 
    21.ascii() 只要是ascii碼中的內容,就打印出來,不是就轉換成\u
 
    22.repr()  用於%r格式化輸出
        print(repr('1'))    '1'
        print(repr(1))      1
 
    23.diet() 字典
 
    24.set()集合
 
    25.frozenset([iterable])  返回一個凍結的集合,凍結后集合不能再添加或刪除任何元素。
 
        >>>a = frozenset(range(10))     # 生成一個新的不可變集合
        >>> a
        frozenset([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
        >>> b = frozenset('runoob')
        >>> b
        frozenset(['b', 'r', 'u', 'o', 'n'])   # 創建不可變集合
        >>>
 
相關內置函數
 
    1.len()  長度
 
    2.enumerate(object)  函數用於將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,
                         同時列出數據和數據下標,一般用在 for 循環當中
 
        >>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
        >>>list(enumerate(seasons))
        [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
        >>>list(enumerate(seasons, start=1))       # 小標從 1 開始
        [(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
 
        普通的 for 循環
            >>>i = 0
            >>>seq = ['one', 'two', 'three']
            >>>for element in seq:
            ...    print(i, seq[i])
            ...    i += 1
            ...
            0 one
            1 two
            2 three
 
        for 循環使用 enumerate
            >>>seq = ['one', 'two', 'three']
            >>>for i, element in enumerate(seq):
            ...    print(i, seq[i])
            ...
            0 one
            1 two
            2 three
 
    3.all(iterable)  如果iterable的所有元素不為0、''、False或者iterable為空,all(iterable)返回True,否則返回False;
                     注意:空元組、空列表返回值為True,這里要特別注意。
                     有一個False就為False
 
    4.any(iterable) 如果都為空、0、false,則返回false,如果不都為空、0、false,則返回true
                    有1個為true就為true
        >>>any(['a', 'b', 'c', 'd'])  # 列表list,元素都不為空或0   True
        >>> any(['a', 'b', '', 'd'])   # 列表list,存在一個為空的元素   True
        >>> any([0, '', False])        # 列表list,元素全為0,'',false  False
        >>> any(('a', 'b', 'c', 'd'))  # 元組tuple,元素都不為空或0  True
        >>> any(('a', 'b', '', 'd'))   # 元組tuple,存在一個為空的元素  True
        >>> any((0, '', False))        # 元組tuple,元素全為0,'',false   False
        >>> any([]) # 空列表    False
        >>> any(()) # 空元組  False
 
    5.zip([iterable, ...]) 拉鏈方法:
        函數用於將可迭代的對象作為參數,將對象中對應的元素打包成一個個元組,然后返回由這些元組組成的對象,
        這樣做的好處是節約了不少的內存。我們可以使用 list() 轉換來輸出列表。
        如果各個迭代器的元素個數不一致,則返回列表長度與最短的對象相同,利用 * 號操作符,可以將元組解壓為列表。
        >>>a = [1,2,3]
        >>> b = [4,5,6]
        >>> c = [4,5,6,7,8]
        >>> zipped = zip(a,b)     # 返回一個對象
        >>> zipped
        <zip object at 0x103abc288>
        >>> list(zipped)  # list() 轉換為列表
        [(1, 4), (2, 5), (3, 6)]
        >>> list(zip(a,c))              # 元素個數與最短的列表一致
        [(1, 4), (2, 5), (3, 6)]
 
        >>> a1, a2 = zip(*zip(a,b))          # 與 zip 相反,*zip 可理解為解壓,返回二維矩陣式
        >>> list(a1)
        [1, 2, 3]
        >>> list(a2)
        [4, 5, 6]
    6.filter() 函數用於過濾序列,過濾掉不符合條件的元素,返回一個迭代器對象,如果要轉換為列表,可以使用 list() 來轉換。
            該接收兩個參數,第一個為函數,第二個為序列,序列的每個元素作為參數傳遞給函數進行判,然后返回 True 或 False,最后將返回 True 的元素放到新列表中。
 
        exp1:
        def func(n):
            return n % 2 == 1
        ret = filter(func,[1,2,3,4,5,6,7,8,9])
        for i in ret:
            print(i)
        執行結果:1 3 5 7 9
        filter(func,[1,2,3,4,5,6,7,8,9])等同於
        [i for i in [1,2,3,4,5,6,7,8,9] if i % 2 == 1]
 
        exp2:
        過濾只要為字符串的信息:
        def func(s):
            if type(s) == str:
                return True
        ret = filter(func,[1, 'felix','love', 4, 5, 6,'alina'])
        for i in ret:
            print(i)
                felix
                love
                alina
 
        exp3:過濾空內容
        def is_str(s):
            return s and str(s).strip()
        ret = filter(is_str, [1, 'hello','','  ',None,[], 6, 7, 'world', 12, 17])
        print(ret)
        for i in ret:
            print(i)
                1
                hello
                6
                7
                world
                12
                17
        exp3:求1-100 平方根是整數的數
        import math
        def my_sqrt(s):
            #return (s**0.5) % 1 == 0
            return math.sqrt(s) % 1 == 0
        ret = filter(my_sqrt,range(1,101))
        for i in ret:
            print(i)
 
    7.map(function, iterable, ...) 根據提供的函數對指定序列做映射。
 
        >>>def square(x) :            # 計算平方數
        ...     return x ** 2
        ...
        >>> map(square, [1,2,3,4,5])   # 計算列表各個元素的平方
            [1, 4, 9, 16, 25]
        >>> map(lambda x: x ** 2, [1, 2, 3, 4, 5])  # 使用 lambda 匿名函數
            [1, 4, 9, 16, 25]
 
        filter和map:都是返回一個迭代器
            filter
            1.執行filter的結果集合 <= 執行之前的結果
            2.filter只管篩選,不會改變原來的值
 
            map:
            1.執行前后元素個數不變
            2.值可能會發生改變
 
    8.sorted(iterable[, cmp[, key[, reverse]]]) 函數對所有可迭代的對象進行排序操作。
        sort 與 sorted 區別:
        sort 是應用在 list 上的方法,sorted 可以對所有可迭代的對象進行排序操作。
        list 的 sort 方法返回的是對已經存在的列表進行操作,無返回值,
        而內建函數sorted 方法返回的是一個新的 list,而不是在原來的基礎上進行的操作。
 
        >>>a = [5,7,6,3,4,1,2]
        >>> b = sorted(a)       # 保留原列表
        >>> a
        [5, 7, 6, 3, 4, 1, 2]
        >>> b
        [1, 2, 3, 4, 5, 6, 7]
 
        >>> L=[('b',2),('a',1),('c',3),('d',4)]
        >>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1]))   # 利用cmp函數
        [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
        >>> sorted(L, key=lambda x:x[1])               # 利用key
        [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
 
 
        >>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
        >>> sorted(students, key=lambda s: s[2])            # 按年齡排序
        [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
 
        >>> sorted(students, key=lambda s: s[2], reverse=True)       # 按降序
        [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
        >>>
 
        exp2:
        L = [1,-3,7,5,-2,-10]
        print(sorted(L,key=abs,reverse=True))
 
        L = ['sorted','sort','filter','map']
        print(sorted(L,key=len))

  

十、匿名函數

匿名函數
    lambda [arg1 [,arg2,.....argn]]:expression
 
    lambda只是一個表達式,函數體比def簡單很多。
    lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
    lambda函數擁有自己的命名空間,且不能訪問自有參數列表之外或全局命名空間里的參數。
    雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,后者的目的是調用小函數時不占用棧內存從而增加運行效率。
 
    exp:
        dic = {'k1': 10, 'k2': 50, 'k3': 100, 'k4': 80}
        print(max(dic,key=lambda k:dic[k]))
 
    內置函數中參數帶key的有以下:
    max min filter map sorted
    以上都可以通過和lambda合用完成一些功能
 
    exp2:
    現有兩元組tup1,tup2,請使用匿名函數生產列表lst
    tup1 = (('a'),('b'))
    tup2 = (('c'),('d'))
    lst = [{'a':'c'},{'b':'d'}]
 
    寫法1:自己寫的
    lst = lambda x,y: [{(x[i][0]):y[i][0]} for i in range(len(x))]
    print(lst(tup1,tup2))
        [{'a': 'c'}, {'b': 'd'}]
 
    寫法2:
 
    tup1 = (('a'),('b'))
    tup2 = (('c'),('d'))
 
    # lst = [{'a':'c'},{'b':'d'}]
 
    # ret = zip(tup1,tup2)
 
    # def func(t):
    #     return {t[0]:t[1]}
    # func = lambda t:{t[0]:t[1]}
    # res = map(lambda t:{t[0]:t[1]},zip(tup1,tup2))
    print(list(map(lambda t:{t[0]:t[1]},zip(tup1,tup2))))
 
    exp3.以下代碼的輸出是什么?請給出答案並解釋。
    def multipliers():
        return [lambda x:i*x for i in range(4)]
    print([m(2) for m in multipliers()])
    請修改multipliers的定義來產生期望的結果。
 
    解析:
        def multipliers():
            return [lambda x : i *x for i in range(4)]  #返回列表推導式 [lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]
 
        print([m(2) for m in multipliers()])
        # [m(2) for m in [lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]]
        # multipliersw()為[lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]
 
        # [m(2) for m in [lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]]
        # m 為 lambda x : i *m,  4次
        # m(2)   [lambda x : i *2,lambda x : i *2,lambda x : i *2,lambda x : i *2]]
        #而此時multipliers()中的for循環已執行完,i最后的值為3
        # 所以 [lambda x : 3 *2,lambda x : 3 *2,lambda x : 3 *2,lambda x : 3 *2]]
        #[6, 6, 6, 6]
 
    exp4.以下代碼的輸出是什么?請給出答案並解釋。
        def multipliers():
            return (lambda x : i *x for i in range(4))  #返回一個生成器 g =(lambda x : i *x for i in range(4)
 
        print([m(2) for m in multipliers()])
 
        # [m(2) for m in multipliers()]
        # [m(2) for m in (lambda x : i *x for i in range(4)]
        # [m(2) for m in (lambda x : 0 *x,lambda x : 1 *x,lambda x : 2 *x,lambda x : 3 *x]
        # [2 * 0,,2 * 1, 2 * 2,2 * 3]
        #[0,2,4,6]

  


免責聲明!

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



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