Frank的学习之路

Day_4_总结_函数参数的使用

今日内容:

1、  函数参数的使用

2、  函数对象

3、  函数嵌套

4、  名称空间与作用域

5、  闭包函数

6、  装饰器

课程复习:

1、  什么是函数

函数就是具备某一功能工具

2、  为何用函数

1、  增强程序的组织结构,可读性

2、  减少代码冗余

3、  可扩展性

3、  如何用函数

函数分为两大类:

内置函数

自定义函数

                            有参

                            无参

                            空函数

定义语法:

         def 函数名(参数1,参数2…:

         ‘’’

         文档注释

         ‘’’

         code1

code2

return 返回值

调用函数的语法:

函数名(1,2,3

函数的使用必须遵循原则:

         先定义,后使用

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

在调用阶段:通过函数名找到函数,执行函数体代码

函数名:是用来访问函数的内存地址,拿到函数的内存地址加括号就可以触发函数体代码执行

函数参数:外部调用者为函数体传值的媒介

函数体代码:是函数功能的具体实现

return 函数的返回值

                   函数的返回值是函数体执行的成果

1、  返回值没有类型限制

2、  返回值没有个数限制

没有return,默认返回值None

return1:返回值1

return1,值2,值3:返回(值1,值2,值3

return注意点:

         return是函数结束运行的标志,函数体内可以有多个return

         但是只执行一次,整个函数终止运行

一、             函数的参数

1、  函数的参数分为两大类:形参与实参

形参:指的是定义函数时,括号内指定的参数,本质是变量名

实参:指的是在调用函数时,括号内传入的值,本质是值

只有在调用函数时才会在函数体内发生实参(值)与形参(变量名)绑定关系

改绑定关系只在调用函数时临时生效,在调用函数结束后就解除关系

2、  位置参数:

位置形参:在定义函数时,按照从左到右的顺序定义的形参称为位置形参

           注意:

1、按照位置定义的形参,在调用函数时必须为其传值,多一个少一个都不行

                   

位置实参:在调用函数时,按照从左到右的顺序依次传入的值

           注意:

1、  在传值时按照顺序与形参一一对应

关键字实参:

         在调用函数时,按照key=value的形式的实参,称之为关键字实参

                   注意:

1、  在传值时可以完全打乱顺序,但仍然能给目标的参数传值

2、  可以在调用函数时,混合时位置实参和关键字实参,但位置实参必须在关键字实参的左边,并且不能为一个形参重复传值

# def register(name,sex,age):

#     print(name)

#     print(sex)

#     print(age)

#

# register('frank',age=18,sex='male')

执行结果:


3、默认参数:

                   在定义函数时,就已经为某些参数绑定值,称之为默认参数

                            注意:

1、  在定义阶段就已经有值,在调用阶段可以不用为其传值

# def foo(x,y,z=3):

#     print(x)

#     print(y)

#     print(z)

# foo(1,2)

执行结果:

2、  默认形参必须放到位置形参后面

#def register(name,age,sex='male'):

#     print(name)

#     print(sex)

#     print(age)

#

# register('frank',age=18)

# register('cxx',age=28,sex='female')

执行结果:

3、  默认形参的值只在定义阶段生效一次,在函数定以后发生的改动无效

# m=100

# def foo(x,y,z=m):

#     print('x:%s' %x)

#     print('y:%s' %y)

#     print('z:%s' %z)

# m=200

# foo(1,2)

执行结果:

4、  默认形参的值通常是不可变的类型

位置形参vs默认形参

         默认形参:大多数情况下值都一样

         位置形参:大多数情况下值都不一样

        

5、  可变长度的参数:

可变长度指的是在调用函数时,函数的参数个数可以不固定

然而实参需要给形参传值,针对两种形式的实参个数不固定,对应的形参也需要有两种解决方案*,**来分别来处理溢出的位置实参和溢出的关键字实参

1*会将溢出的位置实参组成元组,然后赋值给紧跟其后的变量名

1.1 形参中带*

# def foo(x,y,*args): #args=(3,4,5,6)

#     print(x)

#     print(y)

#     print(args)

# foo(1,2,3,4,5,6)

执行结果:

1.2 形参中带*,实参中带*,窍门:实参中带*,先将其理解为单个位置实参,然后考虑传值

                                                        # def foo(x,y,*args): #args=(3,4,5,6)

#     print(x)

#     print(y)

#     print(args)

# foo(1,2,[3,4,5,6])

# foo(1,2,*[3,4,5,6])

执行结果:

# foo(1,*[3,4,5,6])

执行结果:

# def foo(x,y,z):

#     print(x,y,z)

# l=['frank','sunny','franksunny']

# foo(*l) #foo('frank','sunny','franksunny')

执行结果:

**会将溢出的位置实参组成字典,然后赋值给紧跟其后的变量名

# def foo(x,y,a,**kwargs): #args={'a': 1, 'b': 2, 'c': 3}

#     print(x)

#     print(y)

#     print(a)

#     print(kwargs)

# foo(1,2,a=4,b=5,c=6)

执行结果:

#1.2形参中带**,实参中带**,窍门:实参中带**,先将其理解为单个关键字实参,然后考虑传值

# def foo(x,y,**kwargs):

#     print(x,y,kwargs)

# foo(1,2,**{'a':1,'b':2,'c':3}) #foo(1,2,a=1,b=2,c=3)

# foo(1,**{'y':3,'b':4,'c':5}) #foo(1,y=1,b=2,c=3)

执行结果:

#如果我们的需求是

#需要将外层的函数参数格式原封不动转嫁给内部调用函数,需要使用到下面形式

# def index(name,age,sex):

#     print('name:%s age:%s sex:%s' %(name,age,sex))

#

# def wapper(*args,**kwargs): #注释args=('frank') kwargs={'sex':'male','age':18}

#     index(*args,**kwargs)

#     # 注释:

#     #     index(*('frank'),**{'sex':'male','age':18})

#     #     index('frank',sex='male',age=18)

# wapper('frank',sex='male',age=18)

          

执行结果:

我们虽然调用warpper函数,但我们遵循的其实是index函数的参数规则

# def foo(x,y=100,*args,m,**kwargs):

#     print(x,y,args,m,kwargs)

# foo(1,2,3,4,5,6,m=200,a=11,b=22)

执行结果:

常用使用方式:

# def foo(x,y):

#     pass

#

# def  foo(x,y=1):

#     pass

#

# def warpper(*args,**kwargs):

#     index(*args,**kwargs)

#

# def foo(x,*args):

#     pass

#

# def foo(x,**kwargs):

#     pass

用函数求和需求:

# def my_sum(*args):

#     res=0

#     for item in args:

#         res+=item

#     return res

# print(my_sum(1,2,3))

二、             函数对象

#函数是第一类对象,意味函数可以当做数据去使用

#1、可以被引用

#2、可以当作参数传给另外一个函数

#def foo():

#     print('from foo')

#

# print(foo)

# func=foo

# print(func)

# func()

#

# def bar(x):

#     print(x)

#     x()

# bar(foo)

#3、可以当作函数的返回值

         # def foo():

#     print('from foo')

#

# def bar():

#     return foo

# f=bar()

# print(f is foo)

# f()

#4、可以当作容器元素

#def f1():

#     print('from to f1')

#

# def f2():

#     print('from to f2')

#

# l=[f1,f2]

# print(l)

# l[0]()

def pay():

#     print('pay function')

#

# def withdraw():

#     print('withdraw function')

#

# def auth():

#     print('auth function')

#

# def shopping():

#     print('shopping function')

#

# def transfer():

#     print('transfer function')

#

# func_dic={

#     '1':pay,

#     '2':withdraw,

#     '3':auth,

#     '4':shopping,

#     '5':transfer

# }

#

# while True:

#     print('''

#     0’:‘退出’

#     1’:‘支付’

#     2’:‘取款’

#     3’:‘认证’

#     4’:‘购物’

#     5’:‘转账’

#     ''')

#     chocie=input('请输入您的指令:').strip()

#     if chocie=='0':break

#     if chocie  not in func_dic:continue

#     func_dic[chocie]()

三、             函数嵌套

#函数的嵌套调用:在调用一个函数时,其内部代码又调用其他函数

# def bar():

#     print('from to bar')

#

# def foo():

#     print('from to foo')

#     bar()

# foo()

# def max2(x,y):

#     if x>y:

#         return x

#     else:

#         return y

# def max4(a,b,c,d):

#     res=max2(a,b)

#     res1=max2(res,c)

#     res2=max2(res1,d)

#     return res2

#

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

#函数的嵌套定义:在一个函数内部又定义另外一个函数

#def f1():

#     x=1

#     def f2():

#         print('from to f2')

#     f2()

# f1()

# print(f1)

四、名称空间与作用域

1、  什么是名称空间

名称空间是存放名字与值绑定关系的地方

要取到值必须通过名字才能找,而名字在名字空间存放着,所以我们在取值时首先去名称空间找名字,找到名字自然拿到值得内存地址

2、  名称空间分为三种:

a)         、内置名称空间:存放的python解释器自带的名字

在解释器启动时产生,在解释器关闭是回收

b)         、全局名称空间:除了内置的与局部的之外的名字都属于全局名称空间

生命周期:在程序文件执行时就立刻产生,在程序执行完毕后立即回收

其中:x,y,foo,z都是全局名称空间中的名字

# x=1

# y=2

# def foo():

#     x=1

#     y=2

# foo()

#

# if y>x:

#     z=3

c)         、局部名称空间:存放的是函数内部定义的名字

