三、函数

目录

  一、理解函数

  二、函数的定义

  三、函数的调用

  四、函数的返回值return

  五、函数的参数

  六、函数嵌套

  七、名称空间与作用域

  八、函数对象

  九、闭包函数

  十、装饰器

  十一、匿名函数

  十二、内置函数

一、理解函数

  1.为什么要用函数

#1.程序的组织结构不清晰,可读性差
#2.代码冗余
#3.程序的可扩展性极差

 

  2.什么是函数

#1.具备某一功能的工具就是程序中的函数
#2.事先准备工具的过程称之为函数的定义
#3.遇到应用场景“拿来就用”就是函数的调用

##综上所述,在程序中,函数的使用必须遵循:先定义,在调用

 

  3.怎么用函数

name_from_db='egon'
pwd_from_db='123'


def auth():
    name=input('用户名>>: ').strip()
    pwd=input('密码>>: ').strip()

    if name == name_from_db and pwd == pwd_from_db:
        print('login successfull')
    else:
        print('user or pwd error')


auth()

 

二、函数的定义

# def 函数名(参数1,参数2,...):
#     """
#     函数的文档注释
#     :param 参数1: 参数1的作用
#     :param 参数2: 参数1的作用
#     :return: 返回值的描述
#     """
#     代码1
#     代码2
#     代码3
#     ....
#     return 返回值

  2.1 语法:在函数定义阶段只检测语法,不执行代码

# def foo():
#     if        #错误语法

  2.2 先定义后调用

#定义阶段
def bar():
    print('from bar')

def foo():
    print('from foo')
    bar()

#调用阶段
foo()

   2.3 定义函数的三种形式

#1.无参函数
def foo():
    print ('from foo')

foo()

#使用场景:
#需求:用户在选择界面选择不同ATM的功能,进入对应的函数(简单实现)
def repay():
    print ('我是支付功能')

def check():
    print ('我是查询功能')

def transfer():
    print ('我是转账功能')
def run():
    for i in func_dic:
        print (i  ,func_dic[i][0])

    choice=input('>>>:').strip()
    func_dic[int(choice)][1]()  #执行对应的功能函数

func_dic={
    1:['支付',repay],
    2:['查询',check],
    3:['转账',transfer],
}
if __name__ =="__main__":
    run()
#2.有参函数
def bar(x,y):
    print (x,y)

bar(1,2)

#举例
#需求:比较俩个数大小
def max2(x,y):
    if x >y:
        print (x)
    else:
        print (y)

max2(20,30)   
#3.空函数
def foo(x,y):
    pass

#使用场景:当写项目时,有了整体框架,但是还没细写功能,可先定义空函数

 

三、函数的调用

  三种调用方式:

  3.1语句形式

def foo():
    print ('from foo')

foo()    #语句形式

  3.2表达式形式

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

salary= max2(3000,2000)    #表达式形式
annual_salary = salary * 12
print (annual_salary)

  3.3返回值当做参数传给另一个函数

#找出一个1,2,3最大的值
def max2(x,y):
    if x>y:
        return x
    else:
        return y

res= max2(max2(3,2),1)    #函数返回值当参数传递
print (res)

四、函数的返回值return

  4.1特点:

return 是函数结束的标志,函数内可以有多个return,但是只要执行一个,函数就立即结束,并且把return后的值当做本次调用的结果
def foo():
    print ('first')
    return 1
    print ('second')    #以下语句都不会被执行
    return 2
    print ('third')
    return 3

res = foo()
print (res)

  4.2 返回值注意事项:

#1.返回值没有类型限制
def bar():
    return {'x',1}    #可以为任意类型,如字符串,字典,函数,列表等等

print (bar())


#2. 返回值没有个数限制,可以用逗号分开多个值,一次返回
def bar():
    return (1,'hello',{'x':1})    #以元组tuple形式返回

x,y,z = bar()
print (x,y,z)

#3.可以没有return,默认返回None def bar(): pass res = bar() #无返回值,返回None print (res)

 

五、函数的参数

  5.1 函数的参数分为两大类:形参和实参

#形参:指的是在定义函数时括号定义的参数,形参即变量名
def foo(x,y):    #x=1,y=2
    print (x,y)
