飞桨百度领航团零基础学Python之函数(一)

函数基础

  • 前言
  • 1.定义函数
    • 1.1 函数结构
    • 1.2 函数返回值
    • 1.3 函数调用
  • 2. 函数参数传递
    • 2.1 位置参数
    • 2.2 缺省参数
    • 2.3 可变参数
    • 2.4 关键字参数
    • 2.5 命名关键字参数
    • 2.6 参数的组合
  • 3. 变量
  • 总结

前言

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。Python提供了许多内建函数,比如print()。但也可以自己创建函数,这被叫做用户自定义函数。

1.定义函数

1.1 函数结构

def student_name(name):
    "打印学生的名字"
    print('姓名:', name)
    return {
     '姓名':name}
    
rst = student_name('Alice')
rst 

函数运行结果如下:

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

1.2 函数返回值

# 返回多个值
def student_name_and_age():
    "记录学生的名字和年龄"
    name = input('请输入姓名\n')
    age = int(input('请输入年龄\n'))
    print(f'姓名:{name};年龄:{age}')
    return name,age
rst = student_name_and_age()

输入姓名和年龄后,函数运行结果如下:

请输入姓名
请输入年龄
姓名:Molly;年龄:19

注:不同于C++语言,Python可以返回多个值
下面来查看一下,rst 的类型,是元组类型

print(rst)	#('Molly', 19)
type(rst)	#结果为tuple类型

也可以分别返回多个值,如下所示

name, age = student_name_and_age()	
print(name,age)		#Molly 19

1.3 函数调用

在实际应用中,经常使用函数的嵌套调用。

## 函数的嵌套调用
def worker(s):
    rst = 10 / float(s)
    return rst

def group_leader(s):
    rst = worker(s) * 2
    return rst

def CTO(s):
    return group_leader(s)
    
CTO('4')	#运行结果为5.0

2. 函数参数传递

函数的参数包括以下几种参数,下面分别进行介绍。

  • 位置参数
  • 缺省参数
  • 可变参数
  • 关键字参数
  • 命名关键字参数

2.1 位置参数

位置参数是最简单的一种函数调用的方式。位置参数须以正确的顺序传入函数、数量必须和声明时的一样。

def student_name_and_age(name, age):
    print('姓名:%s 年龄 %s' %(name, age))
student_name_and_age('张三', 18)

函数调用结果如下:

姓名:张三 年龄 18

2.2 缺省参数

调用函数时,缺省参数的值如果没有传入,则被认为是默认值。

def student_name_and_age(name, age='不愿透露'):
    "设置默认参数"
    print('姓名:%s 年龄 %s' %(name, age))
student_name_and_age('张三')

运行结果如下:

姓名:张三 年龄 不愿透露

也可以为默认参数赋值

student_name_and_age('张三', 18)

运行结果如下:

姓名:张三 年龄 18

2.3 可变参数

顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个,这些可变参数在函数调用时自动组装为一个tuple。

def all_student_names(*names):
    for name in names:
        print('姓名:', name)
all_student_names('张三','李四','王五')

运行结果如下:

姓名: 张三
姓名: 李四
姓名: 王五

也可以用位置参数调用的方法,实现上述函数的功能

def all_student_names(names):
    for name in names:
        print('姓名:', name)
names = ('张三','李四','王五')
all_student_names(names)

运行结果如下:

姓名: 张三
姓名: 李四
姓名: 王五

2.4 关键字参数

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

def student_info(name, age, **kw):
    print(f'我的名字叫:{name},年龄:{age},其它信息:{kw}')
student_info('张三', 18, height=180)

运行结果如下:

我的名字叫:张三,年龄:18,其它信息:{
     'height': 180}

还可以通过字典的key值对输出值进行限制

def student_info(name, age, **kw):
    print(f'我的名字叫:{name},年龄:{age},其它信息:{kw}')
    if 'city' in kw:
        print('来自:', kw['city'])
student_info('张三', 18, height=180, city='北京')

运行结果如下:

我的名字叫:张三,年龄:18,其它信息:{
     'height': 180, 'city': '北京'}
来自: 北京

下面来介绍一个关键字参数应用的场景。原始需求:要求编写代码输出某人的姓名、年龄、语文成绩和数学成绩。实现代码如下:

def score_info(name, yuwen, shuxue):
    print(name, '的语文成绩', yuwen)
    print(name, '的数学成绩', shuxue)

def person_info(name, age, yuwen, shuxue):
    print('姓名:', name, '年龄',age)
    score_info(name, yuwen, shuxue)    

person_info('张三', 18, 65, 60)

运行结果如下:

姓名: 张三 年龄 18
张三 的语文成绩 65
张三 的数学成绩 60

此时提出新的需求:在原有输出基础上,再输出英语成绩。最简单的方法就是:在person_info函数中传入英语成绩,在person_info函数中传入参数,在score_info函数中传入参数并增加英语成绩输出语句。需要改动的地方很多,如果需要增加新的需求工作量很大。
如果采用关键字参数,可以用如下代码实现:

def score_info(name, **kw):
    if '语文成绩' in kw:
        print(name, '的语文成绩', kw['语文成绩'])
    if '数学成绩' in kw:
        print(name, '的数学成绩', kw['数学成绩'])
        

