#!/usr/bin/env python3
# * coding: utf8 *
################1.0函数基础################
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
1、什么是函数
函数就相当于具备某一功能的工具
函数的使用必须遵循一个原则:
先定义
后调用
2、为何要用函数
1、代码冗余,程序的组织结构不清晰,可读性差
2、可维护性、扩展性差
3、如何用函数
先定义
三种定义方式
后调用
三种调用方式
返回值
三种返回值的形式
"""
# 1、先定义
# #定义的语法
"""
def 函数名(参数1,参数2,...):
###文档描述####
函数体
return值
"""
########形式一:无参函数##########
# def func():
# print('孔维鑫 is a GOOdboy')
#
# func()
#####重点!!!!!!!!!!!
# 定义函数发生的事情
# 1、申请内存空间 存数体代码
# 2,将上述内存地址绑定 数名
# 3、定义函数不会执行函数体代码,但是会检测函数体语法
# 调用函数发生的事情
# 1、通过函数名找到 数的内tt址
# 2、然后加口号就是在触发函数体代码的执行
# print(func)
# func()
# 示范1
# def bar():#bar=函数的内存地址 1
# print("from bar")
#
# def foo():
# # print(bar)
# bar()
# print('from foo')
# foo()
# 示范2
# def foo():
# # print(bar)
# bar()
# print('from foo')
# foo() #会报错 因为此时bar未定义
# def bar(): # bar=函数的内存地址 1
# print("from bar")
#
# foo()#不会报错
########形式二:有参函数##########
# 例如 print() open() input() list()
# def func(x,y):
# print(x,y)
# func(1,2)
########形式三:空函数##########
# def func(x,y):
# pass
"""
函数怎么用 ???
举例说明:
如果你想在统计三个年级的每个年级学生人数中做一个加法运算计算各年级总体人数
正常情况我们应该是
比如:
一年级:
男生1=20
女生1=30
一年级总人数=男生1+女生1
print("一年级总计人数为:-----{}".format(一年级总人数))
二年级
男生2=30
女生2=30
二年级总人数=男生2+女生2
print("二年级总计人数为:-----{}".format(二年级总人数))
三年级
男生3=50
女生3=30
三年级总人数=男生3+女生3
print("三年级总计人数为:-----{}".format(三年级总人数))
总人数=一年级总人数+二年级总人数+三年级总人数
print(总人数)
但是每次这样进行计算确实比较复杂,所以用函数就可以解决这这个问题
def p_number(boy,girl):
总计人数=boy+girl
print("总计男女人数为:-----{}".format(总计人数))
return 总计人数
一年级人数 = p_number(20,30)
二年级人数 = p_number(30,30)
三年级人数 = p_number(50,30)
总人数=一年级人数+二年级人数+三年级人数
print(总人数)
这样就可以进行多次利用
"""
# 三种定义方式各用何处
# 1,无参函数的应用场景
# 接收用户输入信息
# name= input("username>>>:")
# age = input("user age>>>:")
# msg='名字:{}年龄:{}'.format(name,age)
#
# 但是如果是要输入三十次呢??
# def interactive():
# name = input("username>>>:")
# 而且还可以在函数里面添加其他内容
# age = input("user age>>>:")
# msg = '名字:{}年龄:{}'.format(name, age)
# print(msg)
# interactive()
# interactive()
# interactive()
# interactive()
# 2,有参函数的应用场景
# 相加函数
# def add(x,y):
# res=x+y
# print(res)
# 传统做法
# x = 20
# y = 30
# res = x+y
# print(res)
# 换句话说 :如果函数是工场 那参数相当于加工材料
# 3,空函数的应用场景 #构思的时候
# 我们可能想到的功能有用户认证,下载,上传,浏览,切换目录等功能,可以先做出如下定义:
# def auth_user():
# """user authentication function"""
# pass
#
# def download_file():
# """download file function"""
# pass
#
# def upload_file():
# """upload file function"""
# pass
#
# def ls():
# """list contents function"""
# pass
#
# def cd():
# """change directory"""
# pass
# 二 调用函数
# 1.0 语句的形式:只去调用函数,不做其他操作
# interactive()
# 2.0表达式函数
# def add(x,y):#参数-》原材料
# res=x+y
# return res#返回值-》产品]
# 赋值表达式
# res=add(1,2)
# print(res)
# 数学表达式
# res=add(1,2)*10
# print(10)
# 3.0函数调用可以当做参数
# def add(x, y): # 参数-》原材料
# res = x + y
# return res # 返回值-》产品]
#
# res=add(add(1,2),10)
# print(res)
# 三,函数返回值
# return是函数结束的标志,即函数体代码一旦运行到return
# 会立刻终止函数的运行,并且会将return后的值当做本次运行的结果返回:
# 之前的需求
# def func(x,y):
# print('1111')
# print('2222')
# print('3333')
# res =x+y #res = 1+2
# return res
# res = func(1,2)
# print(res)
# 性质:函数体代码一旦运行到return会立刻终止函数的运行
# def func():
# print(1111)
# return # 后面就算是while 也会结束 (一般用的是break)
# print(2222)
# print(3333)
#
#
# func()
# 1.返回none:函数体内没有return
# return
# return None
# def func():
# pass
# res= func()
# print(res)
# def func():
# return None
# res= func()
# print(res)
# 2.返回一个值: (return 值)
# def func():
# return 10
# res = func()
# print(res)
# 3.返回多个值: (return +多个值): 用逗号分隔开多个值,会被return返回成元组
# def func():
# return 10, "kwx", [1, 2] # 返回值元组 不用加括号
#
#
# res = func()
# print(res, type(res))
"""
说白了,函数就是一种工具,
举个例子: 一个机器人 | (你们之前做过ardunio的简单的单片机设计可以知道 所有功能都会变成一个个函数 进行单独使用)
假如这个机器人脑子里啥都是空的就等你输入功能
首先 : 我们是不是先进行构思
第一,是不是要让机器人会动起来吧 怎么动!!!!
定义空函数
def feet(): 脚怎么动
pass
def hands(): 手怎么动
pass
def arms(): 胳膊怎么动
pass
def head(): 头怎么动
pass
等等
内容是看自己的需求来进行确定的!!!!!!(程序员常说的一句话"看情况!!!")
这里举个例子:
我们知道我们写过9x9乘法表
for i in range (1,10):
for j in range(1,i+1):
print("{}x{}={}".format(i,j,i*j),end=" ")
print()
那现在的需求就是输入几 就输出他之前的所有的乘法表
如果没函数的写法:
(第一种)直接改for i in range (1,10):里的范围
eg: 前五的乘法表
for i in range (1,5):
for j in range(1,i+1):
print("{}x{}={}".format(i,j,i*j),end=" ")
print() #这种是不是每次都会改数字啊是不是很麻烦!!!!
(第二种)在第一种基础上优化 每次改太复杂,会不会用到一个input()进行简化赋值
n = int(input("亲输入你要输出的值:"))
# print(type(n))#<class 'str'>这输出的是字符串那是不是就要进行转化啊!!! 怎么转的 是不是想到int()!!!!(你应该想到的)
for i in range(1,n+1): #吧范围进行变量赋值!! 注意我们知道这里是左闭右开 所以n是需要加1的 n+1
for j in range(1, i + 1):
print("{}x{}={}".format(i, j, i * j), end=" ")
(第三种)一行解决 如果内置函数掌握了的话
print('\n'.join([' '.join(["%2s x%2s = %2s"%(j,i,i*j) for j in range(1,i+1)]) for i in range(1,10)]))
自己看看 !!!都学过!!! 数据类型内置函数里面的
虽然已经很好了但是大家在看用函数写的是啥样的
<普通> 将重复部分进行加到函数中
def num(n):
for i in range (1,n+1): #重
for j in range(1,i+1): #复 直接写到函数中
print("{}x{}={}".format(i,j,i*j),end=" ") #部
print() #分
num(5)
<第三对应> 十分简洁
def num(n):
return '\n'.join([' '.join(["%2s x%2s = %2s" % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, n+1)])
print(num(5))
"""
#############2.0函数参数使用#############
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
函数参数的使用
一,形参与实参介绍
二,形参与实参的具体使用
2.1位置参数
2.2关键字参数
2.3 默认参数
2.4可变长度的参数(*与**的用法)
2.4.1可变长度的位置参数
2.4.2可变长度的关键字参数
2.5命名关键字参数(了解)
2.6组合使用(了解)
"""
# 一,形参与实参介绍
# 含义:
"""
形参:在定义函数阶段定义的参数称之为形式参数,简称形参 相当于变量名
def func(x,y): #x=1 y=2
print(x,y)
实参:在调用函数阶段传入的值称之为实际参数,简称实参,相当于变量值
func(1,2)
print(x,y) #绑定关系只在函数体内进行
#形参与实参的关系:
#1.0 在调用阶段,实参(相当于变量值)会绑定(赋值=绑定内存地址)给形参(相当于变量名)
#2.0 这种绑定关系只能在函数体内使用
# 3.0 实参与形参的绑定关系在函数调用时生效,函数调用结束后解除绑定关系
实参是传入的值,但值可以是以下形式
形式一: 直接给值
func(1,2)
形式二:变量形式
a=1
b=2
func(a,b)
#形式三:func(int(2)
func(func1(1.2,),func2(2.3)333)
说白了只要是值就行 是什么无关 基本数据类型都可以!!!
"""
"""
二,形参与实参的具体使用
2.1位置参数:按照从左到右的顺序依次定义的参数称之为位置参数
1>位置形参:在函数定义阶段,按照从左到右的顺序直接定义的"变量名"
特点:特点:必须被传值,多一个不行少一个也不行
def func(x,y):
print(x,y)
func()
func(1,2)
func(1,2,3)
2>位置实参:在函数调用阶段,按照从左到有的顺序依次传值
特点: 按照顺序与形参-对应
func(1,2)
func(2,1)
2.2关键字参数
关键字实参:在函数调用阶段,按照key=value的形式传入的值
特点:指名道姓给某个形参传值,可以完全不参照顺序
def func(x,y)
print(x,y)
func(y=2,x=1)
#注意:混合使用,强调
# 1、位置实参必须放在关键字实参前
def func(x,y)
print(x,y)
func(1,y=2)
func(y=2,1)
# 2、不能为同一个形参重复传值
# func(1,y=2,x=3)
# func(1,2,x=3, y=4)
2.3 默认参数(默认形参参数)
#默认形参:在定义函数阶段,就已经被赋值的形参,称之为默认参数
特点:在定义阶段就已经被赋值,意味着在调用阶段可以不用为其赋值
def func(x,y=3): y=3就是默认的
print(x,y)
func(x=1)
#func(x=1) #输出结果:1 3
func(x=1, y=44444)#输出结果:1 44444 # 以你想传的为准
#那什么时候用位置形参 那什么时候用默认形参呢!!!
位置形参:是必须要传值的,所以当函数必须要有值的时候就用到位置形参!!
默认形参:在调用时候是要经常改变值,但不会改变函数本身,就可以进行设置为默认实参
# 举例:
# 比如机械班的同学进行信息输入(我们知道乃是众星捧月之式 女的很少)
def register(name,age,sex):
print(name,age sex)
register('三炮",18,'男")
register('二炮',19,'男)
register('大炮',19,'男)
register('没炮',19,'女')
# 这样定义是不是太复杂 因为女的就比较少输入会变得很复杂重复 ,那怎么办呢!!!
def register(name,age,gender="男"):
print(name,age,gender)
register('三炮',18)
register('二炮',19)
register('大炮',19)
register('没炮',19,gender="女")
#位置形参与默认形参混用,强调:
#1、位置形参必须在默认形参的左边
#def func(y=2,x):
# pass
# 2、默认参数的值是在函数定义阶段被赋值的, 准确地说被赋予的是值的内存地址.
def func(x,y=2):
print(x,y)
func(1)# 输出值默认是1 2
# 示例1
如果 这么写呢
m=2
def func(x,y=2): #y=-->2的内存地址
print(x,y)
m=333333
func(1)
输出结果呢!!! --->输出结果是 1 2 所以你可以知道 是在定义函数前进行赋值才可以
但是如果是这样的呢
m=[1111]
def func(x,y=m): #y=-->[1111]的内存地址
print(x,y)
m.append(2222)
func(1) #输出结果:1 [1111, 2222]
# 所以准确地说被赋予的是值的内存地址
# 虽然默认值可以被指定为任意数据类型,但是不推荐使用可变类型
m=[1111]
def func(x,y=m): #y=-->[1111]的内存地址
print(x,y)
m.append(2222)
func(1) #输出结果:1 [1111, 2222]
def func(x,y,z,l=None):
if l is None:
l=[]
l. append (x)
l. append(y)
l. append(z)
print(l)
func(1,2,3)
#所有在这里说一嘴 你在定义函数时 是最好是可以满足所有的变化在函数内进行 (就是不能受其他的影响)
2.4可变长度的参数(*与**的用法)
# 什么是可变长度:可变长度指的是在调用函数时,传入的值(实参)的个数不固定
#而实参是用来为形参赋值的,所以对应着,针对溢出的实参必须有对应的形参来接收
2.4.1可变长度的位置参数
#1:形参格式(*形参名):用来接收溢出的位置实参,溢出的位置实参会被*保存成元组的格式,然后赋值给形参
def func(x,y,*z):
print(x,y,z)
func(1,2,3,4,5,6)
def my_sum(*args): #通常为 *args(规定)
res=0
for item in x:
res+=item
return res
res=my_sum(1,2,3,4.5,6)
print(res)
#II:*可以用在实参中,实参中带* ,先*后的值打散成位置实参
# def func(x,y,z):
# print(x,y,z)
# # func(*[11,22,33])## func(11, 22..33)
# l=[11,22,33]
# func(*l)
# 或
# l=[11,22,33]
# func(*l)
#III:形参与实参中都带*
def func(x,y,*args):#args=(3,4,5,6)
print(x,y,args)
func(1,2,[3,4,5,6])
func(1,2,*[3,4,5,6])#func(1,2,3,4,5,6)
2.4.2可变长度的关键字参数
#1:形参格式(**形参名):用来接收溢出的关键字实参,溢出的位置实参会被*保存成字典的格式,然后赋值给形参
**后跟的可以是任意名字,但是约定俗成应该是kwargs
def func(x,y,** kwargs):
print(x,y,kwargs)
# func(1,y=2,a=1,b=2,c=3)
func(*[11,22,33]) #func(11,22,33)
#II:*可以用在实参中,实参中带** ,先**后的值打散成关键字实参
def func(x,y,z):
print(x,y,z)
# func(*{'x':1,'y':2,'z':3}) #func(x=1,y=2)
# func(** {'x':1,'y':2,'z':3})#func(x=1,a=2,z=3)
#错误
# func(*{'x':1,'y':2,})#func(x=1,y=2) #不能少
# TypeError: func() missing 1 required positional argument: 'z'
# TypeError:func()缺少1个必需的位置参数:“ z”
func(**{'x':1,'a':2,'z':3})#func(x=1,a=2,z=3) #不能多
# TypeError: func() got an unexpected keyword argument a
# TypeError:func()获得了意外的关键字参数a
#III:形参与实参中都带**
def func(x,y,**kwargs):
print(x,y,kwargs)
# func(y=222, x=111, a=333, b=444)
func(**{'y':222,'x':111,'a':333,'b':4444,})
#混用*与**时:#*args必须在**kwargs之前
# 示例 1
def func(*args,**kwargs):
print(args)
print(kwargs)
func(1,2,3,4,5,6,7,8,x=1,y=2,z=3)
# 示例2
def index(x,y,z,bbb):
print("index=>>>",x,y,z,bbb)
def wrapper(a,b,c,d):#a=1,b=2,c=3
index(a,b,c,d)#index(1,2,3)
wrapper(1,2,3,4)#wrapper的传递参数是给index用的# 也就是index()牵制wrapper()函数参数!!!
def index(x,y):
print(x,y)
def wrapper(*args, **kwargs):# args=(1,) kwargs={'y':2, 'z':3}
index(*args,**kwargs)
# index(*(1,),**{'y':2, 'z':3})
# index (1, z=3, y=2)
wrapper(y=2,z=3,x=1,)#不会被牵制但是要遵循index()的形参进行赋值实参
2.5命名关键字参数(了解)
#1,命名关键字参数(了解)
#命名关键字参数:在定义函数时,*后定义的参数,如下所示,
#特点:
#1、命名关键字实参必须按照key-value的形式为其传值
# 1
def func(x,y,*,a,b):#其中a和b称之为命名关键字参数
print(x,y)
print(a,b)
# func(1,2,b=222,a=111)
#2
def func(x,y,*,a,b=2222):#其中a和b称之为命名关键字参数
print(x,y)
print(a,b)
func(1,2)
def func(x,y,*,a=11111,b):
print(x.y)
print(a.,b)
#func(1,2)
|||||||了解||||||||||||||
在定义了**kwargs参数后,函数调用者就可以传入任意的关键字参数key=value,
如果函数体代码的执行需要依赖某个key,必须在函数内进行判断
def register(name,age,**kwargs):
if 'sex' in kwargs:
#有sex参数
pass
if 'height' in kwargs:
#有height参数
pass
想要限定函数的调用者必须以key=value的形式传值,Python3提供了专门的语法:
需要在定义形参时,用作为一个分隔符号,号之后的形参称为命名关键字参数。对于这类参数,
在函数调用时,必须按照key=value的形式为其传值,且必须被传值
def register(name,age,*,sex,height): #sex,height为命名关键字参数
pass
register('lili',18,sex='male',height='1.8m') #正确使用
register('lili',18,'male','1.8m') # TypeError:未使用关键字的形式为sex和height传值
register('lili',18,height='1.8m') # TypeError没有为命名关键字参数height传值。
命名关键字参数也可以有默认值,从而简化调用
def register(name,age,*,sex='male',height):
print('Name:%s,Age:%s,Sex:%s,Height:%s' %(name,age,sex,height))
register('lili',18,height='1.8m')
#输出结果:Name:lili,Age:18,Sex:male,Height:1.8m
需要强调的是:sex不是默认参数,height也不是位置参数,因为二者均在后,所以都是命名关键字参数,
形参sex=’male’属于命名关键字参数的默认值,因而即便是放到形参height之前也不会有问题。
另外,如果形参中已经有一个args了,命名关键字参数就不再需要一个单独的*作为分隔符号了
def register(name,age,*args,sex='male',height):
print('Name:%s,Age:%s,Args:%s,Sex:%s,Height:%s' %(name,age,args,sex,height))
register('lili',18,1,2,3,height='1.8m') #sex与height仍为命名关键字参数
#输出结果: Name:lili,Age:18,Args:(1, 2, 3),Sex:male,Height:1.8m
||||||||||||||||||||||||||||||||||||||||||||||||
2.6 组合使用(了解)
#形参顺序:位置新参,默认形参,*args,命名关键字形参,**kwargs
def func(x,y=111,*args,z,**kwargs):
print(x)
print(y)
print(args)
print(z)
print(kwargs)
# 实参用法:
func(1)
func(x=1)
func(1,x=1)
func(*'hello')
func(**{})
func(*'hell'**{})
综上所述所有参数可任意组合使用,但定义顺序必须是:位置参数、默认参数、args、命名关键字参数、*kwargs
可变参数*args与关键字参数kwargs通常是组合在一起使用的,如果一个函数的形参为*args与kwargs,
那么代表该函数可以接收任何形式、任意长度的参数
def wrapper(*args,**kwargs):
pass
在该函数内部还可以把接收到的参数传给另外一个函数(这在装饰器的实现中大有用处)
def func(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs):
func(*args,**kwargs)
wrapper(1,z=3,y=2)
#输出结果:1 2 3
按照上述写法,在为函数wrapper传参时,其实遵循的是函数func的参数规则,调用函数wrapper的过程分析如下:
1. 位置实参1被接收,以元组的形式保存下来,赋值给args,即args=(1,),关键字实参z=3,y=2被*接收,
以字典的形式保存下来,赋值给kwargs,即kwargs={'y': 2, 'z': 3}
2. 执行func(args,kwargs),即func((1,),* {'y': 2, 'z': 3}),等同于func(1,z=3,y=2)
提示: *args、**kwargs中的args和kwargs被替换成其他名字并无语法错误,但使用args、kwargs是约定俗成的。
"""
############3.0函数名称和作用域#############
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
1、名称空间(namespaces)
I:三种名称空间用途与存活周期
II:三种名称空间的加载顺序
III:三种名称空间的查找名字的优先级
2、作用域全局作用域局部作用
global
Local
函数嵌套使用的情况下,作用域与名字的查找关系
(后续补上)
4、函数对象
5、闭包函数
"""
# 1,名称空间namespace:存放名字的地方,是对栈区的划分
# 在编写程序是的变量名的存储在栈区的空间 对名字进行归类为三种:如果不分类 同样的名字会被覆盖(之前说过)
# x =10
"""
栈区 堆区
内置名称空间|
(全局范围:内置,全局)| x->0xfffff0030---------------> 10(0xfffff0030) #x=10
全局名称空间|
局部名称空间
就把栈区当地球 名称空间:就当国家
假设:内置当做美国 全局为中国
你叫tom 但是你在中国 美国中也有叫tom的
但: 你们不是同一个人!!!!
有了名称空间之后,就可以在楼区中存放相同的名字,详细的,
名称空间分为三种:
#1.1内置各称空间 一个
#存放的名字: 存放的python解释器内置的名字 例如:print input open 都是内置函数名
>>> print
<built-in function print> #built-in :内置
>>> input
<built-in function input>
#存活周期:python解释器启动则产生,python解释器关闭则销毁
#1.2全局名称空间 一个
#存放的名字:只要不是函数内定义的,也不是内置的,剩下的就是全局名称空间
比如 :
import os 全局名称
x=10
if 13>3:#全局名称
y=20
if 3==3:#全局名称
z=30
#func=函数的内存地址
def func():#全局名称空间
a=111
b=222
class Foo:: #全局名称空间
pass
#存活周期:python文件执行时新产生,python文件运行完毕后销毁
#1.3局部名称空间 多个
#存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字
#存活周期:在调用函数时存活,函数调用完毕后则销毁
def func():
a=111
b=222
func()
func()
func()
func()
# 民称空间有几个???? ---> 四个 函数调用几次产生几个名称空间
# def func(a,b):
# pass
#名称空间 四个
# func(10,1)
# func(11,12)
# func(13,14)
# func(15,16)
#1.4名称空间的加载顺序
# 内置名称空间 > 全局名称空间 > 局部名称空间
#(python解释器)(python文件) (定义的函数)
# 内置 全局是一定有 局部不一定有
#1.5销毁顺序
#局部名称空间 > 全局名称空间 > 内置名称空间
# 名称空间 不是真实存在的 真正存在的是栈区 栈区进行划分的结果就是名称空间
#1.6名字的查找优先级:当前所在的位置向上一层一层查找
#内置名称空间
#全局名称空间
#局部名称空间
#如果当前在局部名称空间:
#局部名称空间->全局名称空间->内置名称空间
实例1:
#当寻找input的在局部时,根据顺序 局部名称空间->全局名称空间->内置名称空间
input=333
def func():
input=444
print(input) # 局部是不是存在input啊 可知:input=444
#所以你输出的必然是input=444
func()
实例2
#当寻找input的在不在局部时,根据顺序 局部名称空间->全局名称空间->内置名称空间
# 是不是应在去全局里面找啊
input=333
def func():
print(input) # 局部不存在input啊 可知:全局input=333
#所以你输出的必然是input=333
func()
# 实例3
#当寻找input的在不在局部,也不在全局时,根据顺序 局部名称空间->全局名称空间->内置名称空间
# 是不是应在去内置里面找啊
def func():
print(input) # 局部不存在input啊 全局里也没input
#所以你输出的必然是input在内置函数里面的input()函数!!!
func()
# 故输出结果是:<built-in function input>
#如果当前在全局名称空间
#全局名称空间->内置名称空间
# 原理同上
input=333
def func():
input=444
func()
print(input)#全局名称空间进行查找
# 示范1
def func():
print(x)
x=111
func()
def func():
print(x)
func()
x=111
#示范2:名称空间的关系 局部名称空间(省份) > 全局名称空间(国家) > 内置名称空间(地球)
# 名称空间的"嵌套"关系是以函数定义阶段为准,与调用位置无关
x=1
def func():
print(x)
def foo():
x=222
func()
foo()
#示范3:函数嵌套定义
#这里是为了讲解 使用input进行赋值 正常情况不要这么写!!!
input=111
def f1():
input=222
def f2():
input=333
print(input)
f2()
f1()
# 示范4
x=111
def func():
print(x)
x=222
func()
# 名字的查找顺序是从定义阶段为准的 然后进行每层查找的 (局部名称空间->全局名称空间->内置名称空间)
但是在分析的时候要从定义阶段为基准进行每层分析.,
"""
"""
2、作用域-->作用范围
#全局作用域:内置名称空间、全局名称空间
特点:
1,全局存活
2,全局有效:被所有函数共享
# # 自定义函数不能相互找(除非相互嵌套)
def foo():
x=111
print(x)
def bar():
y=222
print(y)
foo()
bar()
#局部作用域
特点:
1,临时存活
2,局部有效:只在自己的函数(局部名称空间)内有效
def foo(x):
def f1():
def f2():
print(x)
# 多个名称空间为了方便定义有一个方法:LEGB(局部名称空间)(!!!!!!!了解内容)
# 三,global与 nonLocal
# global:
# 实例1 x=111 与x=222 无关,因为一个是全局 一个是局部
x=111
def func():
x=222
func()
print(x)
#实例2 如果在局部想要修改全局的名字对应的值,需要用global(要求是不可变类型)
x=111
def func():
global x #申明x为全局名字 x=222为-到了全局名称空间会把111改成222
x=222
func()
print(x)
# 实例3 (可变类型)
l=[111,222]
def func():
l.append()
func()
print(l)
# nonlocal(了解):修改函数外层函数包含的名字对应的值(不可变类型)
# 实例1
def f1():
x=11
def f2():
global x
x=22
f2()
print("f1内的x:",x)
f1()
# 实例2
def f1():
x=11
def f2():
nonlocal x #若x=11不存在的 则报错 若存在 则就改变外层x=11的值
x=22
f2()
print("f1内的x:",x)
f1()
"""
###########4.0函数对象和闭包函数##########
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
1、名称空间(namespaces)
I:三种名称空间用途与存活周期
II:三种名称空间的加载顺序
III:三种名称空间的查找名字的优先级
2、作用域全局作用域局部作用
global
Local
函数嵌套使用的情况下,作用域与名字的查找关系
(后续补上)
4、函数对象
5、闭包函数
"""
# 1,名称空间namespace:存放名字的地方,是对栈区的划分
# 在编写程序是的变量名的存储在栈区的空间 对名字进行归类为三种:如果不分类 同样的名字会被覆盖(之前说过)
# x =10
"""
栈区 堆区
内置名称空间|
(全局范围:内置,全局)| x->0xfffff0030---------------> 10(0xfffff0030) #x=10
全局名称空间|
局部名称空间
就把栈区当地球 名称空间:就当国家
假设:内置当做美国 全局为中国
你叫tom 但是你在中国 美国中也有叫tom的
但: 你们不是同一个人!!!!
有了名称空间之后,就可以在楼区中存放相同的名字,详细的,
名称空间分为三种:
#1.1内置各称空间 一个
#存放的名字: 存放的python解释器内置的名字 例如:print input open 都是内置函数名
>>> print
<built-in function print> #built-in :内置
>>> input
<built-in function input>
#存活周期:python解释器启动则产生,python解释器关闭则销毁
#1.2全局名称空间 一个
#存放的名字:只要不是函数内定义的,也不是内置的,剩下的就是全局名称空间
比如 :
import os 全局名称
x=10
if 13>3:#全局名称
y=20
if 3==3:#全局名称
z=30
#func=函数的内存地址
def func():#全局名称空间
a=111
b=222
class Foo:: #全局名称空间
pass
#存活周期:python文件执行时新产生,python文件运行完毕后销毁
#1.3局部名称空间 多个
#存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字
#存活周期:在调用函数时存活,函数调用完毕后则销毁
def func():
a=111
b=222
func()
func()
func()
func()
# 民称空间有几个???? ---> 四个 函数调用几次产生几个名称空间
# def func(a,b):
# pass
#名称空间 四个
# func(10,1)
# func(11,12)
# func(13,14)
# func(15,16)
#1.4名称空间的加载顺序
# 内置名称空间 > 全局名称空间 > 局部名称空间
#(python解释器)(python文件) (定义的函数)
# 内置 全局是一定有 局部不一定有
#1.5销毁顺序
#局部名称空间 > 全局名称空间 > 内置名称空间
# 名称空间 不是真实存在的 真正存在的是栈区 栈区进行划分的结果就是名称空间
#1.6名字的查找优先级:当前所在的位置向上一层一层查找
#内置名称空间
#全局名称空间
#局部名称空间
#如果当前在局部名称空间:
#局部名称空间->全局名称空间->内置名称空间
实例1:
#当寻找input的在局部时,根据顺序 局部名称空间->全局名称空间->内置名称空间
input=333
def func():
input=444
print(input) # 局部是不是存在input啊 可知:input=444
#所以你输出的必然是input=444
func()
实例2
#当寻找input的在不在局部时,根据顺序 局部名称空间->全局名称空间->内置名称空间
# 是不是应在去全局里面找啊
input=333
def func():
print(input) # 局部不存在input啊 可知:全局input=333
#所以你输出的必然是input=333
func()
# 实例3
#当寻找input的在不在局部,也不在全局时,根据顺序 局部名称空间->全局名称空间->内置名称空间
# 是不是应在去内置里面找啊
def func():
print(input) # 局部不存在input啊 全局里也没input
#所以你输出的必然是input在内置函数里面的input()函数!!!
func()
# 故输出结果是:<built-in function input>
#如果当前在全局名称空间
#全局名称空间->内置名称空间
# 原理同上
input=333
def func():
input=444
func()
print(input)#全局名称空间进行查找
# 示范1
def func():
print(x)
x=111
func()
def func():
print(x)
func()
x=111
#示范2:名称空间的关系 局部名称空间(省份) > 全局名称空间(国家) > 内置名称空间(地球)
# 名称空间的"嵌套"关系是以函数定义阶段为准,与调用位置无关
x=1
def func():
print(x)
def foo():
x=222
func()
foo()
#示范3:函数嵌套定义
#这里是为了讲解 使用input进行赋值 正常情况不要这么写!!!
input=111
def f1():
input=222
def f2():
input=333
print(input)
f2()
f1()
# 示范4
x=111
def func():
print(x)
x=222
func()
# 名字的查找顺序是从定义阶段为准的 然后进行每层查找的 (局部名称空间->全局名称空间->内置名称空间)
但是在分析的时候要从定义阶段为基准进行每层分析.,
"""
"""
2、作用域-->作用范围
#全局作用域:内置名称空间、全局名称空间
特点:
1,全局存活
2,全局有效:被所有函数共享
# # 自定义函数不能相互找(除非相互嵌套)
def foo():
x=111
print(x)
def bar():
y=222
print(y)
foo()
bar()
#局部作用域
特点:
1,临时存活
2,局部有效:只在自己的函数(局部名称空间)内有效
def foo(x):
def f1():
def f2():
print(x)
# 多个名称空间为了方便定义有一个方法:LEGB(局部名称空间)(!!!!!!!了解内容)
# 三,global与 nonLocal
# global:
# 实例1 x=111 与x=222 无关,因为一个是全局 一个是局部
x=111
def func():
x=222
func()
print(x)
#实例2 如果在局部想要修改全局的名字对应的值,需要用global(要求是不可变类型)
x=111
def func():
global x #申明x为全局名字 x=222为-到了全局名称空间会把111改成222
x=222
func()
print(x)
# 实例3 (可变类型)
l=[111,222]
def func():
l.append()
func()
print(l)
# nonlocal(了解):修改函数外层函数包含的名字对应的值(不可变类型)
# 实例1
def f1():
x=11
def f2():
global x
x=22
f2()
print("f1内的x:",x)
f1()
# 实例2
def f1():
x=11
def f2():
nonlocal x #若x=11不存在的 则报错 若存在 则就改变外层x=11的值
x=22
f2()
print("f1内的x:",x)
f1()
"""