需要注意的是,return 语句在同一函数中可以出现多次,但只要有一个得到执行,就会直接结束函数的执行。
现在我们利用 return 关键字 ,尝试自定义一个 capitalize 函数。示例如下:
def capitalize(data):
index = 0
temp = ‘’
for item in data:
if index == 0:
temp = item.upper()
else:
temp += item
index += 1
return temp
result = capitalize(‘hello , Jack’)
print(result)
>>> 执行结果如下
>>> Hello , Jack
再一次注意到,只要有一个得到执行,就会直接结束函数的执行。
return 与 print 的区别
-
print 只是单纯的将对象打印输出,并不支持赋值语句。
-
return 是对函数执行结果的返回,且支持赋值语句;但是我们可以将含有 renturn 值的函数放在 print 里进行打印。
-
必传参数:平时最常用的,必传确定数量的参数
-
默认参数:在调用函数时可以传也可以不传,如果不传将使用默认值
-
不确定参数:可变长度参数(也叫可变参数)
-
关键字参数:长度可变,但是需要以 key-value 形式传参
必传参数
什么是必传参数? —> 在定义函数的时候,没有默认值且必须在函数执行的时候传递进去的参数;且顺序与参数顺序相同,这就是必传参数。
-
函数中定义的参数没有默认值,在调用函数的时候,如果不传入参数,则会报错。
-
在定义函数的时候,参数后边没有等号与默认值。
-
错误的函数传参方式:def add(a=1, b=1)
错误示例如下:
def add(a, b):
return a + b
result = add()
print(result)
>>> 执行结果如下
>>> TypeError: add() missing 2 required positional arguments: ‘a’ and ‘b’
正确的示例如下:
def add(a, b):
return a + b
result = add(1, 2)
print(result)
>>> 执行结果如下
>>> 3
>>> add 函数有两个参数,第一个参数是 a,第二个参数是 b
>>> 传入的两个整数按照位置顺序依次赋给函数的参数 a 和 b,参数 a 和参数 b 被称为位置参数
传递的参数个数必须等于参数列表的数量
-
根据函数定义的参数位置来传递参数,要求传递的参数与函数定义的参数两者一一对应
-
如果 “传递的参数个数” 不等于 “函数定义的参数个数”,运行时会报错
错误传参数量示例如下:
def add(a, b):
return a + b
sum = add(1, 2, 3)
>>> 执行结果如下
>>> sum = add(1, 2, 3)
>>> TypeError: add() takes 2 positional arguments but 3 were given
默认参数
-
在定义函数的时候,定义的参数含有默认值,通过赋值语句给参数一个默认的值。
-
使用默认参数,可以简化函数的调用,尤其是在函数需要被频繁调用的情况下
-
如果默认参数在调用函数的时候被给予了新的值,函数将优先使用新传入的值进行工作
示例如下:
def add(a, b, c=3):
return a + b + c
result = add(1, 2) # 1 对应的 a ;2 对应的 b ; 没有传入 C 的值,使用 C 的默认值 3。
print(result)
>>> 执行结果如下
>>> 6
def add(a, b, c=3):
return a + b + c
result = add(1, 2, 7) # 1 对应的 a ;2 对应的 b ; 传入 C 的值为 7,未使用 C 的默认值 3。
print(result)
>>> 执行结果如下
>>> 10
不确定参数(可变参数)
- 这种参数没有固定的参数名和数量(不知道要传的参数名具体是什么)
不确定参数格式如下:
def add(*args, **kwargs):
pass
*args :将无参数的值合并成元组
**kwargs :将有参数与默认值的赋值语句合并成字典
-
*args 代表:将无参数的值合并成元组
-
**kwargs 代表:将有参数与默认值的赋值语句合并成字典
从定义与概念上似乎难以理解,现在我们通过示例来看一下:
def test_args(*args, **kwargs):
print(args, type(args))
print(kwargs, type(kwargs))
test_args(1, 2, 3, name=‘Neo’, age=18)
>>> 执行结果如下
>>> (1, 2, 3) <class ‘tuple’>
>>> {‘name’: ‘Neo’, ‘age’: 18} <class ‘dict’>
>>> args 将输入的参数转成了一个元组
>>> kwargs 将输入的赋值语句转成了一个字典
>>> 在使用的时候,我们还可以根据元组与字典的特性,对这些参数进行使用;示例如下:
def test_args(*args, **kwargs):
if len(args) >= 1:
print(args[2])
if ‘name’ in kwargs:
print(kwargs[‘name’])
test_args(1, 2, 3, name=‘Neo’, age=18)
>>> 执行结果如下
>>> 3 根据元组特性,打印输出 args 索引为 2 的值
>>> Neo 根据字典特性,打印输出 kwargs 的 key 为 name 的 value
def test_args(*args, **kwargs):
if len(args) >= 1:
print(args[2])
else:
print(‘当前 args 的长度小于1’)
if ‘name’ in kwargs:
print(kwargs[‘name’])
else:
print(‘当前 kwargs 没有 key为 name 的元素’)
test_args(1, 2, 3, name1=‘Neo’, age=18)
>>> 执行结果如下
>>> 3 根据元组特性,打印输出 args 索引为 2 的值3
>>> 当前 kwargs 没有 key为 name 的元素(传入的 kwargs 为 name1=‘Neo’, age=18;没有 name)
参数规则
def add(a, b=1, *args, **kwargs)
-
参数的定义从左到右依次是
a - 必传参数
、b - 默认参数
、可变的 *args 参数
、可变的 **kwargs 参数
-
函数的参数传递非常有灵活性
-
必传参数与默认参数的传参也非常具有多样化
示例如下:
def add(a, b=2):
print(a + b)
我们来看一下该函数可以通过哪些方式传递参数来执行
add(1, 2) # 执行结果为 : 3
add(1) # 执行结果为 : 3
add(a=1, b=2) # 执行结果为 : 3
add(a=1) # 执行结果为 : 3
add(b=2, a=1) # 执行结果为 : 3
add(b=2)
执行结果为 : TypeError: add() missing 1 required positional argument: ‘a’ 。
(因为 a 是必传参数,这里只传入 b 的参数是不行的)
def test(a, b, *args):
print(a, b, args)
int_tuple = (1, 2)
test(1, 2, *int_tuple)
>>> 执行结果如下
>>> 1 2 (1, 2)
***********************************************************
def test(a, b, *args):
print(a, b, args)
int_tuple = (1, 2)
test(a=1, b=2, *int_tuple)
>>> 执行结果如下
>>> TypeError: test() got multiple values for argument ‘a’
>>> 提示我们参数重复,这是因为 必传参数、默认参数、可变参数在一起时。如果需要赋值进行传参,需要将可变参数放在第一位,然后才是 必传参数、默认参数。(这是一个特例)
************************************************************
def test(*args, a, b):
print(a, b, args)
int_tuple = (1, 2)
test(a=1, b=2, *int_tuple)
>>> 执行结果如下
>>> 1 2 (1, 2)
>>> 这种改变 必传参数、默认参数、可变参数 的方式,一般我们是不推荐使用的
def test(a, b=1, **kwargs):
print(a, b, kwargs)
test(1, 2, name=‘Neo’)
test(a=1, b=2, name=‘Jack’)
test(name=‘Jack’, age=18, a=1, b=2)
>>> 执行结果如下
>>> 1 2 {‘name’: ‘Neo’}
>>> 1 2 {‘name’: ‘Jack’}
>>> 1 2 {‘name’: ‘Jack’, ‘age’: 18}
注意:如果传参的顺序发生变化,一定要使用赋值语句进行传参。
需求:定义一个 login 函数,向函数内传入形参 username,password,当 username 值为 admin 且password值为字符串 123456 时,返回“登录成功”;否则返回“请重新登录”
def login(username, password):
定义一个登录函数,传入 username, password 必填参数
if username == “admin” and password == “123456”:
使用if语句,判断用户名和密码为“admin”和“123456”
print(“登录成功”) # 返回登录成功
else:
使用else子句处理用户名和密码非“admin”和“123456”的情况
print(“请重新登录”) # 返回请重新登录
调用函数,向函数内传入’admin’,‘123456’和’test’,'123456’两组数据测试结果
login(username=“admin”, password=“123456”) # 打印函数测试结果
login(username=“test”, password=“123456”) # 打印函数测试结果
前文我们学习了函数的定义方法与使用方法,在定义参数的时候我们并不知道参数对应的数据类型是什么。都是通过函数体内根据业务调用场景去判断的,如果传入的类型与也无偿性不符,就会产生报错。现在我们学习一种方法,可以在定义函数的时候,将参数类型与参数一同定义,方便我们知道每一个参数需要传入的数据类型。
我们来看一个例子:
def person(name:str, age:int=18):
print(name, age)
-
必传参数:参数名 + 冒号 + 数据类型函数 ,为声明必传参数的数据类型
-
默认参数:参数名 + 冒号 + 数据类型函数 + 等号 + 默认值,为声明默认参数的数据类型
-
需要注意的是,对函数的定义数据类型在 python 3.7 之后的版本才有这个功能
-
虽然我们给函数参数定义了数据类型,但是在函数执行的时候仍然不会对参数类型进行校验,依然是通过函数体内根据业务调用场景去判断的。这个定义方法只是单纯的肉眼上的查看。
示例如下:
def add(a: int, b: int = 3):
print(a + b)
add(1, 2)
add(‘Hello’, ‘World’)
>>> 执行结果如下:
>>> 3
>>> HelloWorld
def add(a: int, b: int = 3, *args:int, **kwargs:str):
print(a, b, args, kwargs)
add(1, 2, 3, ‘4’, name=‘Neo’)
>>> 执行结果如下:
>>> 1 2 (3, ‘4’) {‘name’: ‘Neo’}
我们发现执行的函数并没有报错,add(‘Hello’, ‘World’) 也通过累加的方式拼接在了一起
所以说,虽然我们定义了 int 类型,但是并没有做校验,只是单纯的通过肉眼告知我们参数是 int 类型,后续我们进入python高级进阶阶段可以自己编写代码进行校验。
-
全局变量:在当前 py 文件都生效的变量
-
在 python 脚本最上层代码块的变量
-
全局变量可以在函数内被读取使用
-
局部变量:在函数内部,类内部,lamda.的变量,它的作用域仅在函数、类、lamda 里面
-
在函数体内定义的变量
-
局部变量无法在自身函数以外使用
全局变量
示例如下:
coding:utf-8
name = ‘Neo’
age = 18
def test01():
print(name)
def test02():
print(age)
def test03():
print(name, age)
test01()
test02()
test03()
>>> 执行结果如下:
>>> Neo
>>> 18
>>> Neo 18
>>> 这里我们可以看到声明的 全局变量 在多个函数体内都可以被使用
局部变量
示例如下:
coding:utf-8
name = ‘Neo’
age = 18
def test01():
name = ‘Jack’
age = 17
print(‘这是函数体内的局部变量’, name, age)
test01()
print(‘这是函数体外的全局变量’, name, age)
>>> 执行结果如下:
>>> 这是函数体内的局部变量 Jack 17
>>> 这是函数体外的全局变量 Neo 18
>>> 这里我们既声明声明了全局变量,同时还在函数体内变更了变量的值使其成为了局部变量。
>>> 同时,根据打印输出的结果我们可以看出局部变量仅仅作用于函数体内。
全局变量 在 函数体内真的就不能被修改么?当然是可以的,借助关键字 global 就可以实现。
global 关键字
global 关键字的功能:将全局变量可以在函数体内进行修改
global 关键字的用法:示例如下
coding:utf-8
name = ‘Neo’
def test():
global name
name = ‘Jack’
print(‘函数体内 ‘name’ 的值为:’, name)
print(‘函数体外 ‘name’ 的值为:’, name)
>>> 执行结果如下:
>>> 函数体内 ‘name’ 的值为: Jack
>>> 函数体外 ‘name’ 的值为: Jack
注意:日常开发工作中,不建议使用 global
对 全局变量进行修改
再来看一个案例:
test_dict = {‘name’: ‘Neo’, ‘age’: ‘18’}
def test():
test_dict[‘sex’] = ‘man’
test_dict.pop(‘age’)
print(‘函数体内 ‘test_dict’ 的值为:’, test_dict)
test()
print(‘函数体外 ‘test_dict’ 的值为:’, test_dict)
>>> 执行结果如下:
>>> 函数体内 ‘test_dict’ 的值为: {‘name’: ‘Neo’, ‘sex’: ‘man’}
>>> 函数体外 ‘test_dict’ 的值为: {‘name’: ‘Neo’, ‘sex’: ‘man’}
前面我们是通过 global 关键字修改了函数体内的变量的值,为什么在这里没有使用 global 关键字,在函数体内修改了 test_dict 的值却影响到了函数体外的变量值呢?
其实,通过 global 关键字修改的全局变量仅支持数字、字符串、空类型、布尔类型,如果在局部变量想要使用全局变量的字典、列表类型,是不需要通过 global 关键字指引的。
什么是递归函数? —> 通俗的来说,一个函数不停的将自己反复执行,这就是递归函数。(通常是由于函数对自己的执行结果不满意,才需要这样反复的执行。)
递归函数的定义方法
示例如下:
def test(a):
print(a)
return test(a) # 通过返回值,直接执行自身的函数
test(1)
>>> 执行结果如下:
>>> 1
>>> 1… 会一直执行下去,有可能会造成死机,不要尝试。
count = 0
def test():
global count
count += 1
if count != 5:
print('‘count’的条件不满足,需要重新执行。当前’count’的值为%s’ % count)
return test()
else:
print(‘当前’count’的值为%s’ % count)
test()
>>> 执行结果如下:
>>> 'count’的条件不满足,需要重新执行。当前’count’的值为1
>>> 'count’的条件不满足,需要重新执行。当前’count’的值为2
>>> 'count’的条件不满足,需要重新执行。当前’count’的值为3
>>> 'count’的条件不满足,需要重新执行。当前’count’的值为4
>>> 当前’count’的值为5
递归函数的说明
首先我们要知道 递归函数 会造成的影响,递归函数 是不停的重复调用自身函数行程一个无限循环,就会造成内存溢出的情况,我们的电脑可能就要死机了。
递归函数虽然方便了我们用一段短小精悍的代码便描述了一个复杂的算法(处理过程),但一定要谨慎使用。(使用循环来处理,不失为一个稳妥的方案。)
所以我们要尽量的避免使用 递归函数 ,如果真的要使用递归,一定要给予退出递归的方案。
lambda 函数的功能:定义一个轻量化的函数;所谓轻量化就是即用即删除,很适合需要完成一项功能,但是此功能只在此一处使用。也就是说不会重复使用的函数,并且业务简单的场景,我们就可以通过 lambda 来定义函数
感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:
① 2000多本Python电子书(主流和经典的书籍应该都有了)
② Python标准库资料(最全中文版)
③ 项目源码(四五十个有趣且经典的练手项目及源码)
④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)
⑤ Python学习路线图(告别不入流的学习)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!