函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
你可以定义一个由自己想要功能的函数,以下是简单的规则:
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None
函数基本使用
python中定义函数所用的关键字是def, def 函数名() : 冒号代替其他编程语言的大括号,然后换行缩进写的代码就是函数体。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def example():
'''
一个简单的函数
'''
print("Hello World !")
example()
打印结果:
Hello World !
三引号中间的内容属于函数的注释文档,注释的作用是告诉别人或以后查看代码知道能快速知道这段干嘛是做什么的。
函数还可以嵌套,也就是函数里面有函数
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def exapmle(name):
def go(name):
print('我最棒:' + name)
go(name)
example('小明')
打印结果:
我最棒:小明
形参和实参
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def example(username):
print("Hello World ! My name is " + str(username))
example("小明")
example("小花")
打印结果:
Hello World ! My name is 小明
Hello World ! My name is 小花
这是一个带参数的函数,在函数example中,username就是一个形参,也就是形式参数,是用来接收调用函数时传入的参数,你传的是啥它就是啥,传人它就是人,传鬼它就是鬼的那种。
实参就是实际参数,在调用函数的时候,传递是小明,那么小明就是实参,传递的是小花,那么小花也是实参,实参传递给函数后,会赋值给函数中的形参,然后我们就可以在函数中使用到外部传入的数据了。
写Java的时候最痛恨的就是方法不能设置默认值,使得必须得重载才行。
python允许我们给函数的形参设置一个默认值,不传参数调用的话,就统一默认是这个值。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def welcome(username = '奥特曼'):
print("Hello World ! My name is " + str(username))
welcome("小明")
welcome()
打印结果:
Hello World ! My name is 小明
Hello World ! My name is 奥特曼
在函数中修改参数内容会不会影响到外部,这个问题取决于实参的类型是不是可变的,可不可变就是可不可以修改。
字符串就是一种不可变的类型。
比如:
name = “小明”
name = “小花”
请问,我是把"小明"修改成了"小花"吗? 答案是 非也。
实际上我是把"小花"这个字符串赋值给了name,让name指向了这个新字符串,替换掉了原来的"小明",原来的"小明"仍然是"小明",没有受到一点改变。
在python中,不可变类型有:整数、字符串、元组,可变类型有:列表、字典。如果传递的参数包含可变类型,并且在函数中对参数进行了修改,那么就会影响到外部的值。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def change(lis):
lis[1] = '小明他二舅'
names = ['小明','小花','小红']
change(names)
print(names)
打印结果:
[‘小明’, ‘小明他二舅’, ‘小红’]
如果我们不希望出现这种事情,那么就将对象复制一份再传递给函数。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def change(lis):
lis[1] = '小明他大爷'
names = ['小明','小花','小红']
change(names[:])
print(names)
打印结果:[‘小明’, ‘小花’, ‘小红’]
我们用切片的方法拷贝了一份names,函数中尽管修改了参数,也不过是修改的是副本,不会影响到原始的names。
关键字参数让你可以不用考虑函数的参数位置,你需以键值对的形式指定参数的对应形参。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def welcome(name,address):
print(f"你好 {name} , 欢迎来到 {address} !")
welcome(address='长沙',name='小强')
打印结果:你好 小强 , 欢迎来到 长沙 !
有时候我们需要允许用户提供任意数量的参数,函数的形参可以带个星号来接收,不管调用函数的时候传递了多少实参,都将被收集到形参这个变量当中,形参的类型是元组。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def welcome(*names):
print(names)
welcome('乐迪','天天','酷飞','小黑')
打印结果:(‘乐迪’, ‘天天’, ‘酷飞’, ‘小黑’)
还有一种是带两个星号的形参,用于接收键值对形式的实参,导入到函数中的类型是字典。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def welcome(**names):
print(names)
welcome(name='小明',age=20,sex='男')
打印结果:{‘name’: ‘小明’, ‘age’: 20, ‘sex’: ‘男’}
分配参数是收集参数的相反操作,可使得一个元组或字典变量自动分配给函数中的形参。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def welcome(name,address):
print(f"你好 {name} , 欢迎来到 {address} !")
a = ('小明','广州')
welcome(*a)
打印结果:你好 小明 , 欢迎来到 广州 !
我们改成字典的方式:
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def welcome(name,address):
print(f"你好 {name} , 欢迎来到 {address} !")
a = {'address':'山东','name':'小红'}
welcome(**a)
打印结果:你好 小红 , 欢迎来到 山东 !
首先说明,所有的函数都是有返回值的,如果编程人员没有指定返回值,那么默认会返回None,对标其他语言中的null。
一个简单的函数返回值的例子:
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def get_full_name(first_name,last_name):
return first_name + last_name
r = get_full_name('王','大拿')
print(r)
打印结果:王大拿
然而python中的函数还可以返回多个值,返回出的值被装载到元组中:
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def func(num):
return num**2,num**3,num**4
result = func(2)
print(result)
打印结果:(4, 8, 16)
在python中函数定义的时候没有返回值的签名,导致我们无法提前知道函数的返回值是什么类型,返回的什么完全看函数中的return的是什么,特别是逻辑代码比较多的函数,比如里面有多个if判断,有可能这个判断return出来的是布尔值,另一个判断return出来的是列表,还一个判断啥也不return,你调用的时候你都搞不清楚该怎么处理这个函数的返回值,在这一点来说,Java完胜。
所以在无规则限制的情况下,代码写的健不健壮,好不好用,主要取决于编程人员的素质。
匿名函数就是不用走正常函数定义的流程,可以直接定义一个简单的函数并把函数本身赋值给一个变量,使得这个变量可以像函数一样被调用,在python中可以用lambda关键字来申明定义一个匿名函数。
我们把王大锤的例子改一下:
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
get_full_name = lambda first_name,last_name : first_name + last_name
r = get_full_name('王','大锤')
print(r)
打印结果:王大锤
访问全局作用域
python每调用一个函数,都会创建一个新命名空间,也就是局部命名空间,函数中的变量就叫做局部变量,与外部的全局命名空间不会相互干扰。
这是常规状态,当然也会有非常规需求的时候,所以python给我们提供了globals()函数,让我们可以在局部作用域中访问到全局的变量。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def func():
a = globals()
print(a['name'])
name = '小明'
func()
打印结果:小明
globals()函数只能让我们访问到全局变量,但是是无法进行修改的,如果我们要修改全局变量,需要用到global关键字将全局变量引入进来。
#! /usr/bin/python3
# -*- coding:utf-8 -*-'
# @FileName: day4.py
# @Time : 2020/8/8 20:47
# @Author : 码上开始
def func():
global name
name = '小花'
name = '小明'
func()
print(name)
打印结果:小花