def person_info(name, age, **kw):
    print('姓名:', name, '年龄',age)
    score_info(name, **kw)    

score_cfg = {
     '语文成绩':65, '数学成绩':60}
person_info('张三', 18, **score_cfg)

用关键字参数 kw 代替位置参数,这样因为需求改动代码,工作量会小很大。如果想要加入打印英语成绩的功能,则只需要改变关键字参数score_cfg的内容,并在函数score_info中增加打印英语成绩的语句。person_info函数完全无需改变,因为**kw不关心传入内容是什么。第三方库涉及到层层调用和传参,它背后的实现原理与此类似。

2.5 命名关键字参数

如果要限制关键字参数的名字,就可以用命名关键字参数。* 后面的参数不仅需要提供值还需要提供参数名。这样可以避免代码版本迭代后,忘记位置参数对应的含义,导致输出错误的情况发生。

def print_person_info(name, age, *, height, weight):
    print('我的名字叫:', name, '年龄:', age,'身高', height, '体重', weight)
print_person_info('张三', 18, height=180, weight=75)

运行结果如下:

我的名字叫: 张三 年龄: 18 身高 180 体重 75

2.6 参数的组合

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
下面给出几个实例:

def student_info(name, age=18, *books, **kw):
    print('我的名字叫:', name, '年龄:', age,'其它信息:',kw)
    if 'city' in kw:
        print('来自:', kw['city'])
    for book in books:
        print('我有',book,'书')
student_info('张三', 18, '语文','数学','计算机', city='北京', height=180, weight=75)

运行结果如下:

我的名字叫: 张三 年龄: 18 其它信息: {
     'city': '北京', 'height': 180, 'weight': 75}
来自: 北京
我有 语文 书
我有 数学 书
我有 计算机 书

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

def student_info(name, age=18, *books, city, **kw): 
    print('我的名字叫:', name, '年龄:', age,'其它信息:',kw)
    print('来自:', city)
    for book in books:
        print('我有',book,'书')
student_info('张三', 18, '语文','数学','计算机', city='北京', height=180, weight=75)

运行结果如下:

我的名字叫: 张三 年龄: 18 其它信息: {
     'height': 180, 'weight': 75}
来自: 北京
我有 语文 书
我有 数学 书
我有 计算机 书

注:为了避免奇怪的错误发生,建议尽量减少使用参数组合。

3. 变量

下面介绍变量的作用域和global变量。变量分为以下两种:

  • 局部变量 作用域:在函数内
  • 全局变量 作用域:在函数外

下面给出几2个变量使用的例子:

#例1
name = '张三'
def print_my_name():
    name='李四'
    print(name)
    
print_my_name()		#运行结果:李四

函数优先使用局部变量,在没有局部变量的情况下,使用全局变量。因此例1运行结果为李四,例2运行结果为张三。

#例2
name = '张三'

def print_my_name():
    print(name)
    
print_my_name()		#运行结果:张三

注意:定义在函数内部的变量,函数结束之后自动消亡。如果再次使用函数内部的变量将会报错。

def get_my_name():
    new_name = '赵四'
get_my_name()
new_name

报错信息如下:

---------------------------------------------------------------------------NameError                                 Traceback (most recent call last)<ipython-input-47-50225d753478> in <module>
      3     new_name = '赵四'
      4 get_my_name()
----> 5 new_name
NameError: name 'new_name' is not defined

下面这个例子可以进一步加深我们对局部变量和全局变量的理解。我们希望下面的代码可以先输出“我的名字曾经是张三”,然后再输出“我的名字现在是李四”。

def change_my_name():
   print('我的名字曾经是', name)
   name = '李四'
   print('我的名字现在是', name)
name = '张三'
change_my_name()
name

结果运行之后报错,报错信息如下:

---------------------------------------------------------------------------UnboundLocalError                         Traceback (most recent call last)<ipython-input-49-9452ee1a9be8> in <module>
      1 name = '张三'
----> 2 change_my_name()
      3 name
<ipython-input-48-a750cf076394> in change_my_name()
      1 def change_my_name():
----> 2    print('我的名字曾经是', name)
      3    name = '李四'
      4    print('我的名字现在是', name)
UnboundLocalError: local variable 'name' referenced before assignment

报错信息显示局部变量’name’在赋值之前被引用。但根据“函数优先使用局部变量,在没有局部变量的情况下,使用全局变量。”的原则,全局变量name已经被赋值为张三了,应该不会报错呀。
这和Python的机制有关,一旦在函数体内部对同名的全局变量赋值,则同名的全局变量就变为局部变量,且未被赋值。因此会报错。如果使用global变量就可以解决这个问题。

def change_my_name():
    global name
    print('我的名字曾经是', name)
    name = '李四'
    print('我的名字现在是', name)
name = '张三'
change_my_name()
name

运行结果如下,没有报错。

我的名字曾经是 张三
我的名字现在是 李四
'李四'

总结

本文主要介绍了函数的定义、函数参数的传递,以及变量的作用域。函数的定义中具体介绍了如何定义一个函数,函数的调用以及函数的返回值。函数参数的传递中详细介绍了几种参数的调用,变量部分介绍了局部变量、全局变量和global变量。下一篇文章将介绍高阶Python函数。

你可能感兴趣的:(Python基础,python,编程语言)