函数及其参数的使用

函数及其参数的使用

一 函数的基本使用

1 什么是函数

​ 函数就是具备某一功能的工具。

2 为什么要有函数

### 1.对于内置函数来说,主要是为了:
	(1) 提升开发效率。

### 2.对于自定义函数来说:
    (1) 为了增强程序的组织结构性、提升可读性;
    (2) 减少代码冗余;
    (3) 提升程序的可维护性与扩展性。

### PS:自定义函数是把程序中实现某一功能的代码组织整理到一起。

3 如何用函数

3.1 使用的原则:

先定义,后调用。

3.2 定义/调用函数的基本语法:

# 定义函数:
def func(参数1,参数2,···):
    '''文档注释'''
    code1
    code2
    code3
    ···
    return 返回值

# 调用函数,函数名加括号
func(参数1,参数2,···)

3.3 定义函数的本质:

​ 定义函数就是申请内存空间把函数替代码保存下来,然后把内存地址绑定给函数名——》函数名=函数的内存地址。

def sayhello():
    print("=" * 10)
    print('hello')
    print("=" * 10)

print(sayhello)  # <function sayhello at 0x0000012A35F15F70>

3.4 调用函数的本质:

函数名+括号——》函数的内存地址+(),会触发函数体代码的运行。

sayhello()  # ==========
			# hello
			# ==========

4 定义函数的三种格式

# 无参函数/有参函数/空函数
### 4.1 无参函数
即定义了一个不需要传参数的函数。
def login():
    inp_name = input('your name:').strip()
    inp_pwd = input('your pwd:').strip()
    if inp_name == 'zhangsan' and inp_name == '123':
        print('login successful')
    else:
        print('login error')
login()
### 4.2 有参函数
即定义了一个需要传参数的函数。
def max2(x, y):
    if x > y:
        print(x)
    else:
        print(y)
max2(11,22)  # 22
### 4.3 空函数
顾名思义,即定义了一个实际没有函数体代码的函数,一般用于开发中的功能占位,后续会补全功能。
def func():
    pass  # 使用···也可以

5 函数的返回值

5.1 return是什么

​ 函数体代码结束的标志是return,而且调用函数一定会有返回值。函数内可以有多个return,但只要执行一次,函数就会立即结束,并会把return后的值当作本次调用的结果返回。

5.2 函数返回值的三种形式

#### (1) return 值:
​		返回的就是该值本身。
def func():
    return 123

res = func()
print(res)  # 123
#### (2) return 值1,值2,值3:
​		返回值为多个时,会返回一个元组。
def func():
    return 123, "abc", 3.1

res = func()
print(res)  # (123, 'abc', 3.1)
#### (3) 没有return:
​		默认返回None。
def func():
    # return None  属于多此一举,本身就默认了返回None
    pass

res = func()
print(res)  # None

6 函数调用的三种形式:

def max2(p1_msalary, p2_msalary):
    if p1_msalary > p2_msalary:
        return p1_msalary
    else:
        return p2_msalary
    
x = max2(10, 11)
print(x * 12)

6.1 语句形式:单纯的调用函数

print("hello world")  # 调用内置函数print
max2(10,11)

6.2 表达式形式:作为表达式的一部分

x = max2(1, 2)
res = max2(1, 2) * 12
print(res)

6.3 可以把函数的调用当作值传给另一个函数:

print(max2(1, 2))

res = max2(max2(10, 11), 12)
print(res)

7 总结:函数使用的两个阶段

函数的使用一定要分两个阶段去看:

1.定义阶段:只检测语法,不执行代码;如果发生语法错误,会立即被检测出来。

