day11函数对象,函数嵌套,名称空间与作用域,闭包函数

今日内容:
1. 函数对象(*****)
2. 函数嵌套(*****)
3. 名称空间与作用域(******)
4. 闭包函数(****)
5. 内置函数



 

 

# 命名关键字参数: 在定义函数时,*与**之间的参数称之为命名关键字参数。
# 特点:
# 在调用函数时,命名关键字参数必须按照key=value的形式传值。
#
表现形式一:
# def func(x,*,y=1,z): #单独一个*号不接受传值。
# print(x)
# print(y)
# print(z)
#
# func(1,z=2)

表现形式二:
def func(a,b=2,*args,c,**kwargs):
print(a)
print(b)
print(args)
print(c)
print(kwargs)



一。函数对象

# 函数是第一类对象: 指的是函数的内存地址可以像一个变量值一样去使用。

def foo(): #函数定义阶段实质是发生了什么?:函数名foo=函数的内地址。
print('from foo')

变量值可以怎么使用?
# 1. 变量值可以被引用。
# x=1
# y=x
#定义函数:foo=函数的内地址
f=foo #这步是传引用。
# print(f)
# f()

#2. 变量值可以当作参数传给另外一个函数。
# def bar(x):
# print(x)
# x()
#
# x=11111 #foo=函数的内存地址
# # bar(x)
# bar(foo)

#3. 变量值可以当作函数的返回值。
# def func(x):
# return x
#
# f=func(foo)#要认识到这句实质是将函数返回值赋值给变量名f。
# print(f)

#4. 变量值可以当作容器类型的元素。
# l=[foo,]
# print(l)
# l[0]()

# dic={'1':foo}
# print(dic)
# dic['1']()

应用于:购物题目中代替重复的elif判断语句,变得简洁。
def register():
print('注册....')

def login():
print('登录....')

def pay():
print('支付....')

def transfer():
print('转账....')

func_dic={
'1':register,
'2':login,
'3':pay,
'4':transfer
}

# func_dic['1']()

while True:
print("""
0 退出
1 注册
2 登录
3 支付
4 转账
""")
choice=input('请输入你的操作: ').strip()
if choice == '0':break

if choice not in func_dic:
print('输错的指令不存在')
continue
   func_dic[choice]()




二。函数嵌套,
分为1函数嵌套调用,2函数嵌套定义。
# 1.函数的嵌套调用:是在一个函数内部又调用其他函数。

例子:给任意4个数字算出最大值。

# def max2(x,y):
# if x > y:
# return x
# else:
# return y
#
# def max4(a,b,c,d):
# res1=max2(a,b)
# res2=max2(res1,c)
# res3=max2(res2,d)
# return res3
#
# print(max4(1,2,3,4))

由此例可得:函数嵌套调用常应用于把大问题分解为小问题,然后实现小问题功能,最后函数嵌套调用解决大问题。

# 2.函数的嵌套定义: 是在函数内部又定义了其他函数。

# def func():
# def foo():
# print('from foo')
# # print(foo)
# foo()
# x=1
# print(x)

# func()

例子:用户给出圆半径,可以自己选择计算面积还是计算周长。
from math import pi

def circle(radius,action):
def cal_perimeter():
return 2 * pi * radius

def cal_area():
return pi * (radius ** 2)

if action == 1:
res=cal_perimeter()
elif action == 2:
res=cal_area()
return res

res=circle(10,1)
print(res)
由此可得:函数嵌套定义常应用于程序员可以把一个事物的相关功能打包起来,让用户选择执行什么功能。