#实参:指的是在调用函数时括号内传入的值,实参即变量值
foo(1,2)

#在调用时,实参的值会传给形参,可以理解为这是一个赋值操作

  5.2 函数参数

     5.2.1位置参数

#1.在定义函数时,按照从左到右的顺序依次定义的参数,称为位置形参
#特性:位置形参必须被传值,多一个不行少一个也不行
def foo(x,y,z):
    print (x,y,z)


#2.在调用函数时,按照从左到右的顺序依次传入的值,称为位置实参
#特点:与形参一一对应

foo(1,2,3)
foo(1,2)    #报错
foo(1,2,3,4)    #报错

    5.2.2关键字实参

#1.在调用函数时,按照key=value的形式定义的实参,称为关键字参数
#特点:可以完全打乱顺序,但仍然能指名道姓为指定的参数传值
def foo(x,y,z):
    print (x,y,z)

foo(z=3,x=1,y=2,)

#2.位置实参与关键字实参可以混合使用,规则
##2.1位置参数一定放在关键字参数的前面
##2.2同一个形参只能被赋值一次

foo(1,2,z=3)    #正常
foo(1,y=2,3)    #报错,不符合2.1
foo(1,y=2,x=4)    #报错,不符合2.2

    5.2.3默认参数

#默认参数:在定义函数时,就已经被赋值的参数,称为默认形参
#有以下三个特征:
#1.在定义阶段就已经被赋值,意味着在调用阶段就可以不用传值
def foo(x,y=10):
    print (x,y)

foo(1)
foo(1,3)
foo(y=4,x=1)

#2.默认参数必须跟在位置形参的后面
def foo(y=1,x):    #定义函数阶段就会报错
    pass

#3*.默认参数的值只在定义阶段被赋值一次就固定死了,定义之后改变没有影响
m=10
def func(x,y=m):    #定义阶段10赋值为y
    print (y)

m=111
func(1)


#4*.默认参数的值应该设置成不可变类型
#举例:如果想要将每个人的爱好存到各自的列表中,就不能将默认参数l设置成列表
#错误做法:不会报错,需求达不到预期
def func(name,hobby,l=[]): #['read','play']
    l.append(hobby)
    print (name.l)

func('lisl','read')
func('zhangsan','play')
func('lixi','eat')

#正确做法
def func(name,hobby,l=None):
    if l is None:
        l=[]
    l.append(hobby)
    print(name,l)
func('lisl','read')
func('zhangsan','play')
func('lixi','eat')



#位置形参与默认参数的应用:
##1 大多数场景值都固定不变则需要定义成默认参数
##2 大多数场景值需要改变则需要定义成位置形参
#eg1:
def register(name,password,gender='male'):
    print(name)
    print(password)
    print(gender)


register('lisl','123',)
register('xiaohong','123','female')

    5.2.4 可变长参数

#指的是在调用函数时,传入的实参个数可以不固定
#而实参无非两种形式:1 位置实参 2.关键字实参
#所以对应的形参也必须对应俩种解决方案,专门用于接收溢出位置实参和溢出的关键字实参

#*:接收溢出的位置实参,存在元组形式,然后赋值给*后面跟的那个变量名
##用法1:在形参中用*
def foo(x,y,*z):    #z=(3,4,5)
    print (x,y)
    print (z)

foo(1,2,3,4,5)
foo(1,2,3,4,5,y=20)    #报错,2已经传给y,y=20重复赋值报错

##用法2:在实参中用*
def foo(x,y,*z):
    print (x,y)
    print (z)
foo (1,2,*(3,4,5))    #foo(1,2,3,4,5)  实参*是拆分元组元素
foo(1,2,*'abc')    #foo(1,2,'a','b','c')

#**:接收溢出关键字实参,存在字典形式,然后赋值给**后面跟的那个变量名
##用法1:在形参中用**
def foo(x,y,**z):    #z={'b': 3, 'c': 4, 'a': 2}
    print (x,y)
    print (z)
foo(1,a=2,b=3,c=4,y=5)

##用法2:在实参中用**
def foo(x,y,**z):
    print (x,y)
    print (z)
foo(1,**{'a':2,'c':3})    #foo(1,a=2,c=3) 实参**是拆分字典的key=value为关键字参数

