【大数据 / Python / KEN】Python 函数(11)

函数

首次发布时间:2020/8/4
最后修改时间:2020/8/4
本系列文章基于 python3 版本

摘要
  • 什么是函数
  • 如何定义一个函数
  • 调用一个函数
  • 函数的文档说明
  • 函数的参数
    • 带参数的函数
    • 什么是参数?
      • 缺省参数
      • 不定长参数
    • 调用带有参数的函数
    • 什么是函数的返回值
    • 函数的嵌套调用
  • 局部变量和全局变量
    • 局部变量
    • 全局变量
  • 递归函数
  • 匿名函数
    • 使用匿名函数

什么是函数?


  • 之前学的内容,都是一句一句的从上往下依次执行的

  • 并且如果有需要重复用到的代码,要再重新写一下

  • 在程序开发的过程中,经常需要某块代码多次执行

  • 但是为了提高编写效率,通过代码的重(chong)用,把具有独立功能的代码块,组织成一个小模块,这就是函数

如何定义一个函数


def 函数名():
    代码
  • 代码示例:
def func():
    print('the name of this function is func()')

调用一个函数


  • 调用函数通过 函数名() 即可完成调用
def func():
    print('the name of this function is func()')

func()
  • 输出结果:
the name of this function is func()

定义函数名字遵循大小驼峰命名方法
我习惯用小驼峰

函数的文档说明


def add(a, b):
    "对两个数求和"
    print(a + b)

add(1, 2)

help(add)  # 获取 add 函数的帮助信息
  • 输出结果:
3
Help on function add in module __main__:

add(a, b)
    对两个数求和

函数的参数


带参数的函数

  • 假设我们的函数内的参数是写死的
  • 那么,这个函数就只能计算我们写的那两个数的乘积,这个函数也就失去了意义
  • 为了让一个函数更通用,比如可以计算任意两数的积,可以定义两个参数,让个两个参数代表任意的两个数字

什么是参数?

  • 参数就可以理解为是一个代表性的字符
  • 这个字符你可以让它代表 1,也可以代表 2,任意你想让他代表的数字
缺省参数
  • 所谓缺省参数,顾名思义,就是在声明函数的某个参数的时候,为之指定一个默认值
  • 如果你没有指定该参数,在调用该函数的时候就采用该默认值

注意:带有默认值的参数一定要位于参数列表的最后面

def add(a, b=3):
    "对两个数求和"
    print('a 是 {}'.format(a))
    print('b 是 {}'.format(b))
    print('a+b 的和是:{}'.format(a + b))

add(1, 2)

add(1)
  • 输出结果:
a 是 1
b 是 2
a+b 的和是:3
a 是 1
b 是 3
a+b 的和是:4
不定长参数
  • 有时可能需要一个函数能处理比一开始声明时更多的参数
  • 这些参数叫做 不定长参数,声明时 不会命名参数
def funcname([formal_args], *args, **kwargs):
    "函数文档说明"
    代码
    返回值

*args:存放所有未命名的变量参数,args元组
**kwargs:存放所有未命名的变量参数,**kwargs 接收的是字典格式,即 kwargs 是一个字典

def func(item, *args, **kwargs):
    print("item 是:{}".format(item))
    print("args 是:" + str(args))
    print("args 的类型是:" + str(type(args)))
    print("args 的元素是:")
    for i in args:
        print(i)
    print("-"*40)
    print("kwargs 是:" + str(kwargs))
    print("kwargs 的类型是:" + str(type(kwargs)))
    print("kwargs 的元素是:")
    for k, v in kwargs.items():
        print(k + ":" + str(v))  # k 一定是字符串,所以不需要用 str() 转换
                                 # 而 v 有可能是字符串,有可能是数字,所以需要用 str() 转换一下

func(1, 'a', 'b', 'c', name='lisa', age=18)  # 注意传递的参数要对应
  • 输出结果:
