python入门笔记12——函数用法和底层分析(1)

函数用法和底层分析

  函数是可重用的程序代码块。函数的作用,不仅可以实现代码的复用,更能实现代码的一致性。一致性指的是,只要修改函数的代码,则所有调用该函数的地方都能得到体现。
  在编写函数时,只是对代码实现了封装,并增加了函数调用、传递参数、返回计算结果等内容。

函数简介

函数的基本概念

  1. 一个程序由一个个任务组成;函数就是代表一个任务或者一个功能。
  2. 函数是代码复用的通用机制。

Python 函数的分类

  Python 中函数分为如下几类:

  1. 内置函数 我们前面使用的 str()、list()、len()等这些都是内置函数,我们可以拿来直接使用。
  2. 标准库函数 我们可以通过 import 语句导入库,然后使用其中定义的函数
  3. 第三方库函数 Python 社区也提供了很多高质量的库。下载安装这些库后,也是通过 import 语句导入,然后可以使用这些第三方库的函数
  4. 用户自定义函数 用户自己定义的函数,显然也是开发中适应用户自身需求定义的函数。

函数的定义和调用

核心要点

Python 中,定义函数的语法如下:
def 函数名 ([参数列表]) :
  &’’‘文档字符串’’’
  函数体/若干语句

要点:

  1. 我们使用 def 来定义函数,然后就是一个空格和函数名称。
    (1) Python 执行 def 时,会创建一个函数对象,并绑定到函数名变量上。
  2. 参数列表。
    (1) 圆括号内是形式参数列表,有多个参数则使用逗号隔开。
    (2) 形式参数不需要声明类型,也不需要指定函数返回值类型。
    (3) 无参数,也必须保留空的圆括号。
    (4) 实参列表必须与形参列表一一对应。
  3. return 返回值。
    (1) 如果函数体中包含 return 语句,则结束函数执行返回值
    (2) 如果函数体中不包含 return 语句,则返回 None 值。
  4. 调用函数之前,必须要先定义函数,即先调用 def。
    (1) 内置函数对象会自动创建。
    (2) 标准库和第三方库函数,通过 import 导入模块时,会执行模块中的 def 语句。

形参和实参

  首先来看一个例子:定义一个最大值函数,打印三个数中的最大值。

def printMax(a,b,c):
    print("最大值为:",max([a,b,c]))
    
if __name__ == '__main__':
    printMax(10,5,8)

执行结果:

最大值为: 10

  上面的 printMax 函数中,在定义时写的 printMax(a,b,c)。a 、 b和c 称为“形式参数”,简称“形参”。也就是说,形式参数是在定义函数时使用的。 形式参数的命名只要符合“标识符”命名规则即可。
  在调用函数时,传递的参数称为“实际参数”,简称“实参”。上面代码中,printMax(10,5,8),10 、5和 8就是实际参数。

文档字符串(函数的注释)

  程序的可读性最重要,一般建议在函数体开始的部分附上函数定义说明,这就是“文档字符 串”,也有人成为“函数的注释”。我们通过三个单引号或者三个双引号来实现,中间可以加入多行文字进行说明。

代码示例:测试文档字符串的使用

def print_star(n):
    '''
    根据传入的 n,打印多个星号
    '''
    print("*"*n)

help(print_star)

执行结果:

Help on function print_star in module __main__:

print_star(n)
    根据传入的 n,打印多个星号

返回值

return 返回值要点:

  1. 如果函数体中包含 return 语句,则结束函数执行并返回值。
  2. 如果函数体中不包含 return 语句,则返回 None 值。
  3. 要返回多个返回值,使用列表、元组、字典、集合将多个值“存起来”即可。

代码示例:定义一个打印 n 个星号的无返回值的函数

def print_star(n):
    '''
    根据传入的 n,打印多个星号
    '''
    print("*"*n)

print_star(5)

代码示例:定义一个返回两个数平均值的函数

