Python函数之初识函数及函数参数

函数简介

  • 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

  • 函数是一种仅在调用时运行的代码块。

  • 函数能提高应用的模块性,和代码的重复利用率。

  • 可以将数据(称为参数)传递到函数中,函数可以把数据作为结果返回。

  ''' python 提供了很多内建函数,我们学过的就有很多: '''
  
    print()
    count()
    read()
    split()
    ...
  
  # 除了内建函数,我们还可以自己创建函数,这被叫做用户自定义函数。

创建函数

自定义函数的规则:

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号 : 起始,并且缩进。
  • return [表达式]结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
# 函数的格式

def 函数名(参数1,参数2,...):  # 可不带参数
	"""函数注释"""  # 描述函数功能,参数介绍等信息的文档,非必要
	函数体
	return 值  # 非必要

  1. def
    定义函数的关键字
  2. 函数名
    函数名指向函数内存地址,是对函数体代码的引用。 尽量做到见名知意
    3.括号
    在定义函数的时候函数名后面必须跟括号
  3. 参数
    定义函数括号内可以写参数(个数不固定) 也可以不写参数
    用于接收外界传递给函数体代码内部的数据
  4. 冒号
    括号后要加冒号,然后在下一行开始缩进编写函数体的代码
  5. 函数注释
    类似于说明书,用于介绍函数的主题功能和具体用法。建议加上,从而增强函数的可读性
  6. 函数体代码
    整个函数最核心的区域(逻辑代码)
  7. return
    控制函数的返回值

函数的分类

内置函数

解释器已经定义好的函数,用户可直接调用。例如 len()、print()

ps: 数据类型内置函数则需使用数据类型点的方式才可以调用

自定义函数

  • 空函数

    函数体代码使用pass顶替,暂时没有任何功能

    ​ 主要用于前期的项目搭建,提示主要功能

    def run():
      pass
    
  • 无参函数

    函数定义阶段括号内没有填写参数

    def func():
      print('from func')
    
  • 有参函数

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

    def func(a, b):
      print('from func')
      
    # ps:有参函数调用需要函数名加括号并且给数据值
    
    
    def my_min(x,y):
     res=x if x < y else y
     return res
    

调用函数

使用函数名称后跟括号:

# 定义函数
def my_function():
  print("Hello from a function")

my_function()  # 调用函数
  1. 函数必须先定义后使用
    定义函数的代码必须要在调用函数的代码之前先运行

  2. 函数名绑定的是一块内存地址 里面存放了函数体代码
    要想运行该代码 就需要调用函数>>>:函数名加括号

  3. 调用函数 使用函数名加括号(可能需要添加额外的参数)

  4. 函数在定义阶段只检测函数体代码语法 不执行函数体代码
    只有在调用阶段才会真正的执行函数体代码

    ps :函数名加括号执行优先级最高(定义阶段除外)

调用形式

  • 语句形式
my_function()
  • 表达式形式
m = my_min(1,2) # 将调用函数的返回值赋值给x
n = 10*my_min(1,2) # 将调用函数的返回值乘以10的结果赋值给n
  • 调用带参形式
# my_min(2,3)作为函数my_min的第二个参数,实现了取1,2,3中的较小者赋值给m
m=my_min(1,my_min(2,3))

参数传递

python 函数的参数传递:

  • 不可变类型:如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
# python 传不可变对象实例
# 在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id

>>> def change(a):
...     print(id(a))   # 指向的是同一个对象
...     a=10
...     print(id(a))   # 一个新对象
...
>>> a=1
>>> print(id(a))
1560610826544
>>> change(a)  # 调用change函数
1560610826544
1560610826832
  • 可变类型:如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
# 传可变对象实例
# 可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了


>>> def changeme( mylist ):
...    "修改传入的列表"
...    mylist.append([1,2,3,4])
...    print ("函数内取值: ", mylist)
...    return
...
>>> mylist = [10,20,30]
>>> changeme( mylist )  # 调用changeme函数
函数内取值:  [10, 20, 30, [1, 2, 3, 4]]
>>> print ("函数外取值: ", mylist)
函数外取值:  [10, 20, 30, [1, 2, 3, 4]]

函数的返回值

若需要将函数体代码执行的结果返回给调用者,则需要用到return。return的返回值无类型限制,且可以将多个返回值放到一个元组内。

# 如何获取函数的返回值
	变量名 = 函数调用
  • 函数体代码没有return关键字:默认返回None
def my_function():
    print('from my_function')
   
