python基础入门之函数参数

python基础入门之函数参数

一、形参与实参

1、形式参数

在函数定义阶段括号内填写的参数

def index(a)

2、实际参数

在函数调用阶段括号内填写的参数

index(123)

3、形参与实参的关系

1.形参相当于是变量名
2.实参相当于是数据值
3.在函数调用的阶段形参会临时与实参绑定关系,但是函数运行结束之后,会自动解除绑定(动态绑定,动态解除)
eg:
def index(a):
print(a)

index(123)  # 123
index(456)  # 解除绑定,再输出456
index(789)  # 789

二、位置参数

位置参数分为位置形参和位置实参。

1、位置形参

在函数定义阶段括号内从左到右依次填写的变量名称之为位置形参。凡是按照这种形式定义的形参必须要传值。
def func1(a,b,c): #定义位置形参:a,b,c,
    print(a,b,c)
func1() #报错,缺少3个位置参数
func1(1,2,3) #1 2 3

2、位置实参

在函数调用阶段括号内从左往右依次填写的数据值称为位置实参,凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应。
def func1(a,b,c): #定义位置形参:a,b,c,
    print(a,b,c)
func1(1,2,3) #1 2 3 对应关系为a=1,b=2,c=3 按照位置一一对应传值
func1(1,2)    # 报错,少一个不行
func1(1,2,3,4)# 报错,多一个也不行

三、关键字参数

在调用函数时,实参可以是key=value的形式,称为关键字参数,凡是按照这种形式定义的实参,可以完全不按照从左到右的顺序定义,但仍能为指定的形参赋值。

def index(a,b,c):
    print(a,b,c)
index(a=4,c=1,b=2) # 4 2 1 关键字传参,指定数据值对应指定变量名
index(a=1,2,4) # 报错,关键字传参要在位置传参后面
index(2,4,c=1) # 2 4 1,
index(3,a=1,b=4)# 报错,同一形参在调用时不能多次赋值,print(a,b,c)中a最先被赋值,若后面关键字传参又指定数据值给a,则会报错

def index(name,pwd):
    print(name,pwd)
name = 'lily'
pwd = 222
index(name,pwd) # lily 222

def index(a,b):
    print(a,b)
name='lily'
pwd=222
index(a=name, b=pwd) # lily 222
# 实参没有固定的定义,可以传数据值,也可以传绑定了数据值的变量名。

# 格式规范
1、位置参数写在关键字参数前面
2、简单的和短的写在复杂和长的前面
3、同一个形参在调用的时候不能多次赋值

四、默认参数

默认参数本质是关键字形参,提前已经给了的,用户不传值默认提前给到的数据值,若用户传值则使用用户提供的数据值。

def register(name,age,gender='famale'): # 第三个变量名为关键字形参
    print(f'''
    -----------学员信息-----------
    姓名:{name}
    年龄:{age}
    性别:{gender}
    -----------------------------
    ''')
register('lily',19) # 当第三个变量名没有时,就会被默认为关键字形参
register('may',18)  #默认为关键字形参
register('lihua',17,'male') 
# 不是在默认的情况下,这里的值就是第三个形参的值
register('lihua',17,gender='male')
# register('lily',19,'famale')
# register('may',18,'famale')
# register('lihua',17,'male')
# register('lihua',17,'male')
# 默认是famale,若用户在括号内传值即可修改

'''
默认参数必须在位置参数之后
默认参数的值仅在函数定义阶段被赋值一次
'''
x=1
def index(number=x):
	print(number)
... 
x=5 #定义阶段number已被赋值为1,此处的修改与默认参数number无任何关系
index()
# 1

五、可变长参数

参数的长度可变指的是在调用函数时,实参的个数可以不固定,而在调用函数时,实参的定义无非是按位置或者按关键字两种形式,这就要求形参提供两种解决方案来分别处理两种形式的可变长度的参数。

1、可变长形参

  • 如果在最后一个形参名前加*号,那么调用函数时,多余的位置参数会被组织成元组赋值给*号后面的变量名。
