第七章 函数基础

# 第七章 函数基础
## 一、函数定义
### 1、为什么python需要使用函数?
  - 如果你不使用函数,将会出现:代码冗余,复杂度增大,组织结构不够清晰,可读性差,可扩展性差等等,这些缺点却是函数的优点之处。
  - 函数是带名字的代码块,用于完成具体的任务,要执行函数定义的特定任务,可调用该函数。在程序中多次执行同一项任务时,你无需反复编写该任务的代码,而而只需调用该任务的函数,让Python运行其中的代码。
  - 通过使用函数,程序的编写、阅读、测试和修复都将会更容易。
### 2、定义函数
函数定义格式如下:
```python
def 函数名(参数):
  pass
  return 表达式
```
函数名命名规则:字母、数字和下划线组成,和变量命名规则一致。
 
pass在这里表示什么都没有,不执行任何操作。
 
return后面可以返回任何表达式,但不能是赋值语句;return后面没有返回值的话,默认None。
 
下面是一个打印问候语的简单函数,名为greet():
greet.py
```python
def greet():    #数代码块以 def 关键词开头,后接函数标识符名称和圆括号()
  print(‘Hello!‘)    #打印简单的问候语Hello
  
  
greet()    #调用函数,表示去执行该函数
```
  这个实例演示了最简单的函数结构。①处的代码行使用关键字def来告诉python你要定义一个函数,函数名为greet(),括号内可指定函数为完成任务需要带的参数信息,在这里,这个函数不需要任何信息就能完成其工作,因此括号是空的(括号是必不可少)。最后,定义以冒号结束。
  
  紧跟在def greet():后面的所有缩进构成了函数体。②处是函数体内唯一一行代码,greet()函数只做一项工作,打印Hello!。
  
  
  要使用这个函数,可调用它。如④处所示,由于这个函数不需要任何信息,以此调用它只需要输入greet()即可。运行以上代码便可得到结果:
  
---
  Hello!
  
---
  
## 二、函数参数
### 1、什么是函数参数
  函数能把具有独立功能的代码块组织成为一个小模块,在需要的时候调用,而函数的参数能增加函数的通用性,针对相同的数据处理逻辑,能够适应更多的数据。
  
  在使用的过程中,参数有两种形式:形式参数和实际参数,可简单概括:
  - 形参是定义函数的参数
  - 实参是调用函数的参数
  
  根据实际参数类型不同,将实际参数传递给形参的方式有两种:值传递和引用传递,在下一小节--形参和实参详细讲解。
### 2、形参和实参
  形参:函数完成其工作所需的一项信息。即形式参数当作变量使用,进行需要的数据处理。可传多个形参,函数声明时的形参数量和调用函数时传入的实参数量要一致,声明的形参顺序和传入的实参顺序也要一致。
  
  实参:调用函数时传递给函数的信息,即按照函数定义的参数顺序,把希望在函数内部处理的数据,通过参数传递。
  
  将函数名为greet()的函数修改为,可以让函数不仅仅向用户显示Hello!,还可以灵活加入想加的username参数,要求这个函数被调用它时给username指定一个值。调用greet()时,可将名字传递给它,如下所示:
```python
def greet(username):
  print("Hello,"+username+"!")
  
greet(‘jim‘)
```
执行该代码,结果为:
 
---
  Hello,jim!
  
---
  这个实例展示函数里实参和形参的含义。在greet(‘jim‘)中,将实参‘jim’传递给函数greet(),这个值被存储在形参username中。
  
  值传递:实参为不可变对象,传递给形参后,形参的值改变,实参值不变。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
 
  引用传递:实参为可变对象,传递给形参后,形参的值改变,实参值改变。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响。
  
---
注意:在第二、三章介绍的python的数据类型,字符串(strings), 元组(tuples), 和数列(numbers)是不可更改的对象,而列表(list),字典(dict)等则是可以修改的对象。
 
---
```python
def demo(st):
  print(st)
  st+=st
  print(st)
 
end1=‘123‘    
demo(end1)    #实参为字符串,是不可变对象,形参的值改变,实参值不变
print("函数调用后的end1:"+end1)
 
end2=[1,2,3]
demo(end2)    #实参为列表,是可变对象,形参的值改变,实参值改变
print("函数调用后的end2:"+str(end2))
```
执行该代码,结果为:
 
