?? 函数是组织好的, 可重复使用的, 用来实现单一, 或相关功能的代码块.
?? 函数分为 Python 程序内置函数, 用户自定义的函数. 将代码定义为函数, 有如下好处:
代码重用(某个特定功能复用)
保持代码一致性, 易维护
可拓展
1.1 定义和调用函数
?? 使用 def 关键字定义一个函数, 后面紧跟函数名, 小括号也必不可少, 语法如下:
def func():
函数体
?? 函数在执行时, 首先将函数体加载到解释器中, 但是不会运行, 只有当调用函数后才会执行, 函数名 + 小括号即可调用函数:
def func():
函数体
func() # 调用函数
1.2 返回值
?? 有时我们需要函数返回一些数据来报告执行的结果, 所有就需要有返回值, 只需要在函数中添加 return 关键字, 后面跟着返回值即可.
- def func():
- return 1
??return 将返回值传递给函数本身, 我们只要调用函数, 再将函数赋值给变量即可获得返回值:
- def func():
- return 1
- res = func() # 获得返回值, 并赋值给变量 res
- print(res)
- 1
?? 返回值可以是 0 个, 也可以是 1 个 或多个:
没有返回值, 返回 None
一个返回值, 返回 返回值
多个返回值, 返回一个元组
- def func():
- # return
- # return 1
- return 1, 2
- res = func()
- print(res)
- None
- 1
- (1, 2)
1.3 函数参数
?? 函数的参数可以用函数实现个性化, 大致分为两类:
形参: 函数在定义时定义的参数
实参: 函数在调用时传入的参数
?? 形参只有在调用时才分配内存单元, 调用结束, 就释放. 仅在函数内部有效, 不能在函数外部使用.
?? 实参可以是常量, 变量, 表达式, 函数, 占用内存空间.
1.3.1 默认参数
?? 形参又分为: 默认参数, 位置参数, 关键字参数以及可变长参数, 而默认参数即在函数定义时默认赋予某个形参一个值. 若函数调用时, 不传入实参, 函数使用默认值, 否则使用实参.
- def func(x=2): # x 默认为 2
- return x + 2
- res = func() # 即使不传入实参函数也能正常运行
- print(res)
1.3.2 位置参数和关键字参数
?? 普通的参数即为位置参数, 在调用时实参必须与形参一一对应. 而关键字参数, 可以不用考虑位置的关系, 只需要名字相同即可.
- def func(name, words):
- print(name: words)
- func('Hello', words='world') # 第一个为位置参数, 第二个为关键字参数
- func(words='World', name='Hello') # 不用考虑位置
Tips: 位置参数必须在关键字参数后面
1.3.3 可变长参数
?? 可变长参数是一种参数组, 它可以是多个参数, 只需要在参数前加上星号 (*) 即可. 它可以增加函数可拓展性, 当你不知道定义的函数需要定义几个参数时, 使用它很方便.
?? 可变长参数分为:*args 和 **kwargs 两类:
*agrs: 将参数们收集起来, 打包成一个元组, 再一一传递给函数使用
**kwargs: 将参数们收集并打包成一个字典
*args
??*args ,**kwargs 是 Python 官方定义的参数名, 也可以是其他名字, 但是最好使用它, 以便于辨认.
- def func(*args):
- print(args)
- print('有 %d 个参数' % len(args))
- print('第三个参数是:', args[2])
- func('P', 'y', 't', 'h', 'o', 'n')
- func('Python', 123, '爬虫')
- ('P', 'y', 't', 'h', 'o', 'n')
有 6 个参数
第三个参数是: t
('Python', 123, '爬虫')
有 3 个参数
第三个参数是: 爬虫
Tips: 如果可变长参数后面还有参数, 要将其定义为关键字参数, 否则会被收集成可变长参数里面. 建议在使用可变长参数时, 可将其他参数设置为默认参数, 或关键字参数, 这样不易混淆.
- def func(*args, extra=16):
- # def func(*args, extra):
- print(args)
- print(extra)
- func(1,2,3)
- #func(5,6, extra=18)
- (1, 2, 3)
- 16
- (5, 6)
- 18
?? 星号 () 既可用来收集打包参数, 也可以用来 "解包" 参数. 当传入的参数时列表, 元组, 字典以及集合时, 可变长参数将会将其整个打包成只有一个元组的参数, 而在其前面添加一个星号(), 就可以将里面的元素一个个都解出来.
- def func(*args):
- print(args)
- l = [1, 2, 3]
- t = (4, 5, 6)
- d = {'name':'rose', 'age': 18}
- func(l)
- func(*l)
- func(t)
- func(*t)
- func(d)
- func(*d)
- ([1, 2, 3],)
- (1, 2, 3)
- ((4, 5, 6),)
- (4, 5, 6)
- ({'name': 'rose', 'age': 18},)
- ('name', 'age')
- **kwargs
?? 另一种可变长参数就是 **kwargs, 它将传入的实参打包成一个字典, 同样地也支持 "解包".
- def func(x, **kwargs):
- print(x)
- print(kwargs)
- print('总共有 %d 个参数' % len(kwargs))
- print('这些参数分别为:', kwargs)
- func(20, name='rose', age=18)
- 20
- {'name': 'rose', 'age': 18}
总共有 2 个参数
这些参数分别为: {'name': 'rose', 'age': 18}
?? 解包, 当传入的参数是字典时:
- def func(gender, **kwargs):
- print(gender)
- print(kwargs)
- print('总共有 %d 个参数' % len(kwargs))
- print('这些参数分别为:', kwargs)
- t = {'name': 'rose', 'age': 18}
- func('female', **t)
- female
- {'name': 'rose', 'age': 18}
总共有 2 个参数
这些参数分别为: {'name': 'rose', 'age': 18}
?? 当既有 *args, 又有 **kwargs, 以及位置参数和位置参数时:
- def func(gender, country='China', *args, **kwargs):
- print(gender, country)
- print(args)
- print(kwargs)
- func('male', 'America', 20, 30, name='rose', age=19)
- male America
- (20, 30)
- {'name': 'rose', 'age': 19}
1.4 函数文档
?? 函数文档即用来描述函数功能的文档, 可以让别人更好地理解你的函数, 定义函数文档是个好的习惯.
- def func(x):
- """
- 计算一个数加一
- :param x:
- :return:
- """
- x += 1
- return x
- res = func()
1.5 函数变量
1.5.1 函数和过程
?? 在 Python 中函数和过程是分开的, 函数 (function) 与过程 (procedure) 的区别:
函数: 有返回值
过程: 简单, 特殊且无返回值
?? 严格来说 Python 没有过程, 只有函数, 因为即使没有返回值, 也会默认返回一个 None.
- def func():
- print('Hi')
- res = func()
- print(res)
- Hi
- None
1.5.2 函数变量的作用域
?? 变量的作用域即变量可见性, 也就是可用范围, 一般编程语言分为: 全局变量 (global variable) 和局部变量(local variable).
全局变量: 程序开始定义时定义的变量, 在函数外部, 无缩进, 作用域为整个程序
局部变量: 在子程序中 (一般为函数) 定义的变量, 函数内部, 有缩进, 作用域是整个子程序
当全局变量与局部变量同名是, 在子程序中局部变量起作用, 在外面全局变量起作用.
- # 首先加载整个函数(不执行), 调用函数执行函数内部, 打印 tom, 最后打印 rose
- name = 'rose' # 全局
- def test():
- name = 'tom' # 局部
- print(name)
- test()
- print(name)
- tom
- rose
??1. global 关键字
?? 全局变量的作用域是整个程序, 函数内部亦可访问. 但是不要在函数内部试图修改全局变量, 这是因为 Python 使用了屏蔽 (shadowing) 的方式去 保护全局变量. 一旦在函数内部修改, 则会在函数内部创建一个一模一样的局部变量.
- name = 'rose'
- def test():
- name = 'tom'
- print(name)
- test()
- print(name)
- tom
- rose
?? 从上面例子可以看出, 全局变量的值没有改变. 但是 Python 是支持在函数内部修改全局变量的, 只需要在变量前面加上一个 global 关键字即可:
- name = 'rose'
- def test():
- global name
- name = 'tom'
- print(name)
- test()
- print(name)
- tom
- tom
总结: 当全局与局部变量名字相同时, 函数内部优先读取局部变量. 为了更好地区分全局与局部变量, 一般地全局变量名尽量使用大小, 局部变量名使用小写.
??2. 内嵌函数
?? 函数支持嵌套, 即一个函数中嵌套另外一个函数, 这种函数叫内嵌函数或内部函数.
- name = 'rose' # (1)
- def fun1(): # (2)
- name = 'tom' # (5)
- def fun2(): # (6)
- name = 'lila' # (8)
- fun2() # (7)
- print(name) # (9)
- print(name) # (3)
- fun1() # (4)
- print(name) # (10)
- rose
- tom
- rose
Tips: 内部函数只能在内部调用, 外部调用会报 NameError
1.5.3 闭包
?? 闭包 (closure) 是函数式编程中的一个重要数据结构, Python 中认为如果在一个内部函数里, 对在外部作用域 (但不是全局作用域) 的变量进行引用, 那么这个内部函数就是闭包(closure).
- def fun1(x):
- def fun2(y):
- return x * y
- return fun2
- a = fun1(6) # a 接收的是 fun2() 的内存地址
- print(a)
- b = a(5) # a(5) 相当于调用 fun2()
- print(b)
- # 上述可以简写
- # res = fun1(6)(5)
- # print(res)
- <function fun1.<locals>.fun2 at 0x00000000026F48C8>
- 30
?? 从上面的例子可以看出, 内部函数 fun2()对外部函数 fun1()的变量 x (不是全局变量)进行了引用, 那么 fun2()即是闭包.
??nonlocal 关键字
?? 但需要注意的是不能在外部函数外面调用内部函数, 对外部函数的局部变量只能进行访问, 不能修改.
- def fun1():
- name = 'rose'
- def fun2():
- name = 'tom'
- return name
- print(name)
- return fun2
- fun1()()
- rose # 外部函数局部变量 name = 'rose' 并没有被修改
?? 如果在内部函数中想修改外部函数的局部变量可以用 nonlocal 关键字, 但是需要注意的是它不能修改全局变量.
- def fun1():
- name = 'rose'
- def fun2():
- nonlocal name # 添加 nonlocal 关键字
- name = 'tom'
- return name
- print(name)
- return fun2
- fun1()()
- tom # 外部函数局部变量 name = 'rose' 已经被修改
1.6 函数即变量
??Python 程序按程序执行, 遇到函数, 先加载到到内存, 只有当调用函数时, 才会运行函数体. 因此一个函数可以作为 变量在另一个函数内部调用执行, 前提是第一个函数需要先加载.
?? 首先加载 f1(),f2(), 再调用 f1(), 执行 f1()里的函数体, 最后调用 f2(), 执行 f2()里的函数体:
- def f1(): # (1)
- print('from f1') # (4)
- f2() # (5)
- def f2(): # (2)
- print('from f2') # (6)
- f1() # (3)
- from f1
- from f2
?? 另一种情况:
- def f2():
- print('from f2')
- def f1():
- print('from f1')
- f2()
- f1()
- from f1
- from f2
?? 第三种情况, 调用 f2()时, 因为 函数 f2()还未加载, 导致出错(NameError: name 'f2' is not defined):
- def f1():
- print('from f1')
- f2()
- def f2():
- print('from f2')
- f1()
1.7 递归函数
?? 在函数内部, 可以调用其他函数, 如果在调用过程中直接或间接调用自身, 那么这个函数就是递归函数.
?? 递归函数特征:
必须有明确的结束条件(否则死循环)
每次进入更深一次递归时, 问题规模比上一次都应有所减少
递归效率不高, 层次过多容易导致 栈溢出
函数调用是通过栈 (stack) 实现, 每调用一次, 栈就会增加一层栈帧, 函数返回, 则减少一层. 由于栈的大小有限, 所有递归过多, 就会导致栈溢出.
- def func(n):
- print(n)
- if int(n/2) == 0: # 结束条件
- return n
- res = func(int/2) # 调用自身
- return res
- func(10)
- 10,5,2,1
1.7.1 示例
?? 递归问路
?? 使用递归函数, 实现一次递归问路操作.
- import time
- person_list = ['rose', 'tom', 'lila', 'json', 'john']
- def ask_way(person_list):
- """
- 问路操作
- :param person_list: 被问的人
- :return:
- """ print('-'*60)
- if len(person_list) == 0:
- return '没人知道'
- person = person_list.pop()
- if person == 'json':
- return '%s 我知道 xxx 怎么走, 它在 xxx' % person
- print('你好,%s, 请问 xxx 在哪里?' % person)
- print('%s 回答道: 我也不知道, 我帮你去问问 %s' % (person, person_list))
- time.sleep(2)
- res = ask_way(person_list)
- return res
- res = ask_way(person_list)
- print(res)
- ------------------------------------------------------------
你好, john, 请问 xxx 在哪里?
john 回答道: 我也不知道, 我帮你去问问 ['rose', 'tom', 'lila', 'json']
------------------------------------------------------------
JSON 我知道 xxx 怎么走, 它在 xxx
?? 二分查找
- data = [1,3,6,7,9,12,14,16,17,18,20,21,22,23,30,32,33,35]
- def find_num(data, num):
- """
- 使用二分查找法, 查找出一个数字的位置
- """
- print(data)
- if len(data)> 1:
- mid = int(len(data)/2)
- if data[mid] == num:
- print('找到数字', data[mid])
- elif data[mid]> num:
- print('要找的数字在 %s 右边' % data[mid])
- return find_num(data[0:mid], num)
- else:
- print('要找的数字在 %s 左边' % data[mid])
- return find_num(data[mid+1:], num)
- else:
- if data[0] == num:
- print('找到数字', data[0])
- else:
- print('要找的数字不在列表中')
- find_num(data, 66)
- [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
要找的数字在 18 左边
[20, 21, 22, 23, 30, 32, 33, 35]
要找的数字在 30 左边
[32, 33, 35]
要找的数字在 33 左边
[35]
要找的数字不在列表中
1.7.2 尾调用
?? 尾调用又称为为递归, 指的是函数在最后一步调用另一个函数的过程(最后一行不一定是最后一步).
- # bar 在 foo 内为尾调用
- def bar(n):
- return n
- def foo(m):
- return bar(m)
- # bar 在 foo 内不是尾调用, 最后一步为 return y
- def bar(n):
- return n
- def foo(m):
- y = bar(m)
- return y
- # bar1,bar2 在 foo 内都是尾调用
- def bar1(n):
- return n
- def bar2(n):
- return n+1
- def foo(x):
- if type(x) is str:
- return bar1(x)
- elif type(x) is int:
- return bar2(x)
?? 尾调用优化
?? 定义 a 函数, a 内调用 b,b 调用 c, 在内存中形成一个调用记录, 又称为调用帧(call frame). 用于存储调用位置和内部变量等信息, 即(a--b--c), 直至 c 返回结果给 b,c 的调用记录消失. b 返回给 a,b 的调用记录消失, a 返回结果, a 的调用记录消失, 所有记录都是先进后出, 形成一个调用栈(call stack)
1.8 匿名函数
?? 匿名函数即不需要显示地指定函数名的函数, Python 允许使用 lambda 关键字来创建一个匿名函数, 匿名函数也被称为 lambda 表达式.
- lambda x:x+2
- lambda x,y,z:(x+1, y+1, z+1) # 多个参数
?? 冒号左边是原函数参数, 可以有多个参数, 逗号分隔即可, 冒号右边为返回值. 对于有些结构比较简单的函数, 可以直接定义为匿名函数:
- def func(x):
- return x+2
- s = func(3)
- print(s)
?? 上述函数可直接定义一个匿名函数:
- f = lambda x:x+2
- f(3) # 调用
?? 匿名函数常与其他函数搭配使用:
- # 将 匿名函数当做参数传入 calc 中
- def calc(func, li):
- ret = []
- for i in li:
- res = func(i)
- ret.append(res)
- return ret
- li = [2, 3, 4, 6, 8]
- calc(lambda x:x+1, li)
- [3, 4, 5, 7, 9]
??lambda 表达式的作用:
执行一些脚本时, 省略定义函数过程
对于整个程序只需要执行一两次的函数, 不用考虑命名问题
简化代码步骤
2. 函数式编程
2.1 编程论
?? 当今编程的三种方法论:
面向过程:
函数式编程: 特征(无变量, 函数即变量)
面向对象:
?? 函数式编程(函数 + 数学函数), 更贴近数学, 是一种抽象成都很高的编程范式, 不允许函数有变量. 但 Python 不是严格意义上的函数式编程, 因为它允许有变量.
?? 函数式编程特点:
函数即变量(一个函数作为参数传入另一个函数)
返回值是函数(可以函数本身, 也可以是别的函数)
?? 函数即变量
- def foo(n):
- print(n)
- def bar(name):
- print(name)
- foo(bar('rose'))
- rose
- None
?? 上面例子中, bar('rose') 打印 rose, 没有返回值, 因此 foo(bar('rose'))相当于 foo(None).
?? 返回值是函数
?? 返回函数本身:
- def handle():
- print('from handle')
- return handle # 返回函数本身内存地址
- h = handle() # 使用变量 h 接收
- h() # 再调用函数本身
- from handle
- from handle
?? 返回别的函数:
- def test():
- print('from test')
- def test1():
- print('from test1')
- return test # 返回 test 函数的内存地址
- n = test1() # 接收
- n() # 相当于调用 test()
2.2 高阶函数
?? 函数式编程的两个特征: 函数即变量, 返回值是函数, 只需满足其中一个条件, 即可成为高阶函数.
- def add(x, y, f):
- return f(x)+f(y)
- print(add(-5, 6, abs))
- 11
?? 上面例子中, 内置函数 abs 作为参数传入函数 add.
2.2.1 map 函数
??map(function, sequence) 函数是高阶函数的一种, 它有两个参数: 第一个为函数, 另一个接收一个序列.
?? 其作用是将序列中每个元素(for 循环), 作为函数参数传入第一个参数中, 直至序列中每个元素都被循环, 返回一个迭代器对象, 用 list 可获得结果.
- # 对列表 l 中每个元素加 1
- li = [2, 3, 4, 5, 6]
- def add_one(x):
- return x+1
- res = map(add_one, li)
- print(res)
- print(list(res))
- <map object at 0x0000000002C5C0B8>
- [3, 4, 5, 6, 7]
?? 上面例子中 map 函数将列表 li 的每个中每个元素取出, 再传入 add_one 中.
?? 同样地也可以使用 lambda 表达式与 map 函数简写:
res = map(lambda x:x+1, li)
?? 传入两个列表:
- res = map(lambda x, y: x+y, [1, 3, 5], [2, 4, 6])
- print(list(res))
2.2.2 filter 函数
??filter(function or None, iterable)函数有两个参数: 第一个可以是函数也可以是 None, 第二个为可迭代对象.
第一个参数为函数: 将序列中每个元素取出作为参数, 传入第一个参数中, 判断, 并把为 True 的值返回
第一个参数为 None: 将序列中为 True 的元素返回
?? 第一个参数为函数:
- # 过滤掉以 123 结尾的名字
- names = ['rose_123', 'lila_123', 'john']
- def filter_123(x):
- return not x.endswith('123') # 返回没有以 123 结尾的名字
- res = filter(filter_123, names)
- list(res)
- john
?? 使用 lambda 表达式简写:
- res = filter(lambda x: not x.endswith('123'), names)
- list(res)
?? 第一个参数为 None:
- res = filter(None, [1, 2, 0, True, False])
- list(res)
- [1, 2, True]
2.2.3 reduce 函数
??reduce(function, sequence[, initial])函数三个参数: 第一个为函数, 第二个为序列, 第三个可选为初始值.
??Python3 把 reduce 函数集成到 functools 模块中, 因此每次使用时, 需要 from functools import reduce. 它可以把一个函数作用在一个序列上, 这个函数必须接收两个参数. 首先将序列中的前两个元素取出, 传入函数中, 返回值再与序列中接下来的元素做累积计算, 直至序列中的每个元素都被循环.
?? 求列表中所有元素的乘积:
?? 常规:
- nums = [1, 2, 3, 100]
- def reduce_test(func, array):
- res = array.pop(0)
- for i in array:
- res = func(res, i)
- return res
- s = reduce_test(lambda x,y: x*y, nums)
- print(s)
- 600
- ??reduce:
- from functools import reduce
- nums = [1, 2, 3, 100]
- res = reduce(lambda x,y : x*y, nums)
- print(res)
- 600
?? 首先将 nums 前两个元素, 即 1,2 传入 lambda x,y: x*y 中, 返回 x*y. 再将 3 传入, 最后将 100 传入, 相当于(((1*2)*3)*100).
指定初始值:
- from functools import reduce
- nums = [1, 2, 3, 100]
- res = reduce(lambda x,y : x*y, nums, 6) # 相当于 (((6*1)*2)*3)*100
- print(res)
- 3600
?? 累加计算:
- from functools import reduce
- reduce(lambda x,y: x+y, [1, 2, 3, 4, 5])
- 15
2.2.4 sorted 函数
?? 排序算法在程序中是经常用到的算法, 无论是冒泡还是快排, 其核心都是比较两个元素的大小.
数字: 直接比较
字符串 / 字典: 需要用函数抽象出来比较
??sorted(iterable, key, reverse)函数也是一个高阶函数, 在列表内置方法中我们就已经接触到了, 它可以对一个列表进行排序, 默认从小到大.
- sorted([1, -3, 2])
- [-3, 1, 2]
?? 此外, 它还接收一个 key 函数来自定义排序, key 函数作用在列表中的每个元素上, 再进行比较, 如按绝对值排序:
- sorted([1, -3, 2], key=abs)
- [1, 2, -3]
?? 第三个参数 reverse, 可以反向排序:
- sorted([1, -3, 2], key=abs, reverse=True)
- [-3, 2, 1]
?? 上面都是针对数字的排序, 直接比较其大小即可. 但是对于字符串来说, 一般地都是比较其首字母在 ASCII 中的大小:
- sorted(['b', 'a', 'Z']) # 因为在 ASCII 中 Z<a
- ['Z', 'a', 'b']
?? 现在我们不想按照 ASCII 来排序, 而是按照字母表排序, 那么我们可以通过指定 key 函数, 将所有字符串转换为大写或小写即可实现:
- sorted(['b', 'a', 'Z'], key=str.upper)
- ['a', 'b', 'Z']
2.2.5 偏函数
??functools 模块提供了很多功能, 其中一个就是偏函数(partial ).
?? 当函数的参数个数太多, 需要简化时, 使用 functools.partial 创建一个偏函数, 这个新的函数可以固定住原函数的部分参数, 从而调用更简单.
语法结构:
- from functools import partial
- func2 = partial(func, *args, **kwargs) # 第一个参数: 要固定的函数, 第二个: 原函数的位置参数, 第三个: 关键字参数
?? 第一个参数可以是自定义的函数, 也可以是内置函数.
??int() 函数可以把字符串转换为整型, 默认按照十进制转换:
- >>> int('123')
- 123
??int() 函数还额外提供一个 base 参数, 如果传入 base, 就可以做 N 进制转换:
- >>> int('123', base=8) # 按照八进制转换
- 83
内置函数
?? 假如要转换大量的二进制字符串, 每次都要传入 base, 就会很繁琐. 我们可以利用偏函数 (partial) 将 base=2 固定住, 定义一个新的函数, 每次只需要传入要转换的字符串即可:
- >>> from functools import partial
- >>> int2 = partial(int, base=2) # 将 base = 2 固定住
- >>> int2('100') # 相当于 kw={
- 'base': 2
- } int('100', **kw)
- 4
自定义函数
?? 当我们调用某个函数, 已知某个参数的值时, 可以将其固定住(相当于设定默认值):
- from functools import partial
- def add(x, y):
- return x % y
- add2 = partial(add, 5) # 自动将 5 作为 *args 的一部分放在最左边, 也就是 5 % 100
- print(add2(100))
- # 101
2.2.6 练习
?? 将列表中年龄小于等于 18 岁的人过滤出来.
- people = [
- {'name': 'rose', 'age': 18},
- {'name': 'lila', 'age': 30},
- {'name': 'tom', 'age': 60}
- ]
- res = filter(lambda p: p.get('age') <= 18, people)
- print(list(res))
- [{'name': 'rose', 'age': 18}]
3. 内置函数
?? 函数分为 Python 内置函数和自定义函数, 内置函数有很多, 但是真正能用到的也比较少.
- # abs(): 求一个数字的绝对值
- >>> abs(-5)
- 5
- # all(iterable): 判断序列中所有元素是否为 True, 如果序列为空, 也返回 True, 返回布尔值
- >>> all([1, 2, 0])
- False
- # any(iterable): 序列中元素 bool(x), 只要有一个为 True, 则返回 True, 如果序列为空, 返回 False
- >>> any([])
- False
- >>> any(['', 0, 1])
- True
- # bin(number): 十进制转二进制
- >>> bin(10)
- '0b1010'
- # hex(number): 十进制转十六进制
- >>> hex(10)
- '0xa'
- # bool(): 转换为布尔类型
- >>> bool(0)
- False
- >>> bool(None)
- False
- >>> bool('')
- False
- # bytes(obj,encoding=None): 将对象编码(二进制)
- # bytes(obj,encoding=None).decode(None): 解码, 用什么编码就应用什么解码
- >>> name = '你好'
- >>> bytes(name, encoding='utf-8')
- b'\xe4\xbd\xa0\xe5\xa5\xbd'
- >>> bytes(name, encoding='utf-8').decode('utf-8')
- '你好'
- # chr(i): 返回一个数字在 ASCII 中对应的值
- >>> chr(90)
- 'Z'
- # ord(obj): 查询一个字符咋 ASCII 中的对应的数字
- >>> ord('Z')
- 90
- # dict(): 创建一个字典
- >>> d = dict()
- >>> type(d)
- <class 'dict'>
- # dir(obj): 返回一个对象的所有方法名字
- >>> dir(str)
- # help(obj): 查看帮助文档
- >>> help(list.append)
- Help on method_descriptor:
- append(...)
- L.append(object) -> None -- append object to end
- # dirmod(x,y): 返回一个元组, 结果为 x / 有的商和余数, 一般用作网页分页
- >>> divmod(10, 3)
- (3, 1)
- # id(obj): 查看一个对象的内存地址
- >>> id(10)
- 1750035808
- # globals(): 查看全局变量
- # locals(): 查看局部变量
- # pow(x,y[,z]): 幂运算, z 可选, pow(x,y,z)相当于 (x**y)%z
- >>> pow(10, 3)
- 1000
- >>> pow(10, 3, 4)
- 0
- # reversed(iterable): 反转一个序列
- >>> list(reversed('abc'))
- ['c', 'b', 'a']
- >>> list(reversed([1, 2, 3]))
- [3, 2, 1]
- # round(number,ndigits): 四舍五入, 保留几位有效小数
- >>> round(4.5)
- 4
- >>> round(4.564, 2)
- 4.56
- # set(iterable): 转换成集合, 创建一个集合
- >>> set('123')
- {'2', '3', '1'}
- >>> s = set()
- >>> type(s)
- <class 'set'>
- # slice(statr,stop[,step]): 序列切片 / 分片
- >>> l = 'hello'
- >>> s = slice(2, 3)
- >>> l[s]
- 'l'
- # str(): 转换为字符串
- >>> str(123)
- '123'
- # sum(iterable, start=0): 求序列中所有元素的和, 还可指定
- >>> l = [1, 2, 3, 4]
- >>> sum(l)
- 10
- >>> sum(l, 1)
- 11
- # tuple(): 转换为元组
- >>> tuple(['a', 1])
- ('a', 1)
- # vars(obj): 返回对象的属性和属性值的字典对象.
- >>> vars()
- {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'name': '你好', 'd': "{'name:':'
- rose'}", 's': slice(2, 3, None), 'p': {'name': 'rose', 'age': 18, 'gender': 'male'}, 't': <zip object at 0x0000000002D9FF08>, 'i': ('c', 3), 'age': {'rose': 18, 'tom': 19}, 'li': 'hello', 'l': [1, 2, 3, 4]}
- >>> vars(str)
- ....
- # __import__(): 当模块名是字符串是, 可以使用.
- >>> module_name = 'test'
- >>> __import__(module_name)
- <module 'test' from 'C:\\Users\\HJ\\Anaconda3\\lib\\test\\__init__.py'>
- >>> import module_name
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- ModuleNotFoundError: No module named 'module_name'
- ??1. eval()
??eval(expression,[globals[,locals]), 用于执行一个字符串表达式, 并返回表达式值, 可以去掉字符串的引号.
- >>> d = "{'name:':'rose'}"
- >>> type(d)
- <class 'str'>
- >>> s = eval(d)
- >>> type(s)
- <class 'dict'>
?? 字符串中表达式的值, 也可以计算:
- >>> express = '1*2+3'
- >>> eval(express)
- 5
- ??2. hash()
??hash(obj)做哈希运算, 不管对象有多长, 经过哈希运算后的值长度都相同, 也不能根据 hash 值反推出原始对象.
?? 可用于校对软件 / 文件是否被别人篡改, 还可用于判断软件或文件是否下载完整(检验官方给出的 hash 值与自己下载完毕 hash 的值是否相同)
可哈希数据类型: 即不可变数据类型, 如: 字符串, 元组
不可哈希数据类型: 即可变数据类型, 如: 列表, 字典, 集合
- >>> hash('abc')
- 5994226220732616244
- >>> hash('123')
- -3466646395452377901
- ??3. isinstance(),type()
?? 两个都是用于判断数据类型, 官方建议使用 isinstance.
- >>> type(123)
- <class 'int'>
- nums = '123'
- if type(nums) is str:
- res = int(nums) + 1
??isinstance(x,A_tuple)有两个参数: 第一个是待确定类型的数据, 第二个是指定一个数据类型, 判断两者是否一致, 返回一个布尔值.
- >>> isinstance(123, int)
- True
- ??4. zip()
??zip(ite1[,iter2[...]])函数接收两个序列, 要求它们元素数据相等, 返回两个序列元素一一对应的元组(返回的是 zip 对象的内存地址).
- >>> p = {
- 'name': 'rose', 'age': 18, 'gender': 'male'
- }
- >>> t = zip(p.keys(), p.values())
- >>> list(t)
- [('name', 'rose'), ('age', 18), ('gender', 'male')]
- >>> list(zip(['a', 'b', 'c'], [1, 2, 3]))
- [('a', 1), ('b', 2), ('c', 3)]
- >>> for i in zip(['a', 'b', 'c'], [1, 2, 3]):
- ... print(i)
- ...
- ('a', 1)
- ('b', 2)
- ('c', 3)
- ??5. max(),min()
??max(iterable, key, default),min()返回一个序列中的最大, 小元素.
?? 特性:
原理是将序列中每个元素都循环遍历出来比较
首先比较第一个字符, 分出大小则停止比较, 若分出, 钻继续比较. 不同数据类型不能比较
字典比较, 默认比较 key
- >>> max([1, 2, 3])
- 3
- >>> max(['a', 'b'])
- 'b'
- >>> max(['a12', 'a2']) # a 相同, 2>1
- 'a2' # b>a
- >>> max(['a12', 'b10'])
- 'b10'
- >>> age = {
- 'rose': 18, 'tom': 19
- } # 字典比较默认比较 key
- >>> max(age)
- 'tom'
- >>> max(zip(age.values(), age.keys())) # 既比较大小, 又把名字也打印出来
- (19, 'tom')
??max()还可以指定比较方法:
- # 取出 age 比较
- >>> people = [
- {'name': 'rose', 'age': 18},
- {'name': 'lila', 'age': 30},
- {'name': 'tom', 'age': 60}
- ]
- >>> max(people, key=lambda dic:dic.get('age'))
- {'name': 'tom', 'age': 60}
Python 开发[第五篇] : 函数
来源: http://www.bubuko.com/infodetail-2920615.html