函數對象

在面向對象編程中 一切皆對象

具體的體現
1.函數可以被引用
2.函數可以作為函數的參數
3.函數可以作為函數的返回值
4.可以被存儲到容器類型中

def pay():
    print('支付')
def save():
    print('存錢')
def cheak():
    print('查看')




dic={'1':pay,'2':save,'3':cheak}
while True:
     l=['支付','存錢','查看']
     for i,k in enumerate(l):
         print(i+1,k)
     cmd=input('>>>:')
     if cmd in dic:
         dic[cmd]()
     else:
         print('指令錯誤')

2.函數嵌套
1.嵌套調用 在一個函數中調用了另一個函數
2.嵌套定義 在一個函數中定義了另一個函數
定義在函數內的函數 只能函數內使用 外界不能訪問

def func1():
    print("func1")


def func2():
    print("func2")

     func1()

 func2()
嵌套調用
def func1():
     print("func1")

     def func2():
         print("func2")

     func2()

func1()
嵌套定義

3.函數的名稱空間

存儲名稱的空間
名稱空間的分類
內置名稱空間 存儲解釋器自帶的一些名稱與值的對應關系
(python解釋器啟動時創建 所有代碼全部執行完畢 關閉解釋器時 銷毀)
print len max min

全局名稱空間 哪些數據會存儲在全局空間?
文件級別的名稱 只要你的名字的定義是頂著最左邊寫的就在全局空間
除了內置的函數內的 都在全局中
(執行py文件創建全局名稱空間 關閉解釋器時 銷毀)


局部名稱空間 只要是函數內的名稱就是局部的
(調用函數時創建 函數執行完畢就銷毀)

名稱空間的加載順序
內置的 -> 全局的 ->局部的

名稱的查找順序
局部 -> 全局的 -> 內置的

4.函數的作用域

作用域(作用范圍)
域 指的是區域 范圍的的意思
全局的名稱空間和內置的名稱空間 在使用上沒什么區別
局部的和全局的內置的 就區別了 局部定義的只能在局部使用
給三個空間劃分范圍

全局的和內置可以劃分為同一個范圍
global 表示的全局范圍 就是所謂的全局作用域

局部的單獨劃分為一個范圍
local 局部作用域

globals()
locals()

 

print(locals())#查看全局作用域,當locals在全局作用域時,功能和globes相同
print(globals())
def func():
     a = 100
     print(locals())#查看局部作用域

func()
age = 18
def func2():
     # 明確聲明  要使用全局中的age
   global age
    age = 19

    print(age)

func2()
print(age)
a = 1
def func3():
    a = 10
    def inner():
        # 明確聲明 要使用上一中的 a 如果上一層沒有  則找上上層  但是注意 不能找到全局中的
        nonlocal a
        a = 100
        print(a)
    inner()
    print("這是func3中a",a)

func3()
print(a)

5.閉包函數

age = 20
# 如下就是一個閉包函數
def fun1():
    age = 18
    def inner():
        print("hello")
        print(age)
    # 在返回這個內部的函數時 不是單純的返回函數  還把函數中訪問到的局部名稱一起打包了
    # 相當于將內部函數與 訪問的數據打包在一起了  閉包這個名字就是這么得來的
    return inner
f = fun1() # f 就是inner
f()

# 函數的作用域在定義時就固定了  與調用沒有關系
# 閉包函數的模板
def func2():
    a = 1
    b = 10
    def inner():
        print(a)
        print(b)
    return inner
什么是閉包函數
1.定義在另一個函數內的函數
2.內部的的函數訪問了外部的名稱數據 注意 不包含全局的)

6.裝飾器

什么是裝飾器
什么是裝飾 給一個已有的對象(一個函數) 添加新的功能
為什么要裝飾 增強功能
器 指一個工具 在python中 值得是具備某個功能的函數

簡單的說:裝飾器就是 一個用于給其他函數增加功能的函數

 

import time

def download():
    print('開始下載xxx.mp4')
    time.sleep(2)
    print('xxxx.mp4 下載完成')
    
    
# 請你統計下載耗時
start_time = time.time()
download()
end_time = time.time()
print('下載耗時',(end_time-start_time))

def download2():
    start_time = time.time()
    print("開始下載xxx.mp4")
    time.sleep(2)
    print("xxxx.mp4 下載完成!")
    end_time = time.time()
    print("下載耗時", (end_time - start_time))

download2()
def max2(x,y):
    if x > y:
        return x
    else:
        return y

res=max2(10,20)

x=10
y=20

# res=x if x > y else y
# print(res)


res='OK' if False else 'No'
print(res)
三元表達式

 


def outter(func):
    def inner():
        strat_time = time.time()
        func()
        end_time = time.time()
        print('下載耗時',(end_time-start_time))
    return inner
download=outter(download)
download()

 

# 疊加多個裝飾器
# 1. 加載順序(outter函數的調用順序):自下而上
# 2. 執行順序(wrapper函數的執行順序):自上而下


