1

在编程语言中,函数定义时用的是形参,调用时用的是实参。

形参,全称为"形式参数",不是实际存在的变量,又称虚拟变量。形参是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数

实参,全称为"实际参数",是在调用时传递给函数的参数。实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。

形参和实参的功能是数据传送。

2

调用函数时,实参将赋值给形参。必须注意实参的个数、类型应与形参要一一对应,并且实参必须要有确定的值。形参的作用域一般仅限函数体内部,而实参的作用域根据实际设置而定。

Python语言中提供了一种关键字参数的机制,可以给开发者提供更大的灵活性。如函数func()定义时形式参数的顺序是func(x, y),但是调用时实际参数的顺序可以是func(y = 1, x = 2)。

3

在函数调用中,实参的值被传递给函数的形参。这个过程确实涉及到将一个值赋给一个变量,因此可以看作是一种赋值操作。实参的值被赋给相应的形参,使得函数在执行时可以使用这些值。

然而,传递参数的过程与一般的赋值操作还有一些不同之处:

1形参和实参是独立的变量:当实参的值传递给形参时,它们在内存中是独立的变量。修改形参的值不会影响实参的值,因为它们是两个不同的变量。

2传递方式:参数传递可以是按值传递(pass-by-value)或按引用传递(pass-by-reference),这取决于编程语言的特性。在按值传递的情况下,实参的值被复制到形参中,对形参的修改不会影响实参。而在按引用传递的情况下,实参的引用(地址)被传递给形参,对形参的修改会影响实参。

在Python中,实际上是按对象引用传递(pass-by-object-reference)的,而不是按引用传递。这意味着对象的引用被传递给函数的形参,形参和实参引用同一个对象。实参的引用被传递给形参,函数内部可以通过形参来访问和修改实参所引用的对象。当传递可变对象(如列表或字典)时,对形参对象的修改会影响实参。但是当传递不可变对象(如数字、字符串或元组)时,形参的修改不会影响实参,因为不可变对象是无法修改的。

Python的参数引用机制被认为是其设计的亮点之一。

通过按对象引用传递参数,Python能够在函数调用过程中高效地处理对象,同时提供了灵活性和直观性。以下是一些Python参数引用机制的优点:

1对象共享:通过引用传递,多个变量可以引用相同的对象。这意味着可以节省内存,并且对于可变对象,多个变量可以同时对其进行操作。

2不可变对象的安全性:对于不可变对象(如数字、字符串、元组),保证了其值不会被函数修改,从而避免了潜在的副作用。

3可变对象的直接修改:对于可变对象(如列表、字典),函数内部对形参对象的修改会直接反映在实参上,无需使用返回值来获取修改后的结果。

4函数副作用控制:由于参数传递是按对象引用传递的,函数可以通过修改可变对象来产生副作用,但对于不可变对象,函数无法修改实参的值。

4

参数分为可变类型和不可变类型,其调用结果是不同的。

(1)可变类型:类似c++的引用传递,如列表、字典等。如果传递的参数是可变类型,则在函数内部对传入参数的修改会影响到外部变量。

(2)不可变类型:类似c++的值传递,如整数、字符串、元组等。如果传递的参数是不可变类型,则在函数内部对传入参数的修改不会影响到外部变量。

5

可给每个形参指定默认值。

def enroll(name, gender, age='18', city='Beijing'):

定义时必选参数在前,默认参数在后。默认参数在调用时可省略。

默认参数必须指向不可变对象,否则可能会出现错误

def test_add(a=[]):
    a.append('END')
    return a



print(test_add([1, 2, 3]))
print(test_add(['a', 'b', 'c']))
print(test_add())
print(test_add())
print(test_add())



结果:

[1, 2, 3, 'END']
['a', 'b', 'c', 'END']
['END']
['END', 'END']
['END', 'END', 'END']

默认参数是空列表[],但是函数test_add()似乎每次都“记住了”上次添加了’END’后的list。这是因为在Python语言中,函数在定义的时候,默认参数的值就被计算出来了,它指向对象[]。每次调用该函数,如果改变了其内容,则下次调用时,就不再是函数定义时的[]了。

开发者也可以用None这个不可变对象来解决错误,如下代码所示。

def test_add(H=None):
    if H is None:
        H = []
    H.append('END')
    return H


print(test_add())
print(test_add())

结果:
['END']
['END']

对于str、None等类似的不可变对象一旦创建,其内部数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多线程环境下同时读取对象不需要加锁,同时读也没有问题。开发者在编写程序时,如果可以设计一个不可变对象,就尽量设计成不可变对象。

6

is 是一个用于比较对象身份的操作符。它用于检查两个对象是否引用同一个内存位置,也就是它们是否是同一个对象。具体来说,当使用 is 操作符时,它会检查两个对象的身份标识是否相同,而不是比较它们的值。如果两个对象具有相同的身份标识,即它们引用同一个内存地址,则 is 操作符返回 True。如果两个对象的身份标识不同,则返回 False。

a = [1, 2, 3]
b = a
c = [1, 2, 3]


print(a is b)  # 输出 True,a和b引用同一个列表对象
print(a is c)  # 输出 False,a和c引用不同的列表对象

需要注意的是,is 操作符用于比较对象的身份标识,而 == 操作符用于比较对象的值。