def func():
    print("hello"  # SyntaxError: unexpected EOF while parsing

2.调用阶段:执行函数体代码;如果发生的错误不是语法错误,而是逻辑错误,只能在调用阶段检测到。

def func():
    xxx

func()  # NameError: name 'xxx' is not defined

二 函数的参数

1 函数参数的两大分类

#### 1.1 形参:
在定义函数时,括号内定义的变量名,称之为形式参数,简称形参==》相当于变量名,用于接收外部传来的值。
def func(x, y):
    x = 1
    y = 2

print(x)  # NameError: name 'x' is not defined
print(y)  # NameError: name 'y' is not defined
#### 1.2 实参:
在调用阶段,括号内传入的值,称之为实际参数,简称实参==》变量值,用于为形参赋值用。
func(1, 2)
#### 1.3 总结:
在函数调用时,会将实参的值绑定给形参,这种绑定关系只能在函数内使用,在函数调用完毕后,实参会与形参接触绑定,回收占用的内存空间。

2 在python中参数的种类

2.1 位置参数

2.1.1 位置形参,定义及特点:
##### ①定义:

在函数定义阶段按照从左到右的顺序依次定义形参(变量名) ,称之为位置形参。

##### ②特点:

必须被传值,不能多,也不能少。
def func(x, y):
    print(x, y)

func(1, 2)  # 1 2
func(1)  # TypeError: func() missing 1 required positional argument: 'y'
2.1.2 位置实参,定义及特点:
##### ①定义:

在函数的调用阶段,按照从左到右的顺序依次定义实参(传入的变量值) ,称之为位置实参。

##### ②特点:

按照位置传值,一一与形参对应。
def func(x, y):
    print(x, y)

func(1, 2)  # 1 2
func(2, 1)  # 2 1

2.2 关键字实参,定义、特点及混用:

#### (1) 定义:

在函数调用阶段按照key = value 的形式为指定的形参名传值,该形式称之为关键字实参。

#### (2) 特点:

在传值时可以完全打乱顺序,但是仍然能够指名道姓的为指定的形参传值。
def func(x, y):
    print(x, y)

func(1, 2)  # 1 2
func(y=2, x=1)  # 1 2
2.2.1 注意:混用位置实参与关键字实参时

①位置实参必须放在关键字实参前面;

def func(x, y):
    print(x, y)

func(1, 2, x=111)  # TypeError: func() got multiple values for argument 'x'

②不能为同一个形参重复赋值。

def func(x, y):
    print(x, y)

# func(1, y=2)  # 1 2  操作正确,无问题
func(y=2, 1)  # SyntaxError: positional argument follows keyword argument

2.3 默认形参,定义及特点:

#### (1) 定义:
在函数定义阶段就已为某个形参赋值,该形参称之为有默认值的形参,简称默认形参。

#### (2) 特点:
定义阶段就已经被赋值,意味着在函数的调用阶段可以不用为其赋值。
def func(x, y=1111):
    print(x, y)

func(1)  # 1 1111
func(1,2222)  # 1 2222
2.3.1 注意:3个注意事项

①默认形参应该放在位置形参后面;

def func(y=1, x):
    print(x, y)

func(2)  # SyntaxError: non-default argument follows default argument

②默认形参的值通常是不可变类型;因为函数的调用应该做到彼此之间没有关联。

def func(name, names=[]):
    names.append(name)
    print(names)

func("name1")  # ['name1']
func("name2")  # ['name1', 'name2']
func("name3")  # ['name1', 'name2', 'name3']

解决办法:
def func(name, names=None):
    if names == None:
        names = []
    names.append(name)
    print(names)

func("name1")  # ['name1']
func("name2")  # ['name2']
func("name3")  # ['name3']

③默认形参的值只在函数定义阶段被赋值一次,函数定义之后的改变对形参没有影响。

m = 333

def func(x, y=m):  # y=333
    print(x, y)

m = 44444
func(1)  # 1 333

三 *与**在形参中的使用

1 可变长参数

​ 可变长参数指的是参数的个数不固定。

​ 站在实参的角度,实参是用来为形参赋值的,如果实参的个数不固定,那么必须有对应的形参能够接受溢出的实参。

1.1 在形参中使用*与**

#### (1) 在形参名前加*: 
​		*会把溢出的位置实参汇总存成元组,然后赋值给其后的形参名。
# 代码示例:
def add(*nums):
    res = 0
    # print(nums)  # (1, 2, 3)
    for num in nums:
        res += num
    return res

res = add(1,2,3)
print(res)  # 6
===========分割线============
def add(*nums):
    res = ''
    print(nums)  # ('你', '好', '啊')
    for num in nums:
        res += num
    return res
res = add('你','好','啊')
print(res)  # 你好啊
#### (2) 在形参名前加**:
​		**会把溢出的关键字实参汇总存成字典,然后赋值给其后的形参名。
# 代码示例:
def func(x, **y):
    print(x)
    print(y)

func(1, a=111, b=222, c=333)  # 1
                              # {'a': 111, 'b': 222, 'c': 333}
func(a=111, b=222, x=1, c=333)  # 1
                                # {'a': 111, 'b': 222, 'c': 333}

1.2 在实参中用*与**:

#### (1) 在实参名前加*
​		*会把其后的值分解成位置实参。
# 代码示例:
def func(x, y, z):
    print(x, y, z)

nums = [1, 2, 3]
func(*nums)  # 1 2 3 ;相当于func(1,2,3)

str1 = '你好啊'
func(*str1)  # 你 好 啊
#### (2) 在实参名前加**:
​		**会把其后的值分解成关键字实参。	
# 代码示例:
def func(x, y, z):
    print(x, y, z)

dic = {'y':111, 'z':222, 'x':333}
func(*dic)  # y z x
func(**dic)  # 333 111 222 ; func(y=111,z=222,x=333)

1.3 在形参与实参中混用*与**

def index(x, y, z, a, b, c):
    print('index===>', x, y, z, a, b, c)

def wrapper(*args, **kwargs):  # args=(1, 2, 3,)   kwargs={"a":111,"b":222,"c":333}
    index(*args, **kwargs)  # index(*(1, 2, 3,),**{"a":111,"b":222,"c":333})
                            # #  index(1,2,3,c=333,b=222,a=111)
wrapper(1, 2, 3, a=111, b=222, c=333)  # index===> 1 2 3 111 222 333

2 命名关键字参数以及参数组合使用顺序(了解)

#### 1.命名关键字参数:
​		在*与**之间的参数,无论是什么形式(key=value 或 只有参数名) ,都是命名关键字参数,如果没有事先被赋值,那么必须被传值。
# 示例一:
def func(*args, y, **kwargs):
    print(args)
    print(y)
    print(kwargs)


# func(1,2,3,a=1,b=2,c=3)  # 报错,不可以这样传值,必须给y赋值
func(1,2,y=3,a=1,b=2,c=3)  # 正确传值方式
# (1, 2)
# 3
# {'a': 1, 'b': 2, 'c': 3}
# 示例二:
def func(*args, x=1, y, **kwargs):
    print(args)
    print(x, y)
    print(kwargs)

func(1, 2, y=3)  #  (1, 2)
                 # 1 3
                 # {}
func(1, 2, x=111, y=3)  # (1, 2)
                        # 111 3
                        # {}
#### 2.参数的组合使用顺序
​		位置参数,默认参数,可变长度参数,命名关键字参数,可变长度参数
def func(x, y=111, *args, z, **kwargs):
    pass

3 函数参数的总结

	形参中带*与**是汇总操作;

​	实参中带*与**是分解操作。
posted @ 2020-03-10 23:01  越关山  阅读(215)  评论(0)    收藏  举报