六、函数嵌套

  

#1.函数的嵌套调用
def max2(x,y):
    if x >y:
        return x
    else:
        return y

def max4(x,y,m,n):
    res1=max2(x,y)
    res2=max2(res1,m)
    res3 =max2(res2,n)
    return res3

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


#2.函数的嵌套定义
def  f1():
    print ('from f1')
    def f2():
        print ('from f2')
        def f3():
            print ('from f3')
        f3()
    f2()

f1()

七、名称空间与作用域

  7.1什么是名称空间

#存放名字与值绑定关系(内存地址)的地方

问:如何查看名称空间的值
答:dir(),将dir()放置在全局可查看全局名称空间的值,放在局部可查看局部名称空间的值,要放在最后一行。dir()不加参数,加了参数则查的是对应对象的所有属性

__dict__与dir()的区别:
    #1.dir()是一个函数,返回的是list
    #2.__dict__是一个字典,键为属性名,值为属性值
    #3.dir()用来寻找一个对象的所有属性,不加参数代表是所在空间的名称,包括__dict__中的属性,__dict__是dir()的子集

 

 

  7.2名称空间的分类

#1.内置名称空间
    存放python解释器自带名字,比如内置的函数名:len,max,sum
    创建:随着python解释器启动而创建
    销毁:随着python解释器关闭而销毁

#2.全局名称空间
    存放文件级别的名字,比如x,f1,z
    x=1
    def f1():   #定义阶段f1也属于全局名称空间        
        y=w
    创建:文件开始执行时则立即创建
    销毁:文件开始执行完毕时销毁

#3.局部名称空间
    存放函数内的名字,强调函数的参数也属于局部的
    创建:函数执行时才临时创建
    销毁:函数执行完毕则立即销毁
    def f1():
        x=1    #局部名称空间
        y=2

    f1()

  7.3名称空间的加载顺序

内置名称空间---》全局名称空间---》局部名称空间

注意:加载的目的是为了把名字存起来,然而存起来的目的就是为了取,
那么但凡查找一个名字一定会从三种名称空间之一找到

  7.4名称空间的查找名字顺序

局部名称空间---》全局名称空间---》内置名称空间


len =10
def f1():
    len =100
    def f2():
        len =100
        def f3():
            len=10000
            print (len)
        f3()
    f2()

f1()    #结果10000

 7.5 特性:名字的查找关系是在函数定义阶段就已经固定死的,与调用位置无关

x =100
def f1():
    print (x)

def f2():
    x=1111
    f1()

f2()        #结果为100

   7.6 作用域:域=范围

#1.全局范围:内置名称空间中的名字,全局名称空间的名字
#特点:全局有效,全局存活


#2.局部范围:局部名称空间中的名字
#特点:局部有效,临时存活


#定义在全局作用域的名字称为全局变量
#定义在局部作用域的名字称为局部变量
len=10    #全局变量
def f2():
    print (len)    #局部变量
    def f3():
        print (len)    #局部变量
    f3()

##############################
x=10
print (globals())    #查看全局作用域中的名字,结果包含'x':10
print (locals() is globals())    #结果:True,在全局作用域的局部变量就是全局变量

def f1():
    y = 2
    z = 3
   print (locals())    #结果{'z': 3, 'y': 2},为函数内的局部变量
f1()

    7.7 global与nonlocal 关键字

#一般情况下函数里的局部变量是无法影响到全局变量的,除非全局变量是可变类型,如:列表,字典,集合
#例1:
s='hello'    #不可变类型有数字,字符串,元组
def foo():
    s='hello world'

foo()
print (s)    #结果‘hello’

#例2:
l=[]    #空列表
def foo():
    l.append('aa')
foo()
print (l)    #结果['aa']

#global
#特殊情况下,需要将局部变量定义成全局变量(不建议)
x=10
def foo():
    global x
    x=100
foo()
print (x)        #结果100


#nonlocal
#定义:会从当前外一层开始查找一直找到最外层的函数,如果没有就报错
def f1():
    x=10
    def f2():
        def f3():
            nonlocal x
            x=11
        f3()
    f2()
    print (x)    #结果11