三。名称空间与作用域
'''
一 名称空间相关
1. 名称空间Namespaces:指的就是存放名字与值的内存地址绑定关系的地方(内存空间)。
(名字具体可分为:变量名、函数名)
x=1
定义变量(底层)实质发生了什么?
先申请内存空间存变量值,然后申请内存空间存名字与值内存地址的绑定关系。如下图:


2. 名称空间分为三大类
  2.1内置名称空间: 存放的是python解释器自带的名字。
产生:python解释器的启动则产生。
销毁:python解释器关闭则销毁。

  2.2全局名称空间: 存放的是在顶级(即无缩进)定义的 和 在循环、判断下子代码块或循环判断嵌套里定义的名字。
eg x=1

eg if True:
y=2

eg while True:
while True:
while True:
z=3
eg def func():
pass

产生:执行python程序=执行py文件时产生。
销毁:python程序执行完毕=py文件下的代码执行完毕后则销毁。


  2.3局部名称空间: 存放的是在函数内部定义的名字。何为函数内部??? 在子代码块里即在函数内部。
复习调用函数实参给形参传值的过程,相当于在子代码块定义了形参变量。

def foo():
m=100

foo()
产生: 在函数调用时临时产生。
销毁: 在函数调用完毕(即函数运行完毕)后则销毁。


三种名称空间的产生的先后顺序: 内置->全局->局部

1.# len=111
# def foo():
#
# print(len)
#
# foo()

2.# def foo():
#
# print(len)
# len=111
# foo()

3.# def foo():
# q()
# print(111)

#def q():
#  print(222)

# foo()
 
由上可知:函数中,站在局部用变量名而找它时,定义变量语句不一定在使用变量名上面才能找到,主要看函数调用语句是否在变量定义代码下面。
例3是站在局部用函数名而找它,原理同上。
而在同层级中顶级或子代码块中,用到变量名时,定义语句一定要在使用语句上面。

查找名字的顺序:从当前位置往外一层一层查找。己理解:当前位置指的是当前所面对名字的所在位置。
如果当前在局部名称空间: 局部名称空间->全局名称空间->内置名称空间
如果当前在全局名称空间: 全局名称空间->内置名称空间

师:需要注意的是:在全局(即在顶级或判断循环中)无法查看(即访问到值)局部变量(例如顶级写print(局部变量名)),
在局部可以查看(即访问到值)全局变量(例如在函数子代码块里print(全局变量名),还可用全局变量作为函数子代码块里表达式的一部分),但在局部不能更改全局变量名的值eg书page98。
正确版是day12写的:如何在局部更改全局变量?要改全局变量名的值,要在全局才能更改。在全局即在顶级或判断循环中。
更改变量名的值表现形式是 赋新值给变量名。变量名人们常常叫做变量。
这句话的例子:
def f1():
   
    def f2():
        max=3
        print(max)
    f2()
f1()
print(max) #在全局无法查看(即访问)局部变量,所以报错。
 
max=1
def f1():
    
    def f2():
        
        print(max)
    f2()
f1()
print(max) #证明了在局部可以查看(即访问)全局变量。

# len=111
# def foo():
# # len=222
# print(len)
# len=111
# foo()


# x=0
def f1():
# x=1
def f2():
# x=2
def f3():
# x=3
print(x)
f3()
f2()#问:函数的调用语句为何必须要与定义函数(即关键字def)在同一个缩进下才能调用函数?
        因为规定:在某层级定义的函数,只能在某层级调用。这便是函数调用的层级限制。

f1()


def foo1():
def foo2():
def foo3():
print(x)

'''

不同变量的作用域不同
是由这个变量所在的名称空间决定的。(注意:Python中变量名常常说成变量。)

#二 作用域:指的是变量的作用范围。
# 全局作用域:包含内置名称空间与全局名称空间的名字。
# 特点:全局存活(理解为程序运行着这个变量一直存在),全局有效(理解为这个变量可以在全局中使用)
# 局部作用域:包含局部名称空间的名字。
# 特点:临时存活(这个变量函数调用时存在,函数结束时不在),局部有效(这个变量只能自己使用)

注意要记重点:作用域关系是在函数定义阶段就已经固定死了,与函数调用所在的位置无关。

如何理解这句话???就是:在函数定义阶段就决定了:函数调用时要去哪个作用域找出变量名。
# 示范一:
# def f1():
# print(xxx)
# xxx=111
#
# def f2():
# xxx=222
# f1()
#
# f2()

# 示范二:
xxx=111
def f1():
print(xxx)
xxx=222 #为何此处报错???因为定义阶段局部名称空间有xxx,决定了调用时要去局部作用域,
但调用函数时,运行代码是一行一行运行的,运行到print xxx时,xxx还没定义,所以报错。

yyy=222
print(yyy)#此处就是写代码正常逻辑

f1()




 

# 闭包函数:
# 闭:封闭,指的是该函数是定义一个函数内部的函数。
# 包:该内部函数包含对外层函数名字的引用(即访问)。注意:不是引用全局变量。

# def outter():
# x=1
# def inner():
# print('from inner',x)
# return inner
#
#
# f=outter()
#
# def foo():
# # print(f)
# x=111111111111111111111111111111111111
# f()
# foo()


记忆重点:为函数体传值的两种方式:
# def foo():
# print('hello %s' %name)

# 方式一:直接以参数的形式传入
# def foo(name):
# print('hello %s' %name)
#
# foo('egon')
# foo('egon')
# foo('egon')

# 方式二:闭包函数
# def outter(name):
# # name='egon'
# def foo():
# print('hello %s' %name)
# return foo
#
# f=outter('egon')
# # print(f)
# f()
# f()
# f()
#
# f1=outter('alex')
# f1()
# f1()
# f1()


# pip3 install requests
import requests

# 问题:如何实现爬虫要对网站的多页面爬取?
# def get():
# response=requests.get(url)
# if response.status_code == 200:
# print(response.text)

# 解决方案一:
# def get(url):
# response=requests.get(url)
# if response.status_code == 200:
# print(response.text)
#
# get('https://www.baidu.com')
# get('https://www.baidu.com')
# get('https://www.baidu.com')

# 解决方案二:

def outter(url):
# url='https://www.baidu.com'
def get():
response=requests.get(url)
if response.status_code == 200:
print(response.text)
return get

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

baidu()
baidu()
baidu()
baidu()
baidu()
baidu()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()

 
posted @ 2018-09-26 17:05  timm_book  阅读(55)  评论(0)    收藏  举报