res = my_function()
print(res)  # None
  • 函数体代码有return关键字:后面不写 也返回None
def my_function():
    print('from my_function')
    return
   
res = my_function()
print(res)  # None
  • 函数体代码有return关键字:return后面写什么就返回什么
# return后面写的是数据值,则直接返回
def my_function():
    print('from my_function')
    return 666

res = my_function()
print(res)



# return后面写的是变量,则需要找到对应的数据值返回
def my_function():
    print('from my_function')
    name = 'kwan'
    return name

res = my_function()
print(res)  # kwan

  • 函数体代码有return关键字并且后面写了多个数据值(名字) 逗号隔开:默认情况下回自动组织成元组返回
def my_function():
    return 1, 2, 3, 4

res = my_function()
print(res)  # (1, 2, 3, 4)


# 当return后面的返回值为列表、字典类型时,直接返回return后面的值
def my_function():
    return [1, 2, 3, 4]

res = my_function()
print(res)  # [1, 2, 3, 4]


# 当return后面有多个返回值的数据类型不同时,则直接返回return后面的值
def my_function():
    return [1, 2, 3, 4], {'name': 'kwan'}, 123

res = my_function()
print(res)  # ([1, 2, 3, 4], {'name': 'kwan'}, 123)

return是一个函数结束的标志,函数内可以有多个return,但函数体代码一遇到return关键字就会立刻结束函数体代码的运行,并把这个return后定义的值作为本次调用的结果返回。

>>> def my_function():
...     print('我在上面')
...     return 123
...     print('我在下面')
...
>>> my_function()
我在上面
123

函数的参数

函数的参数分为形式参数和实际参数,简称形参和实参:

  • 形式参数

    即在定义函数时,括号内声明的参数。形参本质就是一个变量名,用来接收外部传来的值。

  • 实际参数

    即在调用函数时,括号内传入的值,值可以是常量、变量、表达式或三者的组合

在调用有参函数时,实参(值)会赋值给形参(变量名)。在Python中,变量名与值只是单纯的绑定关系,而对于函数来说,这种绑定关系只在函数调用时生效,在调用结束后解除(动态绑定、动态解除)。

位置参数

位置即顺序,位置参数指的是按顺序定义的参数

  • 在定义函数时,按照从左到右的顺序依次定义形参,称为位置形参,凡是按照这种形式定义的形参都必须被传值

    >>> def register(name, age, gender):  # 定义位置形参:name,age,gender,三者都必须被传值
    ...     print('Name:%s Age:%s gender:%s' % (name, age, gender))
    ...
    >>> register()  # TypeError:缺少3个位置参数
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: register() missing 3 required positional arguments: 'name', 'age', and 'gender'
    
  • 在调用函数时,按照从左到右的顺序依次定义实参,称为位置实参,凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应

    >>> def register(name, age, gender):  # 定义位置形参:name,age,gender,三者都必须被传值
    ...     print('Name:%s Age:%s gender:%s' % (name, age, gender))
    ...
    >>> register('kwan', 18, 'female')  # 对应关系为:name='kwan',age=18,gender='female'
    Name:kwan Age:18 gender:female
    

关键字参数

在调用函数时,实参可以是key=value的形式,称为关键字参数。

使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

>>> def register(name, age, gender):  # 定义位置形参:name,age,gender,三者都必须被传值
...     print('Name:%s Age:%s gender:%s' % (name, age, gender))
...
>>>
>>> register(gender='female', name='kwan', age=18)  
Name:kwan Age:18 gender:female

需要注意在调用函数时,实参也可以是按位置或按关键字的混合使用,但必须保证关键字参数在位置参数后面,且不可以对一个形参重复赋值

>>> register('kwan',gender='female',age=18) #正确使用
>>> register(name='kwan',18,gender='female') #SyntaxError:关键字参数name='kwan'在位置参数18之前
>>> register('kwan',gender='female',age=18,name='jack') #TypeError:形参name被重复赋值

默认参数

默认参数及在函数的定义的时候就给了个默认值,在函数调用的时候可以不传这个默认参数。调用函数时,如果没有传递参数,则会使用默认参数。

>>> def register(name, age, gender='male'):  # 默认值gender的值为male
...     print(f"""
...     -------------info-----------
...     name:{name}
...     age:{age}
...     gender:{gender}
...     ----------------------------
...     """)
...
>>> register('oscar', 28)  # 大多数情况,无需为gender传值,默认为male

    -------------info-----------
    name:oscar
    age:28
    gender:male
    ----------------------------