f1()
#print (x)    #报错,因为x变量全局没有定义

八、函数对象

  8.1 函数对象定义:

#函数可以当做变量去处理

  8.2函数对象的用法:

#1.可以被赋值
def foo()
    print ('from foo')

f=foo
print (f)    #打印的是函数的内存地址


#2.可以当做参数传给一个函数
def foo():
    print ('from foo')

def bar(func):
    print (func)    #打印函数地址
    func()            #执行函数

bar(foo)


#3.可以当做函数的返回值
def foo():
    print ('from foo')

def bar(func):
    return func

f=bar(foo)    #返回函数foo的内存地址赋值给f
print (f)


#4.可以当做容器类型的元素
def foo():
    print ('from foo')

l=[foo,]
print (l)
l[0]()    #执行foo函数

#需求1:打造用户选择界面
def get():
    print ('使用下载功能')

def put():
    print ('使用上传功能')

def ls():
    print ('显示当前列表')
def login():
    pirnt ('用户登录')

func_dic={
    "1":[get,'下载'],
    "2":[put,'上传'],
    "3":[ls,'浏览'],
    "4":[login,'登录'],
}
for i,k in func_dic.items():
    print (int(i),'  ',k[1])

choice=input('>>:')
if choice =='q':break
if choice in func_dic:
    func_dic[choice][0]()

九、闭包函数

  闭包函数就是:函数嵌套+名称空间与作用域+函数对象

  9.1 什么是闭包函数

#1.定义在函数的内函数
#2.该函数体代码包含对该函数外层作用域中名字的引用
    强调:函数外层指的不是全局作用域
#满足上述两个条件,那么该内部函数就称之为闭包函数

#例子:
def outter():
    x=1
    def inner():
        print (x)
    return inner    #利用函数对象的概念,将一个内部函数返回并在全局中拿到使用,从而打破函数的层级限制

f=outter()    #f=inner
print (f)
f()

  9.2 为函数体传值的方式

#方式一:以参数的形式为函数体传值
import requests    #pip3 install requests

def get(url):
    response=requests.get(url)
    if response.status_code ==200:
        print (response.text)

get('https://www.python.org')    #每次都需要将url传进函数
get('https://www.python.org')


#方式二:包给函数,(方便,推荐)
def outter(url):
    def get():
        response=requests.get(url)
        if response.status_code ==200:
            print (response.text)
    return get

python = outter('https://www.python.org')    #相同网站只需一次传值
python()
python()

十、装饰器

  10.1 开放封闭原则

#软件一旦上之后就应该开放封闭原则
#具体是指修改是封闭的,但对扩展是开放的

  10.2 什么是装饰器

#装饰就是修饰,器指的就是工具
#装饰器本身可以是任意可调用的对象
#被装饰的对象也可以是任意可调用的对象

装饰器----》函数
被装饰的对象----》函数

#装饰器是用来为被装饰对象添加新功能的一种工具
#必须遵循:
    1.不能修改被装饰对象的源代码
    2.不能修改被装饰对象的调用方式

  10.3 举例

import time

def index():
    time.sleep(1)
    print ('welcome to index')

def outter(func):
    def wrapper():
        start_time = time.time()
        func()
        stop_time = time.time()
        print ('run time is %s'%(stop_time-start_time))
    return wrapper

index = outter(index)    #index=wrapper
index()
View Code

 

import time
def index():
    time.sleep(1)
    print ('welcome to index')
    return '我是返回值'    #定义有返回值

def outter(func):
    def wrapper():
        start_time=time.time()
        res = func()
        stop_time = time.time()
        print ('run time is %s'%(stop_time-start_time))
        return res    #定义有返回值
    return wrapper

index=outter(index)    #index=wrapper
res=index()    #res=wrapper()
print ('返回值:',res)
有返回值装饰对象
def home(name):
    time.sleep(1)
    print ('welcome %s to home page'%name)