---
123          
 
123123
 
函数调用后的end1:123
 
[1, 2, 3]
 
[1, 2, 3, 1, 2, 3]
 
函数调用后的end2:[1, 2, 3, 1, 2, 3]
 
---
 
### 3、传递实参
  函数的传递实参方式很多,可划分为:必备参数、关键字参数、默认参数、可变参数(不定长参数)、组合参数,总共5种。
#### 1)必备参数(位置参数)
  调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的每个形参。所以,最简单的关联方式基于实参的顺序,这种关联方式被称为位置参数。位置参数要求实参的顺序和形参的顺序相同。
```python
def test(name,age):
  print("My name is " +name+","+" I‘m "+age+" years old today.")
 
test(‘Tom‘,‘18‘)
test(‘Jerry‘,‘16‘)
```
执行该代码,结果为:
 
---
My name is Tom, I‘m 18 years old today.
 
My name is Jerry, I‘m 16 years old today.
 
---
  这个函数的定义表明,形参参数为:name和age,那么,在调用函数时,需要传递两个实参,而且是与形参顺序对应的实参,如果在这个函数调用时,实参是先指定age(‘18‘),再指定name(‘Tom‘),那么结果就会打印成:My name is 18, I‘m Tom years old today.。这结果就不是正确的表达意义了。
 
  调用函数多次是一种效率极高的工作方式。只需再调用函数,写入新的实参,就可以描述新的表意。
#### 2)、关键字参数
  关键字参数要求每一个实参都由变量名和值组成,即直接在实参中将名称和值关联起来了,因此向函数传递实参时不会混淆。关键字实参让你无需考虑函数调用时的实参顺序,还清晰指出了函数调用中各个值的用途。
```python
def test(name,age):
  print("My name is " +name+","+" I‘m "+age+" years old today.")
 
test(name=‘Tom‘,age=‘18‘)
test(age=‘16‘,name=‘Jerry‘)  
```
  执行该代码,结果和位置参数的输出结果一样。那么,总结出关键字实参的顺序无关紧要,因为可以准确地指定函数定义的形参名。
#### 3)默认参数
  函数定义时,可为参数设置一个默认值,在调用函数中形参提供了实参时,Python将使用指定的实参值;否则使用形参的默认值。所以,在形参给定默认值后,可在函数调用中省略相应的实参。使用默认参数可简化函数调用。
```python
#如果介绍的都是18岁的同学,就可将形参参数age默认值设置为‘18‘。
def test(name,age=‘18‘):
  print("My name is " +name+","+" I‘m "+age+" years old today.")
 
test(name=‘Tom‘)
test(name=‘Jerry‘)
```
执行该代码,结果和以上两种传递参数的输出结果一样。
 
---
注意:使用默认值时,在形参列表中必须先列出没有默认值的形参,再列出有默认值的形参,这让Python依然能够正确解读位置实参。
 
---  
#### 4)可变参数(不定长参数)
  有时候,你预先不知道函数需要接受多少个实参,那么,可以传入一个可变参数,即不定长参数,这样,不管调用函数时给了多少个实参,都能够将他们统统收入囊中。
  
  可变参数有两种形式:一种是*args,另一种是**kwargs。
 
  *args:这种形式表示接受任意多个实际参数将其放到一个元组中。
 
  **kwargs:这种形式表示接受任意多个实际参数将其放到一个字典中,类似关键字参数。
```python
#*args形式
 
def demo(*args):
  print(‘我喜欢的城市:‘)
  for i in args:
    print(i)
 
demo(‘深圳‘,‘杭州‘,‘上海‘)    #调用形式:可直接传一个tuple
city=[‘北京‘,‘广州‘,‘哈尔滨‘]     #也可以通过list或者tuple的变量传
demo(*city)
 
#**kwargs形式
def fun(name,age,**kwargs):
    print("name:",name,"age:",age,"other:",kwargs)
 
fun(‘Tom‘,16,sex=‘male‘,job=‘teacher‘)    #结合位置参数和不定长参数传递实参
 
def fun1(**kwargs):
    print("name:age")
    for i,j in kwargs.items():
        print(i,‘:‘,j)
 
di={‘Tom‘:23,‘jin‘:12}    #也可以通过字典变量传
fun1(**di)
```
执行该代码,结果为:
 