def func1(b,c,*a): #在最后一个形参名a前加*号
    print(b)#1
    print(c)#2
    print(a)#(3, 4, 5, 6)
func1(1,2,3,4,5,6)


 def func2(b, *a):
     print(a, b)
 func2()  # 报错,函数至少需要一个参数给到b
 func2(1)  # () 1
 func2(1, 2, 3, 4)  # (2, 3, 4) 1
  • 如果在最后一个形参名前加**号,那么在调用函数时,多余的关键字参数会被组织成字典的形式赋值给**号后面的变量名。
def a1(**k):
    print(k)
a1()  # {}
a1(a=1)  # {'a': 1}
a1(a=1, b=2)  # {'a': 1, 'b': 2}

    def func4(a, **k):
        print(a, k)
        func4()  # 函数至少需要一个参数给到a
        func4(a=1)  # 1 {}
        func4(a=1, b=2, c=3)  # 1 {'b': 2, 'c': 3}
        func4(a=1, b=2, c=3, x='jason', y='kevin')  # 1 {'b': 2, 'c': 3, 'x': 'jason', 'y': 'kevin'}
  • 混合使用
def a1(*args, **kwargs):
    print(args, kwargs)
a()  # () {}
a(a=1)  # () {'a': 1}
a(a=1, b=2, c=3)  # () {'a': 1, 'b': 2, 'c': 3}
a(a=1, b=2, c=3, x='jason', y='kevin')  # () {'a': 1, 'b': 2, 'c': 3, 'x': 'jason', 'y': 'kevin'}


def a(n, *args, **kwargs):
    print(n, args, kwargs)
# a()  # 报错至少有一个b参数
a(1, 2, 3)  # 1 (2, 3) {}
a(111, a=1, b=2, c=3)  # 111 () {'a': 1, 'b': 2, 'c': 3}
a(n=111, a=1, b=2, c=3)  # 111 () {'a': 1, 'b': 2, 'c': 3}
a(a=1, b=2, c=3, n=111)  # 111 () {'a': 1, 'b': 2, 'c': 3}
a(1, 2, 3, a=1, b=2, c=3)  # 1 (2, 3) {'a': 1, 'b': 2, 'c': 3}

# 因为在写函数中*和**在函数的形参中使用频率很高 后面跟的变量名推荐使用增加兼容性。
*args
    **kwargs
def index(*args,**kwargs):pass # 函数体只有一行可以写在一行

2、可变长实参

  • 实参中的*会将参数的值循环取出,打散成位置实参。
def a(a, b, c):
    print(a, b, c)
l1 = ['红', '白', '蓝']
# 方法1索引取值(不推荐)
a(l1[0], l1[1], l1[2])  # 红 白 蓝
# 方法二用*来进行赋值
a(*l1)  # 红 白 蓝
l2 = ['aaa', 'bbb', 'ccc']
a(*l2)  # aaa bbb ccc
s1 = 'tom'
a(*s1)  # t o m 打印单个字符赋值到abc中
set1 = {123, 1231, 321}  # 集合不能重复否则会报错
a(*set1)  # 321 123 1231
dic1 = {'username': 'jason', 'pwd': 123, 'age': 18}
a(*dic1)  # username pwd age取的是键
a(*dic1.values())  # jason 123 18取的是值

  • *在实参中类似于for循环 将所有循环遍历出来的数据按照位置参数一次性传给函数
def user_info(name, password, age):
    print(name, password, age)
d1 = {'name': 'Jason', 'password': 123, 'age': 18}
user_info(name=d1['name'], password=d1['password'], age=d1['age'])  #  Jason 123 18
user_info(*d1.values())  # Jason 123 18
  • **在实参中将字典打散成关键字参数的形式传递给函数
def index(username, pwd, age):
    print(username, pwd, age)
d1 = {'username': 'jason', 'pwd': 123, 'age': 18}
index(username=d1.get('username'), pwd=d1.get('pwd'), age=d1.get('age'))# 使用get获取字典的值输入到index函数中
index(**d1)# 使用**号把字典中的值遍历到index函数中
index(username='jason',pwd=123,age=18)# 直接使用键值对赋值
  • 混合使用