生命周期:在调用函数时临时生效,在函数结束后立刻回收

                   加载顺序:内置名称空间---》全局名称空间---》局部名称空间

                   加载名称空间的目的是为了将名字与值的绑定关系存放起来,

                   存的目的是为了取,也是说,当我查找名字时,必然在三者之一找到

# len=100

# def foo():

#     len=10

#     print(len)

# foo()

                   查找顺序:局部名称空间》全局名称空间---》内置名称空间

                   基于当前所在的位置往后查找

强调:函数的形参名属于局部名称空间

# x=100

# y=200

# def foo(x,y):

#     print(x,y)

# foo(1,2)

执行结果:

# X=222

def f1():

    #x=1

    def f2():

        #x=2

        print('from f2',x)

    f2()

x=111

f1()

d)、作用域

         域指的是范围,作用域指的是作用范围

         分为:

                   全局作用域范围:包含内置名称空间与全局名称空间中的名字

                            特点:全局有效,全局存活

                   局部作用域范围:包含的局部名称空间的名字

                            特点:局部有效,临时存活

                            #x=1

# def f1():

#     def f2():

#         def f3():

#             # x=3

#             print(x)

#         f3()

#     f2()

# f1()

# 了解:globalslocals

# x=111

# def foo():

#     y=2

# print(globals()) #返回的是全局名称空间的名字

