Python之函数

耗尽温柔 提交于 2020-02-04 04:33:25

一函数基础

1.1 函数分类

    a.内置函数:为了方便我们的开发,针对一些简单的功能,python解释器已经为我们定义好了的函数即内置函数。对于内置函数,我们可以拿来就用而无需事先定义,如len(),sum(),max()

     b.自定义函数:很明显内置函数所能提供的功能是有限的,这就需要我们自己根据需求,事先定制好我们自己的函数来实现某种功能,以后,在遇到应用场景时,调用自定义的函数即可。

1.2 定义函数

#语法
def 函数名(参数1,参数2,参数3,...):
    '''注释'''
    函数体
    return 返回的值

#1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印

#2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值

#3、空函数:设计代码结构

1.3 调用函数

1 语句形式:foo()

2 表达式形式:3*len('hello')

3 当中另外一个函数的参数:range(len('hello'))

函数练习:

'''
1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作
'''
import os
def foo(x,y,z):
    '''

    :param x: 文件名
    :param y: 修改的内容
    :return:
    '''
    with open(x,'r')as f_read,open('tmp.txt','w')as f_write:
        for line in f_read:
            data=line.replace(y,z)
            f_write.write(data)
    os.remove(x)
    os.rename('tmp.txt',x)
foo('a.txt','ha','yi')
'''
2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
'''
def foo(a):
    n_num=0
    n_word=0
    n_space=0
    n_other=0
    for word in a:
        if word.isdigit():n_num+=1
        elif word.isalpha():n_word+=1
        elif word==' ':n_space+=1
        else:n_other+=1
        print(word)
    print(n_num,n_word,n_space,n_other)
foo('123   wef   wd23!2')
'''
3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。
'''
def func(a):
    if len(a)>5:return True
    else:return False
print(func('23rsdsd2'))
'''
4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
'''
def func(a):
    while True:
        if type(a)!=list:
            print('list please!')
        else:break
    if len(a)>=2:
        data=a[0:2]
    else:data=a
    print(data)
func([12,])
'''
5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
'''
def func(a):
    l=[]
    for x in a:
        if a.index(x)%2!=0:
            l.append(x)
    return l
print(func(['qef','123','asdf','dcsc','csdcd']))
'''
6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
PS:字典中的value只能是字符串或列表
'''
def func(dic):
    for key in dic:
        if len(dic[key])>=2:
            new_value=dic[key][0:2]
            dic.pop(key)

            dic[key]=new_value
    return dic
print(func( {"k1": "v1v1", "k2": [11,22,33,44]}))

1.4 函数对象

#1 可以被引用
#2 可以当作参数传递
#3 返回值可以是函数
#3 可以当作容器类型的元素
#取代多分支if语句def foo():
    print('foo')

def bar():
    print('bar')

dic={
    'foo':foo,
    'bar':bar,
}
while True:
    choice=input('>>: ').strip()
    if choice in dic:
        dic[choice]()

 1.5 函数嵌套

def max1(x,y):
    return x if x>y else y
def max4(a,b,c,d):
    res1=max1(a,b)
    res2=max1(c,d)
    res=max1(res1,res2)
    return res
print(max4(1,2,3,4))
# 函数的嵌套定义
def f1():
    def f2():
        def f3():
            print('from f3')
        f3()
    f2()
f1()

1.6 名称空间和作用域

名称空间:存放名字的地方。局部名称空间,全局名称空间,内置名称空间

名字的查找顺序:局部名称空间--->全局名称空间-->内置名称空间

名称空间的加载顺序:

python test.py
#1、python解释器先启动,因而首先加载的是:内置名称空间
#2、执行test.py文件,然后以文件为基础,加载全局名称空间
#3、在执行文件的过程中如果调用函数,则临时产生局部名称空间

作用域即范围
        - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
      - 局部范围(局部名称空间属于该范围):临时存活,局部有效

查看作用域:globals(),locals()
  LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
  locals 是函数内的名字空间,包括局部变量和形参
  enclosing 外部嵌套函数的名字空间(闭包中常见)
  globals 全局变量,函数定义所在模块的名字空间
  builtins 内置模块的名字空间

二.闭包函数和装饰器

2.1 闭包函数

    定义在函数内部的函数,特点是,包含对外部作用域而不是对全局作用域名字的引用。

from urllib.request import urlopen
def get(url):
    def inner():
        return urlopen(url).read()
    return inner
baidu=get('http://www.baidu.com')
baidu()闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

2.2 装饰器

    1.为什么要用装饰器:开放封闭原则,对扩展是开放的,对修改是封闭的

    2.什么是装饰器

        -用来装饰它人,装饰器本身可以是任意可调用对象,被装饰器的对象也可以是任意可调用对象。

  -遵循的原则:1.不修改被装饰对象的源代码 2.不修改被装饰对象的调用方式

  -目标是:在遵循原则1和2的前提,为被装饰对象添加新功能

