函数基础
函数的作用
所谓函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候进行调用
=> 一些已经实现的功能,比如sum(数组),这种就应该封装为函数,避免重复造轮子函数的作用,在开发程序时,使用函数可以提高编写的效率以及代码的重用.
函数的基本使用
函数的定义
定义函数的格式如下:
def 函数名(): # 注意缩进4个空格 # 函数封装的代码 # ... pass
- def 是英文define的缩写
- 函数名称 应该能够表达函数封装代码的功能,方便后续的调用 => 尽量做到见名知意.
- 函数名称的命名要符合标识符的命名规则
- 可以由字母,下划线,数字组成
- 不能由数字开头
- 不能与关键字重名
=> 这个标识符的规定基本高级语言都是一致的,从C语言开始.
函数调用
调用函数很简单,通过函数名()
即可完成对函数的调用
=> 在Python中函数定义在出现在函数调用之前,要让Python知道有这个函数.
第一个函数演练
需求
- 编写一个打招呼
say_hello()
的函数,封装三行打招呼的代码 - 在函数下方调用打招呼的代码
# 定义了函数只表示封装了一段代码而已 # 如果不主动调用函数,函数是不会主动执行的 # def 关键字告诉了Python解释器这里定义了一个函数 def say_hello(): print("hello 1") print("hello 2") print("hello 3") # 调用函数 say_hello()
思考
能否将函数调用放在函数定义之前?
=> 不能!因为在使用函数名调用函数之前,必须保证Python已经知道函数的存在,否则控制台会提示 NameError: name 'say_hello' is not defined
PyCharm的调试工具
- Step Over 可以单步执行代码,会把函数调用看作是一行代码直接执行 => 不进入函数内部
- Step Into 可以单步执行代码,如果是函数,会进入函数内部 => 进入函数内部
函数的文档注释
- Python专门为函数写文档注释的方法是在函数名的下方进行多行注释
def say_hello(): """ 打招呼 => 这就是python的文档注释 => 规范的话是使用3个双引号 """ print("hello 1") print("hello 2") print("hello 3")
- PyCharm中的快速文档 View => QuickDocumentation => 在函数调用的时候就可以快速查看文档
注意:因为函数体相对比较独立,函数定义的上方,应该和其他代码(包括注释)保留两个空行
函数的参数
函数参数的使用
- 在函数名的后面的小括号内部填写参数
- 多个参数之间使用 , 分隔
def sum_2_num(a, b): """ 计算两个数的和 :param a: :param b: :return: """ result = a + b print("%d + %d = %d" % (a, b, result)) sum_2_num(10,20)
参数的作用
- 函数的参数,增加函数的通用性,针对相同的数据处理逻辑,能够适应更多的数据
- 在函数内部,把参数当作变量使用,进行需要的数据处理
- 函数调用时,按照函数定义的参数顺序,把希望在函数内部处理的数据,通过参数传递
形参和实参
- 形参:定义函数时,小括号中的参数,是用来接受参数用的,在函数内部作为变量使用
- 实参:调用函数时,小括号中的参数,是用来把数据传递到函数内部用的
函数的返回值
- 返回值是函数完成工作后,最后给调用者的一个结果
- 在函数中使用
return
关键字返回函数的结果 - 调用函数的一方,可以使用变量来接收函数的返回结果
注意:return
表示返回,后续的代码都不会被执行
def sum_2_num(a, b): """ 计算两个数的和 :param a: :param b: :return: """ result = a + b return result # 使用一个变量来接收函数返回的结果 sum_result = sum_2_num(10,50) print("计算结果为: %d" % (sum_result))
函数的嵌套调用
- 一个函数里面又调用了另外一个函数,这就是函数嵌套调用
- 如果函数
test2()
中,调用了另外一个函数test1()
- 那么执行调用
test1()
函数时,会先把函数test1()
中的任务都执行完,然后回到调用位置的下一行,继续完成后续的代码
```python
def test1():
# python中重复打印使用乘法
print("" 50)
- 那么执行调用
def test2():
print("-" * 50)
# 函数的嵌套调用
test1()
print("+" * 50)
test2()
```
函数嵌套的演练--打印分隔线
体会一下工作中需求是多变的
需求1
定义一个print_line()
函数能够打印 * 组成的一条分割线
def print_line1(): print("*" * 50)
需求2
定义一个函数能够打印由任意字符组成分割线
def print_line2(char): """ 打印任意字符组成的分割线 """ print("%s" % (char) * 50)
需求3
定义一个函数能够打印任意重复次数的分割线
def print_line3(char, times): """ 定义一个函数能够打印任意重复次数的分割线 :param char: 传入的字符 :param times: 打印字符的次数 :return: None """ print(char * times)
需求4
定义一个函数能够打印5行的分隔线,分割线要求符合需求3
提示: 工作中针对需求的变化,应该冷静思考,不要轻易修改之前已经完成的,能够正常执行的函数! => 不要轻易删除之前的文件!!
def print_line3(char, times): print(char * times) def print_line4(char,times): for x in range(5): print_line3(char,times)
使用模块中的函数
模块是Python程序架构的一个核心概念
- 模块就好比是工具包,要想使用这个工具包中的工具,就需要导入 => import这个模块
- 每一个扩展名 py 结尾的Python源代码文件都是一个模块 => 也就是现在写的每一个xxx.py文件都可以作为一个模块,可以被import
- 在模块中定义的全局变量,函数都是能够提供给外界直接使用的工具 => xxx.py中的全局变量和函数都能直接被使用
code06_模块.py
def print_line(char, times): """ 定义一个函数能够打印任意重复次数的分割线 :param char: 传入的字符 :param times: 打印字符的次数 :return: None """ print(char * times) name = "传智-黑马"
code07_模块体验.py
# 导入模块 import code06_模块 # 使用自己写的模块的函数 code06_模块.print_line("*", 50) # 使用自己写的模块的全局变量 print(code06_模块.name)
体验小结
- 可以在一个Python文件中定义变量或者函数,然后在另外一个文件中使用
import
导入这个模块 => Java同一个包内的xxx.java文件可以直接使用,不同包之间的xxx.java也是需要import
的 - 导入之后,可以使用
模块名.变量
/模块名.函数
的方式,使用这个模块中定义的变量或者函数.
模块可以让曾经编写过的代码 方便的被复用
模块名也是一个标识符
- 模块名也就是Python源程序的文件名,命名规则也是要符合标识符的命名规则
注意:如果给Python文件起名时,以数字开头是无法在PyCharm中import这个模块的
Pyc文件
c是compiled 编译过的意思
一般模块文件都是通过测试的,很少修改的,所以有import 模块的时候,就会事先进行编译,就不用一行一行的执行,提高的程序运行速度 => 存放在文件 pycache 中
- 浏览程序目录会发现一个
__pycache__
的目录 - 在该目录中会有一个
code06_模块.cpython-37.pyc
文件- cpython-37表示官方使用C语言开发的Python解释器
- 这个pyc文件是由Python解释器将模块的源码转换为字节码
- Python这样保存字节码是作为一种启动速度的优化
字节码
- Python在解释源程序时是分成两个步骤的
- 首先处理源代码,编译生成一个二进制字节码 => 字节码是一个中间的二进制文件
- 再对字节码进行处理,才会生成CPU能够识别的机器码
- 有了模块的字节码文件之后,如果没有修改过模块的源码,Python将会加载.pyc文件并跳过编译这个步骤.
- 如果修改了模块的源码,下次程序运行时,字节码将会自动重新创建.