前言
函数在前面的基础部分频繁出现,更有多次演示,多是数据类型的相关函数或是python内建函数(不需要自己定义的);这章会重点讲自己怎么写函数,即自定义函数。
函数
一个问题,什么是函数?
函数是有组织、有目的,可重复使用的,即提高代码复用率的功能代码块;关键字是def 函数名(如果有参数): Pass
自定义函数
def hello():
print("Hello World!")
hello() # 调用函数,输出内容会打印在控制台:Hello World!
print(hello())
# 会输出print的内容到控制台,同时还有一个None
- 思考一下,为啥print(函数())会有一个None?
参数传递
这里先简单介绍一下参数有哪些名词:形参、实参、默认参数、不定长参数、关键字参数、必须参数,位置参数
- 形参:就是在定义函数时的参数,如:def func(a): pass那么a就是形式参数
- 必须参数:延续上面的例子,如果调用函数func()不传参数就会报错,这时a就是必须参数
- 实参:既然不传参数会报错,那么就给个参数:func(1),这时1就是实际传入func的参数,实参
- 位置参数: 意思是调用函数时指定参数并传值,这样参数就跟定义函数时的位置没有关系了
def func(a,b):
return a+b
print(func(b=2,a=1)) # 输出:3
# 如果不使用位置参数指定入参,那么a和b的值就会不一样。
print(func(2,1)) # 这时函数内部,a=2,b=1
- 默认参数:很好理解,就是定义函数时带参数,并且给参数一个值,那么在调用时可以选择不传参也不会报错
- 不定长参数:又叫动态参数/可变参数;用于不知道函数具体要传多少参数及参数类型,一般有两种使用方式*argsb表示和**kwargs
def func(a,b,c=None,*args,**kwargs):
print("第一个参数a:"+a)
print("第二个参数b:"+b)
print("第三个参数c:"+c)
print("第四个参数args:"+args)
print("第五个参数kwargs:"+kwargs)
pass
func(a=1,c=3,b=2,*("a","v","c"),key="value1",k="value2")
变量
- 什么是变量?
在于变。即在程序运行过程中可能发生变化的量;如:a初始为0,随着程序运行最终a变成了1或非0的值,那么a就是变量;注意:a在使用中才会创建的变量,即给它分配内存空间。
- 既然说到变量,就不得不说一下局部变量跟全局变量
# 局部变量为当前代码块或循环中的变量,它不能被它以外的事务请求
>>> def func():
... a=1
... b=2
... return a+b
...
>>> func()
3
>>> print(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
# 当输入a变量时,则会报错,提示a没有被定义
-
- 全局变量
# 相反,定义在代码块以外的变量称之为全局变量,它可以在当前py模块中任意位置调用,但是不能在它未被申明之前
>>> a = 1
>>> def func(a):
... a = a+1
... return a
...
>>> func(a)
2
>>> print(a) # 函数内的a是变了,但是外面的a没有变
1
- global关键字,定义全局变量
# 如下这种情况,a不是全局变量,因为func()函数用的不是外面的a
>>> a = 1
>>> def func():
... a = 2
... return a
...
>>> func()
2
>>> print(a)
1
-
- 使用关键字global使func函数内的a成为全局变量,那么它在外面调用就应该是func所改变的a
>>> a = 1
>>> def func():
... global a
... a = 2
... return a
...
>>> func()
2
>>> print(a)
2
内置函数
不需要引用也不需要定义就能直接使用的函数,这里特别介绍几个常用的内置函数
- 常用数据类型就是最基础的内置函数:str()、dict()、list()、bool()等等
- eval() # 执行字符串的表达式,并返回它的结果
>>> eval("5*3")
15
- input()和print() # 输入输出
- range() # 一般与for循环搭配使用,创建list或遍历
# 注意一下:这只能是迭代对象,而不是迭代器
res0=range(9) #可迭代对象
print("内置函数range():{}".format(list(res)))
# 支持步长取值
range(n,m,k)
#n为起点,默认为0,m为终点,k为步长即公差
- type() # 获取变量或数据的数据类型
lis1=[1,2,3,4,5,6]
cls_str=type(lis1)
print("查询数据类型:{}".format(cls_str))
- isinstance() # 判断数据类型,返回结果为True或者False
示例1:
# 可以比较数据类型,及类类型type
class TestClsA(unittest.TestCase):
"""
定义一个类,随便选一个类继承;
作用:1.给类属性相关函数使用;
2.其他内置函数对比类型。
"""
pass
class TestClsB(TestClsA):
"""同上,如果该初始化对象,则对象类型与上一个类类型一致"""
pass
#初始化对象
test=TestClsA()
test1=TestClsB()
lis2=[2,3,4,5,6,7]
res4=isinstance(lis2, (list,tuple)) #第二参数可以是类型组成的元组
res5=isinstance(test,unittest.TestCase)# 对象类型是上级的类
res6=isinstance(test1,(unittest.TestCase,TestClsA))# 对象类型是上上级的类型
print("比较数据类型:{},及对象类型:{}".format(res5,res6))
示例2:
# 判断是否是迭代器
# from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections.abc import Iterable,Iterator
# 可以判断对象是否为可迭代对象
a=isinstance([], Iterable)
print("true为可迭代对象{}".format(a))
b=isinstance(iter([]), Iterator)
print("true可迭代对象为迭代器{}".format(b))
- enumerate() # 将可遍历的数据类型组合为一个索引序列
示例1:
>>> list(enumerate(("a","b","c")))
[(0, 'a'), (1, 'b'), (2, 'c')]
示例2:
# 初始化一个list数据类型
lis1=[1,2,4,3,5]
#第一个参数是 一个序列、迭代器或其他支持迭代对象。第二参数指定起始位置,默认为0
res=list(enumerate(lis1))
print("enumerate返回的是枚举对象(计数值,元素值):{}".format(res))
# 应用场景:获取可迭代对象的下标与元素值组成元组元素的list
for k,v in enumerate(lis1):
print("enumerate高级用法,拆包list种的元组元素【{},{}】".format(k,v))
- id() # 获取变量在内存中的地址;
# 返回对象的“标识值”,整数,理解成对象地址
a=1
b=1
c=a
if id(a)==id(c) and id(c)==id(b):
print("比较对象指向的内存地址")
if a==b:
print("比较变量a与b的值")
- open() # 用于文件IO操作
- sum() # 求和
lis13=[1,3,7,9,0,5]
total=sum(lis13)
print("快速求和:{}".format(total))
- len() # 求序列数据类型的长度
lis6=[1,3,4,4,6,7]
length=len(lis6)
print("获取数据类型{}的长度:{}".format(lis6,length))
- min()和max() # 最大或最小值
# 最大
lis5=(2,3,4,4,6,7)
res_max=max(lis5)
print("获取是int类型的可迭代对象:{},的最大值:{}".format(lis5,res_max))
# 最小
res_min=min(lis5)
print("获取是int类型的可迭代对象:{},的最小值:{}".format(lis5,res_min))
- all()和any() # 可迭代参数,判断元素中不能有0或空字符或None元素的数据;但是空列表却是True
>>> a = 1
>>> b = 0
>>> all([a,b])
False
>>> all([a])
True
- filter()
# 返回的是一个迭代器,可以被list、tuple接收
# filter(function, iterable) 相当于一个生成器表达式,
# 当 function 不是 None 的时候为 (item for item in iterable if function(item));
# function 是 None 的时候为 (item for item in iterable if item) 。
# lambda 匿名函数的使用
res1=filter(lambda x:x>3,lis1)
print("filter条件过滤,返回后结果:{}".format(list(res1)))
- round() # 数值求整数
z_n=round(3.11233,3)#int是取整,round取float保留几位小数
print("小数点取整:{}".format(z_n))
- format() # 格式化输出函数不解释
扩展
匿名函数
- lambda,它是一个表达式,比def定义的函数体要简单的多;所以它本身只能是一行代码表示,且逻辑有限,返回的的是:冒号后面的结果
>>> create_list = lambda x:[i for i in range(x)]
>>> create_list(4)
[0, 1, 2, 3]
>>>
>>> sum_x = lambda a,b:a+b
>>> sum_x(3,5)
8
return和yield
- return 每个def定义的函数,都有一个默认的return,后面没有东西,print它是个None
# 对比一下两个函数
>>> def func():
... print(1)
...
>>> func()
1
>>> print(func())
1
None
>>>
>>>
>>> def func():
... print("输出1")
... return "修改了默认输出"
...
>>> print(func())
输出1
修改了默认输出
- yield在python是个特殊用法,函数使用了yield就叫生成器;比较特别,它会在第一个使用它并且记住它,到第二次使用时就进入下一个值,可以说是迭代器
# 引入runoob.com的代码示例:
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
# yield实现斐波那契数列:
# 输出:0 1 1 2 3 5 8 13 21 34 55
exec(object)
object 必须是字符串或者代码对象(表达式)
# 函数支持动态执行 Python 代码
exec("print('动态执行python代码:{}'.format(1+3))")
vars()
返回模块、类、实例或任何其它具有 dict 属性的对象的 dict 属性。
class TestA:
pass
a=TestA()
print(vars(a))
结果输出如下:
{
'_testMethodName': 'runTest', '_outcome': None, '_testMethodDoc': 'No test', '_cleanups': [], '_subtest': None, '_type_equality_funcs': {
<class 'dict'>: 'assertDictEqual', <class 'list'>: 'assertListEqual', <class 'tuple'>: 'assertTupleEqual', <class 'set'>: 'assertSetEqual', <class 'frozenset'>: 'assertSetEqual', <class 'str'>: 'assertMultiLineEqual'}}
iter()迭代器
获取可迭代对象的迭代器,iter()函数实际上就是调用了可迭代对象的__iter__方法。
lis3=[1,3,4,4,6,7]
res6=iter(lis3) # 返回的是一个迭代器
print("用list接收:{}".format(list(res6))) #用list接收
lis4=[1,3,4,4,6,7]
res6=iter(lis4)
print("用tuple接收:{}".format(tuple(res6))) #用tuple接收
使用next()函数来获取iter()迭代器的下一条数据
lis5=[1,3,4,4,6,7]
res6=iter(lis5)
while 1:
try:
v=next(res6)
except StopIteration as e:
print("遇到StopIteration迭代取值完成")
break
else:
print("next获取迭代器的数据:{}".format(v))
map()
返回的是一个迭代器,可以用list/tuple来接收,
lis7=[1,3,4,4,6,7]
res7=map(lambda x:x+1,lis7)
print("{}数据类型,map函数返回一个迭代器:{}".format(lis7,res7))
# 遍历map返回的迭代器的新的元素值
for i in res7:
print("遍历出迭代器{}的值:{}".format(res7,i))
zip()
返回是迭代器,可以用list/tuple来接收,同样next()取值
lis8=[2,3,7,9,0,1]
lis9=[1,3,4,4,6]
res9=zip(lis8,lis9) # 打包为元组的列表,
# 元素个数与最短的列表一致,即会抛开元素个数多的那几个
print("内置打包函数zip:{},list接收:{}".format(res9,list(res9)))
reversed()
lis10=[1,3,7,9,0,5]
revers_li=reversed(lis10)
print("反转:{}".format(list(revers_li)))
sorted()列表排序
lis11=[1,3,7,9,0,5]
bubble=sorted(lis11,reverse=True)#reverse=True降序,默认倒序
print("排序:{}".format(bubble))