# print(dir(globals()['__builtins__']))#返回的是全局作用域的名字

# print(locals() is globals())

#如何打破函数层级带来的访问的限制,让我在任意位置都可以访问到一个内部函数

#基于函数对象的概念将一个函数内部函数返回到全局使用,从而打破层级限制

#函数作用域的关系是在函数定义阶段已经固定了,与函数调用位置无关

#即在调用函数时一定要到定义函数的位置寻找作用域关系

# x=11

# def outter():

#     # x=333

#     def inner():

#         print('from inner',x)

#     return inner

#

# f=outter() #f=指向outter.<locals>.inner

# print(f)

#

# def foo():

#     x=222

#     f()

# x=444

# foo()

# x=[]

# def func():

#     x.append(1)

# func()

# print(x)

# globals:在局部申明名字是全局的

# x=1

# def func():

#     global x

#     x=2

# func()

# print(x)

执行结果:

# x=222

# def f1():

#     x=111

#     def f2():

#         global x

#         x=0

#     f2()

#     print('------>',x)

# f1()

# print(x)

# nonlocal :申明变量是来自与当前层的外层(必须是函数内)

# x=222

# def f1():

#     x=111

#     def f2():

#         nonlocal x

#         x=0

#     f2()

#     print('------>',x)

# f1()