从普通的函数逐渐加入装饰器的过程(不修改原函数代码,不修改调用方式):

def get_up():
    '''描述睡觉起床过程'''
    print('睡他妈的觉')
    time.sleep(random.randint(2,4))
    print('起他妈的床')

def wash():
    '''描述洗漱过程'''
    print('洗他妈的脸')
    time.sleep(random.randint(1,3))
    print('刷他妈的牙')
没有装饰器时普通的两个函数
def count_time(fun):
    def wraper():
        start_time=time.time()
        fun()
        fin_time=time.time()
        print(fin_time-start_time)
    return wraper

def get_up():
    '''描述睡觉起床过程'''
    print('睡他妈的觉')
    time.sleep(random.randint(2,4))
    print('起他妈的床')

def wash():
    '''描述洗漱过程'''
    print('洗他妈的脸')
    time.sleep(random.randint(1,3))
    print('刷他妈的牙')

get_up=count_time(get_up)            #也就是返回的wraper ------fun=get_up
get_up()
将两个函数传入一个时间计算函数
import time,random
def count_time(fun):
    def wraper():
        start_time=time.time()
        fun()
        fin_time=time.time()
        print(fin_time-start_time)
    return wraper

#get_up=count_time(get_up)            #也就是返回的wraper ------fun=get_up
@count_time
def get_up():
    '''描述睡觉起床过程'''
    print('睡他妈的觉')
    time.sleep(random.randint(2,4))
    print('起他妈的床')

@count_time
def wash():
    '''描述洗漱过程'''
    print('洗他妈的脸')
    time.sleep(random.randint(1,3))
    print('刷他妈的牙')

get_up()
wash()
变为装饰器
import time,random
def count_time(fun):
    def wraper(*args,**kwargs):
        start_time=time.time()
        fun(*args,**kwargs)
        fin_time=time.time()
        print(fin_time-start_time)
    return wraper

#get_up=count_time(get_up)            #也就是返回的wraper ------fun=get_up
@count_time
def get_up(name):
    '''描述睡觉起床过程'''
    print('睡他妈的觉%s'%name)
    time.sleep(random.randint(2,4))
    print('起他妈的床%s'%name)

@count_time
def wash():
    '''描述洗漱过程'''
    print('洗他妈的脸')
    time.sleep(random.randint(1,3))
    print('刷他妈的牙')

get_up('hantao')
wash()
改进(解决参数的不可预见性)
import time,random
def count_time(fun):
    def wraper(*args,**kwargs):
        start_time=time.time()
        res=fun(*args,**kwargs)
        fin_time=time.time()
        print(fin_time-start_time)
        return res
    return wraper

#get_up=count_time(get_up)            #也就是返回的wraper ------fun=get_up
@count_time
def get_up(name):
    '''描述睡觉起床过程'''
    print('睡他妈的觉%s'%name)
    time.sleep(random.randint(2,4))
    print('起他妈的床%s'%name)
    return '开心的一天开始了'

@count_time
def wash():
    '''描述洗漱过程'''
    print('洗他妈的脸')
    time.sleep(random.randint(1,3))
    print('刷他妈的牙')

res=get_up('hantao')
wash()
print(res)
改进(解决return正常)

 

import time

def index():
    time.sleep(2)
    print('welcome to index page!')

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

index=timer(index)
index()
实现装饰器功能
def timer(func):
    def inner():
        start_time=time.time()
        func()
        stop_time=time.time()
        print(stop_time-start_time)
    return inner
@timer
def index():
    time.sleep(2)
    print('welcome to index page!')

index()
python装饰器语法

 