---
name: Tom age: 16 other: {‘sex‘: ‘male‘, ‘job‘: ‘teacher‘}
 
name:age
 
Tom : 23
 
jin : 12
 
---
#### 5)组合参数  
  在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数组合使用。但是注意,参数定义的顺序必须是:必备参数、默认参数、可变参数、关键字参数。
  比如定义一个函数,包含上述若干种参数:
```python  
def f1(a, b, c=0, *args, **kw):
    print(‘a =‘, a, ‘b =‘, b, ‘c =‘, c, ‘args =‘, args, ‘kw =‘, kw)
 
def f2(a, b, c=0, *,d, **kw):
    print(‘a =‘, a, ‘b =‘, b, ‘c =‘, c, ‘d =‘, d, ‘kw =‘, kw)
 
f1(1, 2)    #结果为:a = 1 b = 2 c = 0 args = () kw = {}
 
f1(1, 2, c=3)    #结果为:a = 1 b = 2 c = 3 args = () kw = {}
 
f1(1, 2, 3, ‘a‘, ‘b‘)    #结果为:a = 1 b = 2 c = 3 args = (‘a‘, ‘b‘) kw = {}
 
f1(1, 2, 3, ‘a‘, ‘b‘, x=99)    #结果为:a = 1 b = 2 c = 3 args = (‘a‘, ‘b‘) kw = {‘x‘: 99}
 
f2(1, 2, d=99, ext=None)    #结果为:a = 1 b = 2 c = 0 d = 99 kw = {‘ext‘: None}
 
args = (1, 2, 3, 4)    
kw = {‘d‘: 99, ‘x‘: ‘#‘}
f1(*args, **kw)    #结果为:a = 1 b = 2 c = 3 args = (4,) kw = {‘d‘: 99, ‘x‘: ‘#‘}
 
args = (1, 2, 3)
kw = {‘d‘: 88, ‘x‘: ‘#‘}
f2(*args, **kw)    #结果为:a = 1 b = 2 c = 3 d = 88 kw = {‘x‘: ‘#‘}
```
## 三、课堂练习
### 1、编写一个名为hobby()的函数,它创建一个描述人物的爱好的字典。这个函数应接受任务的名字,年龄和性别,并返回名字和爱好的字典。通过使用组合参数的形式展示这一章所学的传递参数的知识。
## 四、上一节课堂练习答案
### 1、打印9*9乘法口诀表
  九九乘法表的阵型图片如下:
 
第七章 函数基础

 第七章 函数基础

- 乘法表几行几列?
 
9*9
 
- 怎么打印横排和竖排?
 
横排: print(‘‘,end=‘\t‘)
 
竖排: print(‘‘)
 
- 那么如何同时打印横竖排?
 
观察第一张乘法表,第一行乘数都是1,被乘数就是1-9,可以理解为,当乘数都是1时,被乘数遍历1-9这九个数字。
```python
for i in range(1,10):
  for j in range(1,10):
    print(‘%s*%s=%s‘%(j,i,i * j),end=‘\t‘)
  print()
```
执行该代码,就能够得到第一张九九乘法表,那么,如何改为第二章典型的九九乘法表呢?观察,可看出,需要删除右上角那一半,都是乘数比被乘数大,可以根据这个条件进行判断。
```python
for i in range(1,10):
     for j in  range(1,10):
        if j > i:
          break
        print("%s*%s=%s"%(j,i,j * i),end=‘\t‘)
     print()
#条件判断还可以写成更简练的代码,可以私下查资料,还有很多大同小异的代码块也能实现九九乘法表。
for i in range(1,10):
     for j in  range(1,i+1):
        print("%d*%d=%d"%(j ,i , j * i),end=‘\t‘ if j<i else ‘\n‘)
```
### 2、打印range(31)除带7或是7的倍数的数以外的所有数,并注明奇数还是偶数。
- 7的倍数怎么确定:
 
i%7==0
 
- 带7的数怎么确定?
 
i//10==7
 
也可以将数值转换为字符串,通过判断‘7‘是否在这个字符串里面
```python
for i in range(31):
  if i%10==7 or i%7==0:
    continue
  else:
    result = str(i)+‘是偶数‘ if i % 2 == 0 else str(i)+‘是奇数‘
    print(result)
```
 
 
 
  
 
 
 
 

相关推荐