>>> register('kwan', 18, 'female')  # 少数情况,可以为gender传值female

    -------------info-----------
    name:kwan
    age:18
    gender:female
    ----------------------------
    
'''
默认参数必须在位置参数之后
默认参数的值仅在函数定义阶段被赋值一次`
'''

不定长参数

若需要一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数,即调用函数的时,实参的个数是可以不固定的。

# 基本语法
def functionname([formal_args,] *var_args_tuple ):
   "函数_文档字符串"
   function_suite
   return [expression]
  • 加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
>>> def printinfo( arg1, *vartuple ):
...    "打印任何传入的参数"
...    print ("输出: ")
...    print (arg1)
...    print (vartuple)
... 
>>> printinfo( 70, 60, 50 )  # 调用printinfo 函数
输出:
70
(60, 50)

如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。

>>> def printinfo( arg1, *vartuple ):
...    "打印任何传入的参数"
...    print ("输出: ")
...    print (arg1)
...    for var in vartuple:
...       print (var)
...    return
...
>>> printinfo( 10 )  # 调用printinfo 函数
输出:
10
>>> printinfo( 70, 60, 50 )  # 调用printinfo 函数
输出:
70
60
50
  • 参数带两个星号 ** 基本语法如下:
def functionname([formal_args,] **var_args_dict ):
   "函数_文档字符串"
   function_suite
   return [expression]

加了两个星号 ** 的参数会以字典的形式导入。

>>> def printinfo( arg1, **vardict ):
...    "打印任何传入的参数"
...    print ("输出: ")
...    print (arg1)
...    print (vardict)
...
>>> printinfo(1, a=2,b=3)  # 调用printinfo 函数
输出:
1
{'a': 2, 'b': 3}

声明函数时,参数中星号 * 可以单独出现。如果单独出现星号 *,则星号 * 后的参数必须用关键字传入:

>>> def f(a,b,*,c):
...     return a+b+c
... 
>>> f(1,2,3)   # 报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1,2,c=3) # 正常
6

* 与 ** 在实参中的作用

  • * 在实参中 会将 * 后面的数据相当于用for循环一次性一个个传入函数

  • ** 在实参中 相当于将字典里的键值对作为关键字传入函数

>>> def func(*args, **kwargs):  # 相当于无参
...     print(args)
...     print(kwargs)
...

# *args,**kwargs相当于无参,可以不传参
>>> func()
()
{}

# 列表为一个元素
>>> func([1, 2, 3, 4, 5, 6])
([1, 2, 3, 4, 5, 6],)
{}



'''将列表元素一个个传入函数'''
>>> l1 = [1, 2, 3, 4, 5, 6]
>>> func(l1[0], l1[1], l1[2], l1[3], l1[4], l1[5])
(1, 2, 3, 4, 5, 6)
{}

'''  * 在实参中 会将 * 后面的数据相当于用for循环一次性一个个传入函数'''
# 使用 * 可以得到和以上相同效果
>>> func(*l1)  # func(1,2,3,4,5,6)
(1, 2, 3, 4, 5, 6)
{}

>>> s = 'hello'  
>>> func(*s)  # func('h','e','l','l','o')
('h', 'e', 'l', 'l', 'o')
{}

>>> d = {'1': 'kwan', '2': 18}
>>> func(*d)  # func('1','2')
('1', '2')
{}


'''  ** 在实参中 相当于将字典里的键值对作为关键字传入函数  '''

>>> d1 = {'username': 'kwan', 'pwd': 123}
>>> func(**d1)
()
{'username': 'kwan', 'pwd': 123}

>>> func(username='kwan', pwd=123)
()
{'username': 'kwan', 'pwd': 123}

命名关键字参数(冷门了解)

def func(a, b, *args):
    pass


func(1, 2)
func(a=1, b=2)
func(1, b=222)
'''需要形参在传实参的时候 必须按照关键字参数才可以'''


# 在形参*args的后面
def func(a, b, *args, c):
    print(a, b, args, c)


func(1, 2, 3, 4, 5, 6, 7)  # 报错
func(1, 2, 3, 4, 5, 6, c=666)


# 如果形参中还有**kwargs 那必须在它的前面
def func(a, b, *args, c, **kwargs):
    pass


func(1, 2, 3, 4, 5, 6, c=123, name='kwan')
posted @ 2022-06-30 21:36  梦想有双休  阅读(30)  评论(0)    收藏  举报