#无参装饰器import time
from functools import wraps
def timmer(func):
    @wraps(func)
    def inner(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is :%s'%(stop_time-start_time))
        return res
    return inner

@timmer
def index():
    time.sleep(2)
    print('welcom to index!')
    return 'index'

@timmer
def home(name):
    time.sleep(3)
    print('welcome %s to home'%name)
    return 'home'

index()
home('hantao')
print(index())
print(home('hantao'))
#有参装饰器
import time
current_status={'user':None,'status':False}


def auth(egine='file'):
    def wrapper(func):
        def inner(*args,**kwargs):
            if current_status['user'] and current_status['status']:
                res=func(*args,**kwargs)
                return res
            if egine=='file':
                name=input('username>>:').strip()
                pwd=input('password>>:').strip()
                if name=='hantao'and pwd=='123':
                    print('login successful!')
                    current_status['user']=name
                    current_status['status']=True
                    res=func(*args,**kwargs)
                    return res
            elif egine=='mysql':
                print('mysql')
            else:pass
        return inner
    return wrapper

@auth(egine='file')   #@wrapper  #index=wrapper(index)
def index():
    time.sleep(2)
    print('welcom to index!')
    return 'index'

index()
'''
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
'''
from functools import wraps

auth_status={'user':None,}

def auth(engine='file'):
    def wrapper(func):
        @wraps(func)
        def inner(*args,**kwargs):
            if engine=='file':
                with open('aaa')as read_f:
                    userinfo=eval(read_f.read())
            else:
                pass
            while True:
                if auth_status.get('user'):break
                username=input('username:').strip()
                password=input('password:').strip()
                with open('aaa')as read_f:
                    if username == userinfo.get('name') and password==userinfo.get('password'):break
            res=func(*args,**kwargs)
            return res
        return inner
    return wrapper

@auth(engine='file')
def index(x):
    print(x)

index('hantao')
装饰器练习1
#编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录
from functools import wraps
import time

auth_status={'user':None,'auth_time':None}

def auth(engine='file'):
    def wrapper(func):
        @wraps(func)
        def inner(*args,**kwargs):
            with open('aaa')as read_f:
                userinfo=eval(read_f.read())
            while True:
                if auth_status.get('user') and time.time()-auth_status['auth_time']<10:break
                username=input('username:').strip()
                password=input('password:').strip()
                if username == userinfo.get('name') and password==userinfo.get('password'):
                    auth_status['user']=username
                    auth_status['auth_time']=time.time()
                    break
            res=func(*args,**kwargs)
            return res
        return inner
    return wrapper

@auth(engine='file')
def index1(x):
    time.sleep(3)
    print(x)
    time.sleep(8)

@auth(engine='file')
def index2(x):
    print(x)

index1('hantao')
index2('hantao')
装饰器练习2

 

三.迭代器和生成器

3.1 迭代器

    1.什么叫迭代:迭代是一个重复过程,每次重复都是基于上一次的结果来的

    2.为什么用迭代器?

        -对于序列类型:字符串,列表,元祖,可以基于索引的迭代取值方式,而对于没有索引的类型,入字典、集合、文件,这种方式不适用,于是我们必须找出一种能不依赖与索引的取值方式,这就是迭代器。

    3.可迭代对象:只要对象内置有__iter__方法,obj.__iter__(字符串,列表,元祖,字典,集合,文件)

    4.迭代器对象:对象既内置有__iter__方法,又内置有__next__,如文件对象

    注意:可迭代对象不一定是迭代器对象,而迭代器对象一定是可迭代的对象

list=[1,2,3,4]                   #可迭代对象
list_item=list.__item__()                #一个迭代器对象
list_item.__next__()                       #相当于next(list__item)    不依赖所有取值
#for循环就是将被循环对象执行__item__()方法,进行next()操作,进行取值
dic={'a':1,'b':2,'c':3}
iter_dic=dic.__iter__()
while True:
    try:
        print(next(iter_dic))
    except StopIteration:
        break

    迭代器的优缺点:

        -优点:

    提供了一种统一的迭代取值方式,该方式不再依赖于索引

    更节省内存(迭代器只是一个内存地址连接到文件,next()取值到内存)

  -缺点:

    无法统计长度

    一次性的,只能往后走,不能往后退,无法获取指定位置的值

from collections import Iterable,Iterator

print(isinstance([1,2,3],Iterable))
print(isinstance([1,2,3],Iterator))
判断

 

 3.2 生成器

'''
定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行函数体代码,会得到一个结果
该结果就是生成器对象
'''
def fun():
    print('first')
    yield 1
    print('second')
    yield 2
    print('third')
    yield 3

g=fun()**********************************************************************************
#生成器本质就是迭代器'''next() 在生成器的实质是:  1.让函数继续运行,直到运行到yield停止。  2.将yield的值返回到next()'''print(next(g))print(next(g))
for i in g:
    print(i)*********************************************************************************
'''
yield的功能:
    -为我们提供了一种自定义迭代器的方式
    -对比return,可以返回多次值,挂起函数的运行状态
'''**********************************************************************************
#利用生成器实现range()方法
def my_range(start,stop,step=1):
    while start<stop:
        yield start
        start+=step
g=my_range(1,5)
print(next(g))
print(next(g))
print(next(g))
for i in my_range(1,1342341,step=2):
    print(i)
import time
def tail(filepath):
    with open(filepath,'rb')as read_f:
        read_f.seek(0,2)
        while True:
            read_line=read_f.readline()
            if read_line:
                yield read_line.decode('utf-8')
            else:
                time.sleep(0.2)

def grep(pattern,lines):
    lines=tail('access.log')
    for line in lines:
        if pattern in line:
            print(line,end='')

grep('404',tail('access.log'))
利用生成器实现tail -f |grep
#协程函数
#yield的表达式形式用法
def eat(name):
    food_list=[]
    print('%s开始吃了'%(name))
    while True:
        food=yield food_list
        print('%s正在吃%s'%(name,food))
        food_list.append(food)

g_eat=eat('喵')
'''
send的作用:
    1.next()的作用
    2.向yield传值
    3.要注意的是第一次要先send(None) == next()
'''
print(g_eat.send(None))            
print(g_eat.send('猫粮'))
print(g_eat.send('小鱼干'))
print(g_eat.send('猫罐头'))
g_eat.close()
print(g_eat.send('狗粮'))

 

四.面向过程编程

定义面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么 基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式

优点:复杂的问题流程化,进而简单化

缺点:可扩展性差

 

五.三元表达式,列表推导式,生成器表达式

5.1 三元表达式

name=input('>>:')
if name == 'hantao':
    print('sb')
else:
    print('nb')


name=input('>>:')
print('sb' if name=='hantao' else 'nb')

5.2 列表推导式

#语法
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
#相当于
res=[]
for item1 in iterable1:
    if condition1:
        for item2 in iterable2:
            if condition2
                ...
                for itemN in iterableN:
                    if conditionN:
                        res.append(expression)
egg_list=[]
for i in range(10):
    res='egg%s'%i
    egg_list.append(res)
print(egg_list)

l=['egg%s'%i for i in range(10) if i >=3]
print(l)
names=['egon','alex_sb','wupeiqi','yuanhao']
names=[name.upper() for name in names if not name.endswith('sb')]
print(names)

5.3 生成器表达式

#把列表推导式的[]换成()就是生成器表达式
l=('hantao%s'%i for i in range(10) if i>=3)
print(l)
print(next(l))
print(next(l))
print(next(l))

#优点:省内存,一次只产生一个值在内存中

六. 函数递归与二分法

#函数递归调用:在调用一个函数的过程中直接或间接的调用该函数本身,称之为函数的递归调用
import sys
sys.setrecursionlimit(3000)

count=1
def func1():
    global count
    print('func1',count)
    count+=1
    func1()

func1()
#递归分为两个重要的阶段:递推+回溯
def age(n):
    if n==1:
        return 18
    return age(n-1)+2

res=age(12)
print(res)
#总结递归调用
#1:进入下一次递归时,问题的规模必须降低
#2:递归调用必须要有一个明确的约束条件
#3:在python中没有尾递归优化,递归调用的效率就是不高

l=[1,2,[3,4,[5,6,[7,8]]]]

def func(l):
    for i in l:
        if isinstance(i,list):
            func(i)
        else:
            print(i)

func(l)
#二分法
l=[1,2,4,8,11,15,19,23,38,80,123,234,345,456,567,678,789]   #从小到大排列的数字列表



def get(num,l):
    print(l)
    if len(l)>0:
        mid=len(l)//2
        if num>l[mid]:
            #in right
            l=l[mid+1:]
        elif num<l[mid]:
            #in left
            l=l[:mid]
        else:
            print('find it')
            return
        get(num, l)
    else:
        print('not exists')
get(68,l)
l=[1,2,4,6,9]

def search(num,l,start=0,stop=len(l)-1):
    if start <= stop:
        mid=start+(stop-start)//2
        if num > l[mid]:
            start=mid+1
        elif num< l[mid]:
            stop=mid-1
        else:
            print(mid)
            return
        search(num,l,start,stop)
    else:
        print('meiyou')


search(6,l)
查找列表索引

 

七.匿名函数lambda

7.1 语法

#匿名函数没有绑定名字的函数,没有绑定名字意味着只能用一次就会被回收
#所以匿名函数的应用场景就是,某个功能只用一次就结束了
def f1(n):
    res=n**2
    return res

lambda n:n**2

7.2 匿名函数和一些内置函数的配合使用

#lambda和max配合使用
#求最高工资
salary={'hantao':1000,
        'mayun':500,
        'xi':30}

res=max(salary,key=lambda k:salary[k])            #key传入函数进行比较规则制定
print(res)

#与min()函数用法相同
#lambda和sorted配合使用
salary={'hantao':1000,
        'mayun':500,
        'xi':30}

print(sorted(salary,key=lambda k:salary[k],reverse=True))
#map   映射
l1=['hantao','mayun','xjp']
print(list(map(lambda x:x+'_主席',l1)))

#reduce   进行处理
from functools import reduce
print(reduce(lambda x,y:x+y,range(101)))

#filter  过滤
l2=['hantao主席','mayun主席','xjp']
print(list(filter(lambda name:name.endswith('主席'),l2)))

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!