item 是:1
args 是:('a', 'b', 'c')
args 的类型是:<class 'tuple'>
args 的元素是:
a
b
c
----------------------------------------
kwargs 是:{'name': 'lisa', 'age': 18}
kwargs 的类型是:<class 'dict'>
kwargs 的元素是:
name:lisa
age:18

调用带有参数的函数

  • 如上面所写的 add() 函数,在调用该函数时,需要传入两个参数
def add(a, b):
    "对两个数求和"
    print('a 是 {}'.format(a))
    print('b 是 {}'.format(b))
    print('a+b 的和是:{}'.format(a + b))

add(2, 4)  # 调用带参数的函数时,需要在小括号中,传递数据(参数)
  • 输出结果:
a 是 2
b 是 4
a+b 的和是:6
  • 定义函数时,小括号中的参数,是用来接收参数用的,称为形参

  • 调用函数时,小括号中的参数,是用来传递数据给函数用的,称为实参

  • 大家可以用一下这个网站,它会将运行过程展示出来,能够帮助我们理解程序的运行:

什么是函数的返回值

def add(a, b):
    "对两个数求和"
    print('a 是 {}'.format(a))
    print('b 是 {}'.format(b))
    print('a+b 的和是:{}'.format(a + b))
    return a+b

print('返回值是:' + str(add(2, 4)))
  • 输出结果:
a 是 2
b 是 4
a+b 的和是:6
返回值是:6
  • 上面的代码中,return a+b 就是返回值的过程,返回的是 a+b 的值
  • 另外,返回值可以是有多个的:
def func():
    a = 2
    b = 3
    return a, b

print(func())
  • 输出结果:
(2, 3)

返回的结果是元组类型

函数的嵌套调用

  • 之前讲的 if、while 可以嵌套使用,达到想要的效果
  • 函数也是可以嵌套使用,而且是非常常用的
def func1():
    print('This is func1()')

def func2():
    print('This is the head of func2()')
    func1()
    print('This is the end of func2()')

func2()
  • 输出结果:
This is the head of func2()
This is func1()
This is the end of func2()

局部变量和全局变量


局部变量
def func1():
    a = 1
    print('a 是 {}'.format(a))
    a = 6
    print('a 变为了 {}'.format(a))

func1()


def func2():
    a = 3
    print('a 是 {}'.format(a))

func2()
  • 输出结果:
a 是 1
a 变为了 6
a 是 3
  • 上面 func1()func2() 定义的变量 a 就是局部变量
  • 局部变量作用域是有限的
    • 比如上面的例子中,变量 a 出了函数 func1func2 的定义范围,就没用了,不存在了
  • 所以说,不同函数,可以定义同名的变量,互相不会有影响
  • 局部变量,就是为了临时保存数据,需要在函数中定义变量来进行存储
  • 关键的一点是,局部变量的作用域仅限于在函数
全局变量
  • 如果一个变量能在一个函数里面使用,又可以在其他函数里面使用,这种变量我们称为全局变量
a = 10

def func1():
    global a
    print('a 是 {}'.format(a))
    a = 6

def func2():
    print('a 是 {}'.format(a))

func1()

func2()
  • 输出结果:
a 是 10
a 是 6
  • 如果要在函数里面修改全局变量的值,必须要声明 global a
  • 否则如果直接就赋值的话,会报错
    • (系统会认为你在函数内定义了一个局部变量,而该局部变量和全局变量重名了)
  • 全局变量能够在所有的函数中进行访问
  • 对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用 global无法修改全局变量(像上面的例子)
  • 对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用 global 时也可以修改全局变量(请看下面的例子)
a = [1, 2, 3, 4, 5, 6]

def func1():
    print('a 是 {}'.format(a))
    a[0] = 6


def func2():
    print('a 是 {}'.format(a))


func1()

func2()
  • 输出结果:
