第1章 递归函数
函数递归调用:在调用一个函数的过程中直接或间接地调用该函数本身,称之为函数的递归调用
### 在函数中调用自己本身 递归函数 超出了函数递归的最大限制
### 直接
def func():
print('from func')
func()
func() # RecursionError: maximum recursion depth
exceeded while calling a Python object
# Python中递归的效率低
# 在Python中没有伪递归优化
### 间接
def foo ():
print('from foo')
bar()
def bar():
print('from bar')
foo()
foo()
1.1 递归的过程
# age(5)=age(4)+2
# age(4)=age(3)+2
# age(3)=age(2)+2
# age(2)=age(1)+2
# age(1)=18
#
# age(n)=age(n-1)+2
# age(1)=18 #n=1
def age(n):
if n
== 1:
return
18
return
age(n-1)+2
>>> 26
递归执行分为两个阶段:递推和回溯
1.2 python中的递归
python中的递归效率低,需要在进入下一次递归时保留当前的状态,在其他语言中可以有解决方法:尾递归优化,即在函数的最后一步(而非最后一行)调用自己,尾递归优化:http://egon09.blog.51cto.com/9161406/1842475
但是python又没有尾递归,且对递归层级做了限制
### 总结递归的使用:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
1.3 递归的层级
import sys
print(sys.getrecursionlimit())
>>> 1000
sys.setrecursionlimit(1500) # 修改递归的层级,没必要 这样会造成占用更多的层级
1.4 使用场景
# 取出列表中所有的元素
l=[1,2,[3,[4,[5,[6,7,[8,9,[10,[11,[12,]]]]]]]]]
def search(l):
for item
in l:
if type(item) is list: # 如果循环出来的元素是列表的话
search(item) # 继续向下
else:
print(item) # 打印出来
search(l)
1.5 总结递归调用
#总结递归调用:
#1:进入下一次递归时,问题的规模必须降低
#2:递归调用必须要有一个明确的结束条件
#3:在python中没有尾递归优化,递归调用的效率就是不高
第2章 二分法
l=[1,2,10,30,33,99,101,200,301,402]
# 从小到大排列的数字列表 例如要找到10 循环比3次即可 那要是1W个元素呢
# 如果全部遍历一次 列表又非常大 效率极低
# 如何高效解决,使用二分法
# 将列表从中间切分 然后对比两边的数据 得到条件后继续切分 直到得出结果 问题规模每次都缩小一半
# 例如要找到200
# 不知道切多少次能够切完 使用递归 找到结果终止
def binary_search(l,num):
print(l)
mid_index=len(l)//2 # 地板除得整数,得到中间的索引
print(mid_index,l[mid_index])
if
num > l[mid_index]: # 如果值比中间索引的值大 那么该值在列表的右边
#
in the right
l=l[mid_index+1:] # 切一刀 中间的值到最后,中间的值已经做过一次比较
所以 + 1 到最后
binary_search(l,num)
elif
num < l[mid_index]:
# in the left
l=l[:mid_index] # 顾头不顾尾,取不到mid_index
binary_search(l,num)
else:
print('find it')
binary_search(l,200)
[1, 2, 10, 30, 33, 99, 101, 200, 301, 402]
5 99
[101, 200, 301, 402]
2 301
[101, 200]
1 200
find it
# 如果要找到的值不在列表中呢?
# [1, 2, 10, 30, 33, 99, 101, 200, 301, 402]
# 5 99
# [30, 33]
# [1, 2, 10, 30, 33]
# 1 33
# []
def binary_search(l,num):
print(l)
if len(l) > 0: # 列表不为空,则证明还有值是可以执行二分法逻辑的
mid_index=len(l)//2 # 地板除得整数,得到中间的索引
print(mid_index,l[mid_index])
if num
> l[mid_index]: # 如果值比中间索引的值大 那么该值在列表的右边
# in the right
l=l[mid_index+1:] # 切一刀 中间的值到最后,中间的值已经做过一次比较 所以 + 1 到最后
binary_search(l,num)
elif num
< l[mid_index]:
# in the left
l=l[:mid_index] # 顾头不顾尾,取不到mid_index
binary_search(l,num)
else:
print('find it')
return
else: # 列表为空,则证明根本不存在要查找的值
print('not
exists')
return
binary_search(l,20)
第3章 匿名函数
# 函数名可以指向内存地址
def func(x,y,z=1):
return x+y+z
print(func) # <function func at
0x0000009910729950>
# 函数名加括号传参
print(func(1,2,3))
# 匿名函数
# 1、没有函数名,直接加参数
# 2、匿名函数体只有一行代码
# 3、函数体自带return
print(lambda x,y,z=1:x+y+z) # 这就是个值 可以直接打印 <function <lambda> at 0x0000009F99619950>
f=lambda x,y,z=1:x+y+z #
给一个名字 <function <lambda> at
0x000000902A2C9950>
print(f)
print(f(1,2,3)) # 直接调用 但是匿名函数本意是不要名字
这样调用还是给了名字
# 匿名函数的应用场景:
# 应用于一次性场景,临时用 临时定义
第4章 内置函数
# 注意:内置函数id()可以返回一个对象的身份,返回值为整数。这个整数通常对应与该对象在内存中的位置,但这与python的具体实现有关,不应该作为对身份的定义,即不够精准,最精准的还是以内存地址为准。
is运算符用于比较两个对象的身份,等号比较两个对象的值,内置函数type()则返回一个对象的类型
# 更多内置函数:https://docs.python.org/3/library/functions.html?highlight=built#asci
4.1 优先掌握
4.2 面向对象
classmethod
staticmethod
property
getattr
hasattr
setattr
delattr
4.3 其他了解
4.3.1 abs( ) 取绝对值
# abs() 取绝对值 负数得正数
print(abs(-1))
>>> 1
4.3.2 all ( ) 判断可迭代参数的bool值
# all() 可迭代对象里面取出来每一个值,每一个值的bool值都为真,那么all最终的结果才为真
# 判断给定的可迭代参数 iterable 中的所有元素是否不为 0、''、False 或者 iterable 为空,如果是返回 True,否则返回 False。
# 存在一个为空的元素 存在一个为0的元素 返回Flase
# 如果可迭代对象为空 返回Ture
print(all([1,2,3,4]))
print(all([1,2,'a',None]))
print(all([1,2,'a',0]))
print(all([]))
True
False
False
True
4.3.3 any( ) 判断可迭代参数的bool值
any() 函数用于判断给定的可迭代参数 iterable 是否全部为空对象,如果都为空、0、false,则返回 False,如果不都为空、0、false,则返回 True。
print(any(['a', 'b', 'c', 'd'])) # 列表list,元素都不为空或0
print(any(['a', 'b', '', 'd'])) # 列表list,存在一个为空的元素
print(any([0, '', False]) ) # 列表list,元素全为0,'',false
print(any([]))空列表
True
True
False
False
4.3.4 bin,oct,hex 进制转换
print(bin(10)) # 转二进制
print(oct(10)) # 转八进制
print(hex(10)) # 转十六进制
4.3.5 bool 布尔值
bool() 函数用于将给定参数转换为布尔类型,如果没有参数,返回
False。
bool 是 int 的子类。
bool值为假的情况:None,空,0.False
4.3.6 bytes返回一个新的 bytes 对象
# bytes 返回一个新的 bytes 对象
#unicode-----encode------bytes
print('hello'.encode('utf-8'))
print(bytes('hello',encoding='utf-8'))
>>> b'hello'
>>> b'hello'
4.3.7 callable # 卡乐伯 是否可以被调用
# callable() 函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;但如果返回False,调用对象ojbect绝对不会成功。
# 对于函数, 方法, lambda 函式, 类, 以及实现了 __call__ 方法的类实例, 它都返回 True 。
print(callable(bytes))
True
4.3.8 chr,ord 字符与数字转换
返回值是当前整数对应的ascii字符。
print(chr(65)) # A 将数字转成字符
print(chr(35)) # #
print(ord('A')) # 65 将字符转成数字
print(ord('#')) # 35
print(chr(65)) # 65 - 90 是 A 到 Z
print(chr(90))
4.3.9 frozenset 不可变集合
s1={1,2,3,4} # s=set{1,2,3,4} 可变集合 有add方法
print(type(s1))
# frozenset 不可变集合 没有add方法
s2=frozenset({1,2,3,4})
print(type(s2))
4.3.10 dir 返回模块的属性列表
import sys
print(dir(sys))
['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_getframe', '_git', '_home', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_wrapper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'set_asyncgen_hooks', 'set_coroutine_wrapper', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']
4.3.11 divmod 返回商和余数
# divmod 返回商和余数 可以用来实现分页的功能
print(divmod(10,3)) #(3, 1)
4.3.12 enumerate 返回元祖,并为每个元素加上索引显示
l=['a','b','c','d']
res=enumerate(l)
print(res) # <enumerate object at 0x00000024A4F41A68>
for i in
res:
print(i)
>>> (0, 'a')
>>> (1, 'b')
>>> (2, 'c')
>>> (3, 'd')
l=['a','b','c','d']
res=enumerate(l)
print(res) #
<enumerate object at 0x00000024A4F41A68>
for index,item in res:
print(index,item)
4.3.13 globals,locals 查看全局作用域和局部作用域
print(globals()) # 内置和全局中的名字 字典形式展示
4.3.14 hash
# hash
print(hash('abcefg123'))
print(hash('abcefg123'))
>>> -159098785945555233
>>> -159098785945555233
4.3.15 help 查看帮助信息
def func():
'''
test function
:return:
'''
pass
print(help(func))
4.3.16 id 反映变量在内存中位置
# id 反映变量在内存中位置,是id号 并不是在内存的真实位置
# id 只是python解释器实现的功能
a=10
print(a,id(a),type(a))
>>> 10 1407764432 <class 'int'>
4.3.17 isinstance 判断变量类型
x=1
print(type(x))
print(type(x)
is int)
print(isinstance(x,int))
>>> <class 'int'>
>>> True
>>> True
4.3.18 pow平方后的取模运算
# pow
print(pow(3,2,2)) # 3 ** 2 % 2 =1
4.3.19 repr 把对象转成字符串
# repr 把对象转成字符串
print(type(str(1))) # <class 'str'> str 给用户用的
print(type(repr(1))) # <class
'str'> repr是给解释器用的
4.3.20 reversed 反转
l=[1,'a',2,'c']
print(list(reversed(l)))
print(l)
4.3.21 round 保留指定小数,并且四舍五入
round 保留指定小数,并且四舍五入
print(round(3.478,2)) # 3.48
4.3.22 slice( ) 切片
l=[1,2,3,4,5,6]
print(l[0:4:2]) # 顾头不顾尾[1, 3]
# 给一个切片对象 可以给很多列表使用
s=slice(0,4,2)
print(l[s])
# [1, 3]
4.3.23 sorted() 排序 只能同类型去排
# sorted() 排序 只能同类型去排
l=[1,10,4,3,-1]
print(sorted(l)) # 从小到大
print(sorted(l,reverse=True)) # 从小到大
4.3.24 sum 求和
#
sum() 求和
print(sum([1,2,3]))
# 传一个生成器
print(sum(i for i in range(10)))
4.3.25 zip 拉链函数
# zip 拉链函数
s='hello' # 序列类型
l=[1,2,3,4,5] # 序列类型
res=zip(s,l)
# 对应取值形成元组,多出来的不生成元组,只找对应部分
print(list(res)) # [('h', 1),
('e', 2), ('l', 3), ('l', 4), ('o', 5)]
4.3.26 __import__ 通过字符串形式来导入一个模块
m_name=input('>>>: ')
if m_name == 'sys':
# import
m_name # 变量名=
'sys' 有需求通过字符串形式来导入一个模块 这就要用__import__
m=__import__(m_name)
# print(m_name.path) # No module named 'm_name'
print(m) #
<module 'sys' (built-in)>
print(m.path) # ['D:\\Python_Learn\\day5', 'D:\\Python_Learn',
'C:\\Python36\\python36.zip', 'C:\\Python36\\DLLs', 'C:\\Python36\\lib',
'C:\\Python36', 'C:\\Python36\\lib\\site-packages']
第5章 内置函数与匿名函数的使用
5.1 求工资最高的人名 max
#与匿名函数结合使用
# max min.sorted
# filter map reduce
salaries={
'egon':3000,
'alex':10000000,
'wupeiqi':10000,
'yuanhao':2000
}
#求工资最高的人名 max
print(max(salaries))
#
yuanhao max循环字典得的是key 比较的是key 字符串的比较 “首字母”
print(max(salaries.values())) # 10000000 .values() 取得是字典的值 但是要得到的是人名
# 如果能有一种方式 让 一个值对应一个key
# 序列比较和字符串是一样的 一个个比较 1=1 'y'>'h'
# t1=(1,'h',3,4,5,6)
# t2=(1,'y',3)
# print(t1 > t2) # False
# # 带入刚才的问题
# t1=(10000000,'alex')
# t2=(3000,'egon')
# print(t1 > t2) # 比较第一个已经分出大小 ,然后再取人名
print(salaries.values())
#
dict_values([3000, 10000000, 10000, 2000])
print(salaries.keys())
#
dict_keys(['egon', 'alex', 'wupeiqi', 'yuanhao'])
# 然后使用zip 拉链
print(list(zip(salaries.values(),salaries.keys()))) # zip 可以将两个序列类型 合并成为一个元组
# [(3000, 'egon'), (10000000, 'alex'), (10000, 'wupeiqi'), (2000, 'yuanhao')]
print(max(zip(salaries.values(),salaries.keys()))[1]) # (10000000, 'alex') 最大 然后取人名 # alex
# max 已经提供了这种方法
# max(salaries,key=) # key= 想要的结果
这里要字典的key 人名 # key 告诉max 按照什么来比较
# 在这里我指定key=薪资 但是max的输出结果
还是按照字典中的key 也就是人名来输出最后的比较结果
# key=比较的依据
# # 通过key获取value
# def get_value(name):
# return salaries[name] # 就一行函数体 使用匿名函数即可
#
# max(salaries,key=lambda name:salaries[name])
# max函数默认比较的是字典的key,也就是人民 但是后面指定了 key= 所以讲salaries传给了lambda
的name,这个匿名函数获取了薪资
# 所有max每次获取到每个key人名 比较的是薪资 最后得到的是人名
# max 的for 循环 取字典一个值
就会传给后面的匿名函数
print(max(salaries,key=lambda name:salaries[name]))
# alex
def get_value(name):
return salaries[name]
l=[]
for name in salaries:
res=get_value(name)
l.append(res)
print(max(l))
5.2 求工资最低的人名 min
print(min(salaries,key=lambda name:salaries[name])) # yuanhao
5.3 排序 sorted 默认从小到大
# 排序 sorted
salaries={
'egon':3000,
'alex':10000000,
'wupeiqi':10000,
'yuanhao':2000
}
# 按照名字排序
# print(sorted(salaries)) # ['alex',
'egon', 'wupeiqi', 'yuanhao'] 默认从小到大
def get_value(name):
return salaries[name]
# 按照工资排序
# print(sorted(salaries,key=get_value)) # ['yuanhao', 'egon', 'wupeiqi',
'alex']
# 反转 从大到小
# print(sorted(salaries,key=get_value,reverse=True)) # ['alex', 'wupeiqi',
'egon', 'yuanhao']
# 匿名函数的写法
print(sorted(salaries,key=lambda name:salaries[name])) # ['yuanhao', 'egon', 'wupeiqi', 'alex']
print(sorted(salaries,key=lambda name:salaries[name],reverse=True)) # ['alex',
'wupeiqi', 'egon', 'yuanhao']
5.4 合并 reduce
# redice 合并
# 在python2里是内置函数 python3要导入functools
from functools
import reduce
print(reduce(lambda x,y:x+y,range(101))) #方法,序列,初始值(默认none) # 5050
print(reduce(lambda x,y:x+y,range(101),100)) # 5150
# 原理:reduce 如果有初始值,会把初始值作为第一个值
# for循环后面的序列 得到一个值
# 实际上现在有两个值了 初始值和后面循环的值
# 然后将这两个值 传给前面的函数 x,y 然后会得到第一次计算加法的结果 == 0+100 100
# 然后在for循环 再得到一个值1,那么现在 x=100 ,y=1 传给函数
==101 然后继续循环
# 没有指定默认值会先循环一次range(101) 得到的第一个值 作为初始值 所以初始值是0
5.5 生成器与迭代器 自己做map方法
names=['alex','wupeiqi','yuanhao','egon'] # 每一个元素映射成一个sb结尾
# def my_map(seq):
# new_list=[]
# for item in seq:
# item=item+'_SB'
# new_list.append(item)
# return new_list
#
# print(my_map(names))
# 如果列表非常大 会很占内存 所有要用 yield
def my_map(seq):
for
item in
seq:
item=item+'_SB'
yield
item # generator object my_map at
0x00000077DEB310F8 生成器 都是 迭代器 省内存
res=my_map(names)
print(next(res))
print(next(res))
print(next(res))
print(next(res))
def my_map(func,seq):
for item
in seq:
yield
func(item) # generator object my_map at 0x00000077DEB310F8
生成器 都是 迭代器 省内存
res=my_map(lambda x:x+'_SB',names)
print(next(res))
5.6 filter() 过滤出bool值为真的值
#
filter() 过滤出bool值为真的值
# 过滤出结尾SB
names=['alex_SB','wupeiqi_SB','yuanhao_SB','egon']
print(filter(lambda name:name.endswith('SB'),names))
print(list(filter(lambda name:name.endswith('SB'),names)))
# ['alex_SB', 'wupeiqi_SB', 'yuanhao_SB']
5.7 eval、compile和exec
# eval 将字符串转成命令执行
# 作用域:全局 和 局部 全都是字典形式 eval 会先找局部
cmd='print(x)'
x=1
eval(cmd)
eval(cmd,{'x':0},{'x':123}) # 123 走的局部
eval(cmd,{'x':0},{'y':123}) # 0 走的全局
compile # 编译
s='for i in range(10):print(i,x)'
code=compile(s,'','exec') # 代表编译成可执行的代码
print(code) # <code object <module>
at 0x0000009747261270, file "", line 1>
# exec(code) # exec执行编译之后的结果
exec(code,{},{'x':111}) # 局部作用域