# print(x)

执行结果:

#函数的作用域是在函数在定义阶段就固定了,与调用位置无关

五、             闭包函数

1、  闭指定义在函数的内部的函数

2、  包指该内部函数包含对外层函数作用域名字的引用

3、  闭包函数通常需要结合函数对象的概念,将闭包函数返回到外部使用

# def outter():

#     x=100

#     def inner():

#         print(x)

#     return inner

# f=outter()

# f()

 

# def foo():

#     def bar():

#         x=300

#         f()

#     bar()

# foo()

执行结果:

闭包函数的基本形式:

# def outter(x):

#     def inner():

#         print(x)

#     return inner

爬虫使用的模块:pip3 install requests

# 通过参数的形式为函数传值

# import  requests

# def get(url):

#     response=requests.get(url)

#     print(len(response.text))

# get('https://www.baidu.com/')

#将包传给函数

# def outter(url):

#     #url='https://www.baidu.com/'

#     def get():

#         response = requests.get(url)

#         print(len(response.text))

#     return get

#

# bd=outter('https://www.baidu.com/')

# bd()

执行结果:

六、             装饰器

1、  什么是装饰器

装饰是指被装饰的对象增加新的功能

器是指工具

装饰器本身可以任意调用的对象,被装饰的对象也是任意可调用对象

目标:写一个函数为另外一个函数添加新的功能,需要遵循开放封闭原则(对修改是封闭的,对扩展是开放的)

1、  不修改被装饰对象的源代码

2、  不修改被装饰对象的调用方式

import time

# def index():

#     time.sleep(3)

#     print('welcome to index page')

# # index()

# def outter(func): #func=最原始的index

#     def wrapper():

#         start=time.time()

#         func() #最原始的index

#         stop=time.time()

#         print('run time is %s' %(stop - start))

#     return wrapper

# index=outter(index) #index=wrapper

# index() #wrapper

#import  time

# def index():

#     time.sleep(0.5)

#     print('welcom to index page')

#     return 1234

#

# def home(name):

#     time.sleep(1)

#     print('welcome %s to home page ' %name)

#

# def timmer(func):

#     def wrapper(*args,**kwargs):

#         start=time.time()

#         res=func(*args,**kwargs)

#         stop=time.time()

#         print('run time is %s' %(stop -start))

#         return  res

#     return wrapper

# index=timmer(index)

# home=timmer(home)

# res=index()        #wrapper()

# print(res)

# home('frank') #wrapper('frank')

装饰器的语法糖:在被装饰对象的正上方单独一行写上@装饰器的名字

#import  time

# def timmer(func):

#     def wrapper(*args,**kwargs):

#         start=time.time()

#         res=func(*args,**kwargs)

#         stop=time.time()

#         print('run time is %s' %(stop -start))

#         return  res

#     return wrapper

# @timmer #index=timmer(index)

# def index():

#     time.sleep(0.5)

#     print('welcom to index page')

#     return 1234

# @timmer # home=timmer(home)

# def home(name):

#     time.sleep(1)

#     print('welcome %s to home page ' %name)

#

# # index=timmer(index)

# # home=timmer(home)

# res=index()        #wrapper()

# print(res)

# home('frank') #wrapper('frank')

返回顶部