a 是 [1, 2, 3, 4, 5, 6]
a 是 [6, 2, 3, 4, 5, 6]
  • 这里是修改列表 a 的元素,如果要对 a 整个重新赋值
  • 就像这样:a = [6, 5, 4, 3, 2, 1]
  • 也是需要声明 global 的,否则也会报错
  • 所以我们可以得出一个结论:
    • 在函数中不使用 global 声明全局变量时不能修改全局变量,
    • 本质是不能修改全局变量的指向,即不能将全局变量指向新的数据
    • 有点类似于,可以修改对象的,但是无法修改地址(不声明 global 的情况下)

递归函数


  • 之前说的一个函数可以调用另外一个函数
  • 那么函数自己调用自己本身的话,这个函数就是递归函数
  • 用途:
    • 比如说,计算 6 的阶乘:1x2x3x4x5x6
    def func(num):
        if num >= 1:
            result = num * func(num-1)
        else:
            result = 1
    
        return result
    
    print(func(6))
    
    • 输出结果:
    720
    

如果你学过 c、c++ 或 java 等语言,你可能会有个疑惑
为什么 result 是在 if...else... 里面定义的,但是出了 if 语句的范围还可以用
因为 Python 中并不是所有语句块都会产生作用域
只有在 Module(模块)Class(类)def(函数) 中定义的时候,才会有作用域的概念
详细可以参考这篇文章:Python学习之变量的作用域

  • 其实上面的函数内部也可以用循环来实现
def func(num):
    result = 1
    while num >= 1:
        result *= num
        num -= 1

    return result

print(func(6))
  • 输出结果是一样的

匿名函数


  • lambda 关键词能创建小型匿名函数

  • 这种函数省略了用 def 声明函数的标准步骤

  • 语法:
    lambda [arg1 [,arg2,.....argn]]: expression

    • lambda 参数列表 : 返回 [表达式] 变量
    • 由于 lambda` 返回的是函数对象(构建的是一个函数对象),所以需要定义一个变量去接收
  • 代码实例:

sum = lambda arg1, arg2 : arg1 + arg2

# 调用 sum 函数
print("两个数的和是:{}".format(sum(1, 2)))
  • 输出结果:
两个数的和是:3
  • lambda 只是一个表达式,函数体比 def 简单很多
  • 仅仅能在 lambda 表达式中封装有限的逻辑进去
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外全局命名空间里的参数
  • 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数
    • 后者的目的是调用小函数时不占用栈内存从而增加运行效率
  • lambda 函数能接收任何数量参数但只能返回一个表达式的值
  • 匿名函数不能直接调用 print(),因为 lambda 需要一个表达式
使用匿名函数
ladies = [
    {"name":"lisa", "age":18}, 
    {"name":"emma", "age":19}, 
    {"name":"penny", "age":17}
]

ladies.sort(key = lambda x : x['name'])
print(ladies)

ladies.sort(key = lambda x : x['age'])
print(ladies)
  • 输出结果
[{'name': 'emma', 'age': 19}, {'name': 'lisa', 'age': 18}, {'name': 'penny', 'age': 17}]
[{'name': 'penny', 'age': 17}, {'name': 'lisa', 'age': 18}, {'name': 'emma', 'age': 19}]

对于 sort(key = lambda x : x['name']) 这种写法的理解
可以参考这篇文章:python-文件字符分布

思考


  • 函数实现一个判断用户输入的年份是否是闰年的程序

    • 提示:
    1. 能被 400 整除的年份
    2. 能被 4 整除,但是不能被 100 整除的年份
    • 以上 2 种方法满足一种即为闰年
  • 实现方法:

def leapYear(year):
    "如果输入的年份是闰年,返回 True,否则返回 False"
    if year % 4 == 0:
        if year % 100 != 0:
            return True
        else:
            if year % 400 == 0:
                return True
            else:
                return False
    else:
        return False

print(leapYear(128))  # True

print(leapYear(100))  # False

print(leapYear(400))  # True

print(leapYear(3))  # False
  • 输出结果:
True
False
True
False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值