def outter1(func1): #func1=wrapper2的內存地址
    print('加載了outter1')
    def wrapper1(*args,**kwargs):
        print('執行了wrapper1')
        res1=func1(*args,**kwargs)
        return res1
    return wrapper1

def outter2(func2): #func2=wrapper3的內存地址
    print('加載了outter2')
    def wrapper2(*args,**kwargs):
        print('執行了wrapper2')
        res2=func2(*args,**kwargs)
        return res2
    return wrapper2

def outter3(func3): # func3=最原始的那個index的內存地址
    print('加載了outter3')
    def wrapper3(*args,**kwargs):
        print('執行了wrapper3')
        res3=func3(*args,**kwargs)
        return res3
    return wrapper3



@outter1 # outter1(wrapper2的內存地址)======>index=wrapper1的內存地址
@outter2 # outter2(wrapper3的內存地址)======>wrapper2的內存地址
@outter3 # outter3(最原始的那個index的內存地址)===>wrapper3的內存地址
def index():
    print('from index')

print('======================================================')
index()

'''
疊加多個裝飾器
 
有參裝飾器
import time

current_user={'user':None}

def auth(engine='file'):
    def outter(func):
        def wrapper(*args,**kwargs):
            if current_user['user']:
                res=func(*args,**kwargs)
                return res

            user=input('username>>>: ').strip()
            pwd=input('password>>>: ').strip()

            if engine == 'file':
                # 基于文件的認證
                if user == 'egon' and pwd == '123':
                    print('login successfull')
                    current_user['user']=user
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('user or password error')
            elif engine == 'mysql':
                # 基于mysql的認證
                print('基于mysql的認證')
            elif engine == 'ldap':
                # 基于ldap的認證
                print('基于ldap的認證')
            else:
                print('不知道engine')
        return wrapper
    return outter

@auth('ldap') #@outter #index=outter(index) # index=wrapper
def index():
    time.sleep(1)
    print('from index')

@auth('mysql') #@outter # home=outter(home) #home=wrapper
def home(name):
    print('welcome %s' %name)

index()
home('egon')
View Code

 

def max2(x,y):
    if x > y:
        return x
    else:
        return y

res=max2(10,20)

x=10
y=20

# res=x if x > y else y
# print(res)


res='OK' if False else 'No'
print(res)
三元表達式

 

 
# 列表生成式
# l=[]
# for i in range(10):
#     if i > 4:
#         l.append(i**2)
#
#
#
# l=[i**2 for i in range(10) if i > 4]
# print(l)


# names=['egon','alex_sb','kevin_sb','hxx_sb','cxx_sb']
# sbs=[]
# for name in names:
#     if name.endswith('sb'):
#         sbs.append(name)

# sbs=[name.upper() for name in names if name.endswith('sb')]



# print([name.upper() for name in names])
# print([name for name in names if name.endswith('sb')])


# 字典生成式
# res={i:i**2 for i in range(10) if i > 3}
# print(res)
生成式

 

# func()
# func()
# func()
# 匿名函數就是只定義了一個函數的內存地址,主要用于臨時使用一次的場景
# func=lambda x,y:x+y
# print(func)
# print(func(1,2))

# res=(lambda x,y:x+y)(1,2)
# print(res)


# print(max([10,11,-3,23]))
# salaries={
#     'egon':3000,
#     'alex':100000000,
#     'wupeiqi':10000,
#     'yuanhao':2000
# }
# def func(k):
#     return salaries[k]

# print(max(salaries,key=lambda k:salaries[k]))
# print(min(salaries,key=func))
# for循環的結果         比較依據
# 'egon'                3000
# 'alex'                100000000
# 'wupeiqi'             10000
# 'yuanhao'             2000

# l=[4,2,3]
# l_new=sorted(l,reverse=True)
# print(l_new)
#
#
# print(sorted(salaries,key=lambda k:salaries[k],reverse=True))
#
匿名函數

 

迭代器

1. 什么是迭代器
什么是迭代?
迭代是一個重復的過程,但是每次重復都是基于上一次重復的結果而繼續
#下列循環知識單純的重復
while True:
print(1)

# 基于索引的迭代取值
l=['a','b','c']
i=0

while i < len(l):
print(l[i])
i+=1
什么是迭代器?
迭代取值的工具
2. 為什么要用迭代器
迭代器
優點
1. 提供一種不依賴索引的迭代取值方式
2. 更節省內存
缺點:
1. 不如按照索引的取值方式靈活
2. 取值一次性的,只能往后取,無法預測值的個數

3. 如何用迭代器
可迭代的對象:str\list\tuple\dict\set\文件對象
但凡內置有__iter__方法的對象都稱之為可迭代對象

迭代器對象: 文件對象
既內置有__iter__方法又內置有__next__方法的對象都稱之為迭代器對象


調用可迭代對象下__iter__方法,會有一個返回值,該返回值就是內置的迭代器對象
 
# s='abcdef'
# l=['a','b','c']
# d={'k1':111,'k2':222,'k3':333}

# iter_d=d.__iter__()
# # print(iter_d)
#
# try:
#     print(iter_d.__next__())
#     print(iter_d.__next__())
#     print(iter_d.__next__())
#     print(iter_d.__next__())
# except StopIteration:
#     print('取值完畢')


d={'k1':111,'k2':222,'k3':333}
# d={1,2,3,4,5}
# d=[1,2,3,4]

# iter_d=d.__iter__()
# iter_d=iter(d) #d.__iter__

# print(next(iter_d)) #iter_d.__next__()

# print(len(d))
print(d.__len__())


# print(iter_d.__iter__().__iter__().__iter__() is iter_d)

# print(d.__iter__().__next__())
# print(d.__iter__().__next__())
# print(d.__iter__().__next__())



# while True:
#     try:
#         v=iter_d.__next__()
#         print(v)
#     except StopIteration:
#         break
#
# print('第二次取值')
#
# iter_d=d.__iter__()
# while True:
#     try:
#         v=iter_d.__next__()
#         print(v)
#     except StopIteration:
#         break
#

# for k in d:
#     print(k)

#for循環的底層原理:
# 1. 調用in后面那個值/對象的__iter__方法,拿到一個迭代器對象iter_obj
# 2. 調用迭代器對象iter_obj.__next__()將得到的返回值賦值變量名k,循環往復直到取值完畢拋出異常StopIteration
# 3. 捕捉異常結束循環
View Code

 

生成器就是一種自定義的迭代器

如何得到生成器?
但凡函數內出現yield關鍵字,再去調用函數不會立即執行函數體代碼,會得到一個返回值,該返回值就是生成器對象,
即自定義的迭代器

# def func():   
#     print('first')
#     yield 1
#     print('second')
#     yield 2
#     print('third')
#     yield 3
#
#
# g=func()
# # print(g)
#
# res1=next(g)
# print(res1)
#
# res2=next(g)
# print(res2)
#
# res3=next(g)
# print(res3)
#
# next(g)

# 總結yield:
# 1. 提供一種自定義迭代器的解決方案
# 2. yield & return
#    相同點: 都可以返回值,返回值沒有類型限制\個數限制
#    不同點: return只能返回一次值,yield卻可以讓函數暫停在某一個位置,可以返回多次值



# def my_range(start,stop,step=1):
#     while start < stop: # 5 < 5
#         yield start # 3
#         start+=step #start=5

# range(1,5,2) # 1 3
# for i in my_range(1,5000000000000000000000000000000000000000000,2): # 1 3
#     print(i)
View Code

 

函數的遞歸調用與二分法
1. 函數的遞歸調用:
在調用一個函數的過程又直接或者間接地調用該函數本身,稱之為遞歸調用

遞歸必須滿足兩個條件:
1. 每進入下一次遞歸調用,問題的規模都應該有所減少
2. 遞歸必須有一個明確的結束條件
遞歸有兩個明確的階段:
1. 回溯
2. 遞推

# age(5)=age(4)+2
# age(4)=age(3)+2
# age(3)=age(2)+2
# age(2)=age(1)+2
# age(1)=18

# age(n)=age(n-1)+2  # n > 1
# age(1)=18          # n = 1

# def age(n):
#     if n == 1:
#         return 18
#     return age(n-1)+2
#
# print(age(5))


# l=[1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]]
#
# def func(list1):
#     for item in list1:
#         if type(item) is not list:
#             print(item)
#         else:
#             # 如果是列表,應該...
#             func(item)
#
# func(l)


# nums=[3,5,7,11,13,23,24,76,103,111,201,202,250,303,341]
#
# find_num=203
# for num in nums:
#     if num == find_num:
#         print('find it')
#         break
# else:
#     print('not exists')


nums=[3,5,7,11,13,23,24,76,103,111,201,202,250,303,341]


def binary_search(list1,find_num):
    print(list1)
    if len(list1) == 0:
        print('not exist')
        return
    mid_index=len(list1) // 2
    if find_num > list1[mid_index]:
        # in the right
        binary_search(list1[mid_index + 1:],find_num)
    elif find_num < list1[mid_index]:
        # in the left
        binary_search(list1[:mid_index],find_num)
    else:
        print('find it')

binary_search(nums,203)
View Code

 res=[i for i in range(10)  if i > 5]

print(res)#這是列表生成式

 

g=(i for in range(10) if i >5)

print(g)

print(next(g))

print(next(g))

print(next(g))

print(next(g))#這是生成器表達式

 

with open('a.txt','rt,encoding='utf8')as f:
#print(len(f.read())) 統計文件中字符個數
res = sum(len(line) for line in f)
print(res) #用生成器表達式的方法統計文件字符個數