def index(*args, **kwargs):
    print(args,kwargs)
index(*(11, 22, 33, 44), **{'age':66})
# (11, 22, 33, 44) {'age': 66} 

六、命名关键字参数

eg:
def index(name, *args, gender='male', **kwargs):
    print(name, args, gender, kwargs)
index('jason',1,2,3,4,a=1,b=2)
# jason (1, 2, 3, 4) male {'a': 1, 'b': 2} 默认参数输出
index('jason', 1, 2, 3, 4, gender='female', b=2)
# jason (1, 2, 3, 4) female {'b': 2} 关键字参数输出

eg:
def index(name, *, gender='male', **kwargs):
    print(name, gender, kwargs)
index('jason', gender='female', b=2)

# *args限制后面的参数只能为关键字参数进行传输

七、名称空间与作用域

1、名称空间

名称空间就是存放名字与对象映射/绑定关系的地方。

x=1
首先需要申请内存空间存放对象1,然后将名字x与1的绑定关系存放在名称空间。
若删除x表示清除该绑定关系。

2、内置名称空间

伴随python解释器运行自动产生,里面包含了很多名字。

eg:len print input

3、全局名称空间

python文件运行产生,里面存放文件级别的名字。

name = 'jason'
        if name:
            age = 18
        while True:
            gender = 'male'
        def index():
            pass
        class MyClass(object):
            pass
存放着一些变量名(name/gender)、函数名(index)、类名等等

4、局部名称空间

伴随函数的调用/结束而临时产生/回收,函数的形参、函数内定义的名字都会被存放于该名称空间中。

def foo(x):
    y=3 #调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中
  • 名称空间的加载顺序是:内置名称空间->全局名称空间->局部名称空间,而查找一个名字,必须从三个名称空间之一找到,查找顺序为:局部名称空间->全局名称空间->内置名称空间。

5、名称空间存活周期及作用域

  • 存活周期

    内置名称空间:python解释器启动创建,关闭则销毁

    全局名称空间:python文件执行创建,文件结束则销毁

    局部名称空间:函数体代码运行创建,函数体代码运行结束销毁

  • 作用域

    内置名称空间:解释器级别全局有效

    全局名称空间:Python文件级别的全局有效

    局部名称空间:函数体代码内有效

八、名字的查找顺序

首先,涉及到名字的查找要先搞明白自己在哪个空间。

1.当我们在局部名称空间中的时候

​ 局部名称空间 >>> 全局名称空间 >>> 内置名称空间

2.当我们在全局名称空间中的时候

​ 全局名称空间 >>> 内置名称空间

3、案例

1.相互独立的局部名称空间默认不能够互相访问
	 def func1():
    	name = 'jason'
    	print(age)

    def func2():
       age = 18
       print(name)
# 相互之间不存在联系,也就输出不了任何东西

2.局部名称空间嵌套
	先从自己的局部名称空间查找,之后由内而外依次查找。
"""
函数体代码中名字的查找顺序在函数定义阶段就已经固定死了
	x = '干饭了' # 全局作用域名字x
    def func1():
        x = 1    # 局部作用域名字x
        def func2():
            x = 2
            def func3():
                print(x) # 在局部里找x
                x = 3 #将此定义与上方print操作交换顺序,可得到输出结果3
            func3()
        func2()
    func1()
"""

作业

判断下列money的值是多少并说明理由 思考如何修改而不是新增绑定关系
	money = 100
	def index():
        money = 666	
 	print(money)
    # money = 100,因为print(money)是直接打印,属于全局作用域
    #修改
    money = 100
def index():
    money=666
    print(money)
index()
    
   

	money = 100
 	def func1():
        money = 666
        def func2():
            money = 888
        func2()
   print(money)
# print还是在最外层,作用于全局,所以money=100
#修改
money = 100
def func1():
    money = 666
    def func2():
        money = 888
        print(money)#888
    func2()
    print(money)#666
func1()
print(money)#100
posted @ 2022-10-10 20:31  知了了了了  阅读(136)  评论(0)    收藏  举报