def outter(func):
    def wrapper(*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 wrapper

home=outter(home)    #home=wrapper
home('lisl')    #wrapper('lisl')
有参被装饰对象

  10.4装饰器语法糖

#在被装饰器对象正上方单独一行写@装饰器的名字
def  timmer(func):
    def wrapper(*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 wrapper

@timmer
def index():
    time.sleep(1)
    print ('welcome to index')
    return 1234

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

index()
home('lisl')

 

#例子:检测用户是否登录,没有要求登录在使用功能
import time
current_user = {'login':False}

def outter(func):
    def wrapper(*args,**kwargs):
        if current_user['login']:
            return func(*args,**kwargs)

        user=input('username>>>:').strip()
        pwd = input('password>>>:').strip()
        if user =='lisl' and pwd=='123':
            current_user['login']=True
            return func(*args,**kwargs)
    return wrapper

@outter
def index():
    time.sleep(1)
    print ('welcome to index')
    return 1234

@outter
def home(name):
    time.sleep(2)
    print ('welcome %s to home page'%name)

index()
home('lisl')

 

10.5 有参装饰器

import time
current_user={'login':False}

def auth(engine):
    def outter(func):
        def wrapper(*args,**kwargs):
            if current_user['login']:
                return func(*args,**kwargs)
            
            user=input('username>>>:').strip()
            pwd =input('password>>>:').strip()
        
            if engine =='file':
                if user =='lisl' and pwd=='123':
                    current_user['login'] =True
                    return func(*args,**kwargs)
            elif engine =='mysql':
                print ('基于mysql认证')
            elif engine =='ldap':
                print ('基于ldap的认证方式')
        return wrapper
    return outter

@auth(engine='mysql')    #@outter    #index=outter(index)
def index():
    time.sleep(1)
    print ('welcome to index')
    return 1234

@auth(engine=='ldap')
def home(name):
    time.sleep(2)
    print ('welcome %s to home page'%name)

index()
home('lisl')

十一、匿名函数

  11.1 匿名函数格式

#匿名函数
lambda x,y:x+y

#普通函数
def func(x,y):
    return x+y

  11.2 使用匿名函数注意事项

#1.不会单独使用,会与其他函数配合使用
#2.匿名函数的精髓在于没有名字,如果没有名字意味用一次就立即回收,所以,匿名函数的应用仅应用于值使用一次的场景

  11.3 与匿名函数配合较多的内置函数:max,min,sorted,filter,map

salaries={
    '唐三':2000,
    '王东':40000,
    '张三':3000,
    '戴沐白':2500,
}

#求出最大工资的那个人名
print('工资最多的人:',max(salaries,key=lambda x:salaries[x]))

#求出工资最低的人名
print ('工资最少的人:',min(salaries,key=lambda x:salaries[x]))

#按照薪资排序,从小到大排
print(' < '.join(sorted(salaries,key=lambda x:salaries[x])))

#需求:将每个元素都加上"_唐门"
#方法一:map与lambda配合使用:
names=['唐三','小舞','唐昊','胖子','戴沐白']
g=list(map(lambda x:x+'_唐门',names)) #map()返回的结果是一个迭代器,(第四章会学)
print (g)

#方法二:
names=['唐三','小舞','唐昊','胖子','戴沐白']
names=[x+'_唐门' for x in names]
print (names)


#需求:将列表里的_唐门去除掉
#方法一:filter与lambda配合使用
names=['唐三_唐门', '小舞_唐门', '唐昊_唐门', '胖子_唐门', '戴沐白']
# filter会得到names的迭代器对象obj,然后next(obj)将得到的值传给filter第一个参数指定的函数,将函数返回值为True的那个值留下
g=filter(lambda x:x.endswith('_唐门'),names)
print (list(g))

#方法二:列表生成式(第四章会学)
names=['唐三_唐门', '小舞_唐门', '唐昊_唐门', '胖子_唐门', '戴沐白']
names=[x for x in names if x.endswith('_唐门')]
print (names)
匿名函数与内置函数配合应用

 

十二、内置函数

  12.1 isinstance(obj,cls)  判断类型

l=list([])
print (isinstance(l,list))  #判断l是否是列表

  12.2 issubclass(sub,super)  #判断子类

class Father:   #父类
    pass

class Children(Father): #子类
    pass

class Grandson(Children):   #孙类
    pass

print (issubclass(Grandson,Father)) #孙类是父类的子类,返回True

 

posted @ 2018-04-25 23:35  森林326  阅读(313)  评论(0编辑  收藏  举报