def return_avg(a, b):
    return (a+b)/2
    
#如下是函数的调用
c = return_avg(100,90)
print(c)

函数也是对象,内存底层分析

  Python 中,“一切都是对象”。实际上,执行 def 定义函数后,系统就创建了相应的函数对象。

代码示例:

def print_star(n):
    print("*"*n)

print(print_star)
print(id(print_star))
c = print_star
c(3)

执行结果:

<function print_star at 0x000002254BEC51F0>
2359210824176
***

  上面代码执行 def 时,系统中会创建函数对象,并通过 print_star 这个变量进行引用:
在这里插入图片描述
  执行“c=print_star”后,显然将 print_star 变量的值赋给了变量 c,内存图变成了:
在这里插入图片描述
  显然,我们可以看出变量 c 和 print_star 都是指向了同一个函数对象。因此,执行 c(3)和执行 print_star(3)的效果是完全一致的。Python 中,圆括号意味着调用函数。在没有圆括号的情况下,Python 会把函数当做普通对象。
  与此核心原理类似,我们也可以做如下操作:

代码示例:

zhengshu = int
print(type(zhengshu("234")))

执行结果

<class 'int'>

  显然,我们将内置函数对象 int()赋值给了变量 zhengshu,这样 zhengshu 和 int 都是指向了同一个内置函数对象。当然,此处仅限于原理性讲解,实际开发中没必要这么做。

变量的作用域(全局变量和局部变量)

  变量起作用的范围称为变量的作用域,不同作用域内同名变量之间互不影响。变量分为:全局变量、局部变量。

全局变量:

  1. 在函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始直到模块结束。
  2. 全局变量降低了函数的通用性和可读性。应尽量避免全局变量的使用。
  3. 全局变量一般做常量使用。
  4. 函数内要改变全局变量的值,使用 global 声明一下

局部变量:

  1. 在函数体中(包含形式参数)声明的变量。
  2. 局部变量的引用比全局变量快,优先考虑使用。
  3. 如果局部变量和全局变量同名,则在函数内隐藏全局变量,只使用同名的局部变量

代码示例:全局变量的作用域测试

a = 100
def f1():
    global a
    print("打印全局变量:",a)

if __name__ == '__main__':
    f1()

执行结果:

打印全局变量: 100

代码示例:全局变量和局部变量同名测试


执行结果

a = 100
def f1():
    a = 3 #定义同名局部变量
    print(a)

f1()
print(a) #全局变量a依然是100没有变化

代码示例:输出局部变量和全局变量

a = 100
def f1(a):
    print(a)
    print(locals())
    print("#"*100)
    print(globals())
if __name__ == '__main__':
    f1(5)

执行结果

5
{
    
    'a': 5}
####################################################################################################
{
    
    '__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000206BF9A1970>, '__spec__': None, '__annotations__': {
    
    }, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/python/fzbaishijiaoyu/python_coding/打印局部变量和全局变量.py', '__cached__': None, 'a': 100, 'f1': <function f1 at 0x00000206BF9861F0>}

局部变量和全局变量效率测试

  局部变量的查询和访问速度比全局变量快,优先考虑使用,尤其是在循环的时候。
  在特别强调效率的地方或者循环次数较多的地方,可以通过将全局变量转为局部变量提高运行速度.

测试代码示例:

import math
from timeit import Timer
def t1():
    for i in range(10000):
        math.sqrt(30)
def t2():
    b = math.sqrt
    for i in range(10000):
        b(30)
timer1 = Timer("t1()","from __main__ import t1")
print("全局变量消耗时间:",timer1.timeit(5000))
timer2 = Timer("t2()","from __main__ import t2")
print("局部变量消耗时间:",timer2.timeit(5000))

执行结果

全局变量消耗时间: 9.5024587
局部变量消耗时间: 7.018546599999999

猜你喜欢

转载自blog.csdn.net/weixin_45031468/article/details/112299687
今日推荐