美文网首页
第五篇 匿名函数、内置函数、import的使用、包的使用

第五篇 匿名函数、内置函数、import的使用、包的使用

作者: 张大志的博客 | 来源:发表于2018-06-14 15:04 被阅读0次

一、函数的递归调用

#函数递归调用:在调用一个函数的过程中直接或间接地调用该函数本身,称之为函数的递归调用,也就是函数的嵌套调用时调用自己本身
import sys
print(sys.getrecursionlimit()) #打印发现默认递归的层级是1000
sys.setrecursionlimit(2000) #可以修改递归的层级到2000
n=1
def func1():
    global n
    print('from func1',n)
    n+=1
    func1()
func1()

#间接地调用自身也叫递归调用
def func():
    print('from func')
    bar()

def bar():
    func()
func()

#递归分为两个重要的阶段:递推+回溯
# age(5)=age(4)+2
# age(4)=age(3)+2
# age(3)=age(2)+2
# age(2)=age(1)+2
# age(1)=18
# n!=1 #age(n)=age(n-1)+2
# n=1 #age(n)=18

上面的例子可以用函数的递归调用表示
def age(n):
    if n == 1:
        res=18
        return res
    res=age(n-1)+2 #res=age(4)+2
    return res
print(age(5))

#总结递归调用:
#1:进入下一次递归时,问题的规模必须降低
#2:递归调用必须要有一个明确的结束条件
#3:在python中没有尾递归优化,递归调用的效率就是不高

#练习,取出列表中的每一元素
l=[1,2,[3,[4,[5,[6,7,[8,9,[10,[11,[12,]]]]]]]]]
def get(l):
    for item in l:
        if isinstance(item,list): #等于if type(item) is list,判断item是否是列表类型
            get(item) #如果是列表就递归调用
        else:
            print(item)
get(l)

二、二分法

判断一个数字是否在这个列表内,如果在就打印find it
l=[1,2,10,30,33,99,101,200,301,402] #从小到大排列的数字列表,如果不是按照顺序排列的不能用二分法
def get(num,l):
    print(l)
    if len(l) > 0: #列表不为空,则证明还有值是可以执行二分法逻辑的
        mid=len(l)//2 #地板除只取整数部分
        if num > l[mid]:
            #in the right
            l=l[mid+1:] #对列表进行切分,取列表的右半部分
        elif num < l[mid]:
            #in the left
            l=l[:mid]
        else:  #如果正好是中间的值
            print('find it')
            return
        get(num,l) #使用函数的递归调用
    else: #列表为空,则证明根本不存在要查找的值
        print('not exists')
        return
get(403,l)

三、匿名函数

#匿名函数即没有绑定名字的函数,没有绑定名字,意味着只能用一次就会被回收
#所以说匿名函数的应用场景就是:某个功能只用一次就结束了
def f1(n):
    return n**2
print(f1(3)) #打印函数的返回值
上面的代码可以写成匿名函数
f2=lambda n:n**2 #n:n**2第一个n是上面函数中的参数,匿名函数只能写到一行,并且把冒号后面的当做匿名函数的返回值,不用加return
print(f2(3))

取出最大的工资
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}
print(max(salaries)) #默认比较的是key
print(max(salaries.values())) #要取value需这样写
运行结果:
Yuanhao  
100000000

#拉链函数
l1=[1,2,3]
s1='hello'
res=zip(l1,s1)
print(list(res)) #把res的值放到列表中
执行结果:
[(1, 'h'), (2, 'e'), (3, 'l')]
发现拉链函数是把l1和s1中的元素按照顺序合起来放在元组中
#补充:序列类型的比较,先比较第一个,如果第一个一样大才比较第二个,有索引的叫做序列类型
两个元组比较大小
t1=(3333,'a')
t2=(2,'a','b','c')
print(t1 < t2)
运行结果为False

把工资最大的人名取出来
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}
res=zip(salaries.values(),salaries.keys())
#print(max(res)) #发现把工资最大的和人名放到一个元组中
print(max(res)[1]) #要取出人名就取元组中索引为1的元素

#max与lambda的结合
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}
def f1(k):
    return salaries[k]
print(max(salaries,key=f1))  #表示取最大值,不是键而是值,key=什么表示要取的什么,因为key=f1函数的返回值,表示要取value的最大值
运行结果为:alex

上面代码可以用匿名函数简写为
print(max(salaries,key=lambda k:salaries[k])) #表示取的是lambda匿名函数的最大值,此匿名函数的返回值为salaries[k],如果k=alex,就是比较alex的value是不是最大的,不是就继续比较
print(min(salaries,key=lambda k:salaries[k]))
print(sorted(salaries,key=lambda k:salaries[k])) #表示排序,按照lambda函数的返回值排序,也就是按照工资排序
print(sorted(salaries,key=lambda k:salaries[k],reverse=True))

执行结果为:
Alex    
Yuanhao
['yuanhao', 'egon', 'wupeiqi', 'alex']
['alex', 'wupeiqi', 'egon', 'yuanhao']

匿名函数其他常用的其他用途
#map,reduce,filter
map表示映射,在列表中所有的人名后面加_SB结尾
l=['alex','wupeiqi','yuanhao','huanghongwei']
print(list(map(lambda x:x+'_SB',l)))
执行结果:
['alex_SB', 'wupeiqi_SB', 'yuanhao_SB', 'huanghongwei_SB']
reduce表示合并:计算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(1,101))) #,匿名函数有x,y两个参数,默认初始值是0,首先取初始值0,然后在range中取第一个元素1,进行运算,运算的结果再取一个元素进行加运算,
print(reduce(lambda x,y:x+y,range(1,101),100)) #如果初始值是100,就会100+1,然后101+2,103+3这样运算
执行结果:
5050
5150
filter:过滤,把SB结尾的过滤出来
l=['alex_SB','wupeiqi_SB','yuuanhao_SB','hhw','egon']
res=filter(lambda name:name.endswith('SB'),l)
print(list(res))

四、内置函数

#其他内置函数
print(abs(-1)) #求-1绝对值为+1

print(all([1,'a',[]])) #all的参数为可迭代对象,并且可迭代对象中的每一个元素都为真,结果才为真,否则为假
print(all([])) #如果参数为空,则结果为真,空不是没有参数,而是空列表或者空元组、字典等
执行结果:
False
True

print(any([0,None,'',1])) #any表示参数为可迭代对象中的元素有一个为真,结果为真
print(any([])) #False

print(bin(10)) #十进制转化为二进制
print(oct(10)) #十进制转化为八进制
print(hex(10)) #十进制转化为十六进制

# bool()
#布尔值为假:0,None,空

把字符串转化为bytes类型
print('hello'.encode('utf-8'))
print(bytes('hello',encoding='utf-8'))

print(callable(max)) #判断对象是否是可调用的,max是个内置函数,可以被调用,结果为True

print(chr(65)) #把数字根据ASIC表转化为对应的字母
print(chr(90))
print(ord('A')) #反过来,转化为数字

#complex复数
x=1-2j #x=complex(1-2j)
print(type(x)) #查看类型
print(x.real) #查看复数的实部为1
print(x.imag) #查看虚部为-2

#dict,int,list,tuple,str,float,set,frozenset
s=set({1,2,3}) #可变集合,造的集合是可变类型的,set是内置函数,用来造可变集合
s=frozenset({1,2,3}) #不可变集合,造的集合是不可变类型的
dict是内置函数,用来造字典

import time
print(dir(time))#查看一个模块都有哪些属性,比如time.time属性等

print(divmod(1001,25)) #40是商,1是余数
运行结果:(40, 1)

l=['a','b','c','d']
for x in enumerate(l):
    print(x)
运行结果:取出列表里的元素的同时,还取出索引
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')

print(hash('asdfasdfasdfasdfasdf')) #取哈希值

查看函数的注释信息
def func():
    '''
    xxxxxx
    :return:
    '''
    pass
print(help(func)) 

print(isinstance(1,int)) #判断一个数据是不是什么类型
print(type(1) is int) #也可以用这种方式,但推荐用上面那种

print(pow(10,2,3)) #10**2%3

print(str({'a':1})) #把一个数据类型转化为字符串

l=[1,4,2,9]
print(list(reversed(l)))#对列表倒着排

print(round(10.55545,3)) #表示保留三位小数,四舍五入

l1=['a','b','c','d','e']
l2=['a','b','c','d','e']
print(l1[1:5:2]) #'b','d'
print(l2[1:5:2]) #'b','d'
下面这种方式和上面是一样的
l1=['a','b','c','d','e']
l2=['a','b','c','d','e']
obj=slice(1,5,2)#可以取切片对象
print(l1[obj])
print(l2[obj])

print(sum([1,2,3,4])) #传进来的值可以是列表、元组、集合等数字
print(sum(range(10)))#sum函数可以把传进来的参数变成迭代器,next一次取一次值

print(vars() is locals())#不加参数vars函数是看局部作用域的名字,等于locals函数
vars(obj) 等同于obj.__dict__

# import "time" #import 不能导入字符串,但可以通过如下方式导入字符串
m=input('>>: ')
print(type(m))
obj=__import__(m) #实现与用户交互的方式导入模块,比如输入的是time字符串,就相当于导入time模块
print(obj.time())

#了解:compile,exec,eval
#eval:提取字符串内的表达式执行,然后返回执行结果
s1="1+2+3"
print(eval(s1))
s2="['a','b','c']"
l=eval(s2)
print(type(l))
print(l)
执行结果:
6
<class 'list'>
['a', 'b', 'c']
s2="for i in range(10):print(i)"
eval(s2) #运行会报错,因为没有执行结果

#exec:仅仅只是执行字符串内的表达式或语句,没有返回值
s1="1+2+3"
print(exec(s1))
s2="for i in range(10):print(i)"
exec(s2)#可以执行

#优先掌握
max min sorted map   from functools import reduce   filter sum bool chr
divmod enumerate id input print isinstance iter len open pow type
zip

五、import的使用

#常见的场景:一个模块就是一个包含了一组功能的python文件,比如spam.py,模块名为spam,可以通过import spam使用。
#在python中,模块的使用方式都是一样的,但其实细说的话,模块可以分为四个通用类别: 

  1 使用python编写的.py文件

  2 已被编译为共享库或DLL的C或C++扩展

  3 把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)

  4 使用C编写并链接到python解释器的内置模块
#导入模块,只会在第一次导入时执行源文件的代码
#如果模块已经加载到内存了,下一次导入直接引用内存中导入的结果
import spam #m1=111111
import spam #m2=m1
import sys
print(sys.modules) #查看内存中已经加载的模块
print('spam' in sys.modules) #查看spam模块是否在内存中
#import 导入文件都做了哪些事?
#1 以源文件为准产生一个名称空间,在spam.py文件里
#2 以刚刚产生的名称空间为准,执行源文件的代码
#3 会在当前文件中定义一个名字,这个名字就是模块名,用来引用模块中的名字
#spam.py
print('from the spam.py')
money=1000
def read1():
    print('spam模块:',money)
def read2():
    print('spam模块')
    read1()
def change():
    global money
    money=0

import spam #导入模块就会执行源文件的代码
money=0
def read1():
    print('from ------>')
read1()#调用的是当前文件的read1
spam.read1() #调用的是spam.py文件中的read1
spam.read2()
money=1000000000
spam.change()
print(money) #打打印的是当前文件定义的money
spam.read1()
总结:import导入spam模块后,可以使用spam.调用spam.py文件的内容

六、from...import的使用

#spam.py
print('from the spam.py')
money=1000
def read1():
    print('spam模块:',money)
def read2():
    print('spam模块')
    read1()
def change():
    global money
    money=0

#为模块起别名
import spam as sm
print(sm.money)
举例
#mysql.py
def parse():
    print('mysql sql parse')
#oracle.py
def parse():
    print('oracle sql parse')

engine_type='mysql'
if engine_type == 'mysql':
    import mysql as engine
elif engine_type == 'oracle':
    import oracle as engine
engine.parse()
#在一行导入多个模块
import spam,time
#导入模块的另外一种方式:from...import...
from spam import money,read1,read2,change #从哪个模块导入什么属性
money=1
print(money) #打印的是当前文件的
read1() #好处是调用的时候不用加前缀spam.read1(),坏处会和当前文件的冲突
def read1():
    print('===>?')
read1()#调用当前的
read2()
change()
print(money) #打印当前文件的

from spam import * #可以导入模块的所有属性,但不知道都导入了什么,尽量不要用,不然冲突的可能性更大
print(money)
print(read1) #打印函数的内存地址
print(read2)
print(change)

#spam.py
print('from the spam.py')
__all__=['money','read1'] #from ... import *
money=1000
def read1():
    print('spam模块:',money)
def read2():
    print('spam模块')
    read1()
def change():
    global money
    money=0

from spam import * #* 对应模块spam内的__all__属性
print(money)
print(read1)
print(read2) #此时会报错,因为没有导入此属性

七、python文件的两种用途

#模块的重载 (了解)
考虑到性能的原因,每个模块只被导入一次,放入字典sys.module中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块,
有的同学可能会想到直接从sys.module中删除一个模块不就可以卸载了吗,注意了,你删了sys.module中的模块对象仍然可能被其他程序的组件所引用,因而不会被清楚。
特别的对于我们引用了这个模块中的一个类,用这个类产生了很多对象,因而这些对象都有关于这个模块的引用。
如果只是你想交互测试的一个模块,使用 importlib.reload()可以重新加载模块, 比如
import importlib 
importlib.reload(modulename)#这只能用于测试环境。

#py文件区分两种用途:模块与脚本
#编写好的一个python文件可以有两种用途:    
一:脚本,一个文件就是整个程序,用来被执行
二:模块,文件中存放着一堆功能,用来被导入使用
#python为我们内置了全局变量__name__,
 当文件被当做脚本执行时:__name__ 等于'__main__'
 当文件被当做模块导入时:__name__等于模块名,也就是说如果被导入的模块中含有__name__代码,那么__name__等于模块名
#作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':
总结一下:
如果我们是直接执行某个.py文件的时候,该文件中”__name__ == '__main__'“是True,但是我们如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字而不是__main__。
这个功能还有一个用处:调试代码的时候,在”if __name__ == '__main__'“下面加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码

八、模块的搜索路径

#模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
import sys
sys.path.append(r'D:\张大志迈远\pythontest\day5\day5\a') #如果模块的py文件与执行文件不在同一目录下,要将模块的py文件加到sys.path环境变量中才能导入模块sys.path.append或者sys.path.insert
import m
或者
from a import m

九、包的使用

1、什么是包?
#官网解释Packages are a way of structuring Python’s module namespace by using “dotted module names”
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。
#具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来
#需要强调的是:
  1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块

#导入包实际上就是在导入包下面的__init__.py文件,如果想调用包下的其他模块文件,需要先在__init__.py文件中导入此模块文件才能使用包下的其他模块,__init__.py文件的path环境变量路径和执行文件环境变量相同,也就是执行文件在哪个目录下,_init__.py文件的环境变量也在哪个目录下

在__init__.py中导入模块的方法
from aaa import m1 #导入aaa目录下的m1模块,这样在执行文件中就可以使用这个模块
在执行文件中的操作
import aaa #在执行文件中先导入aaa这个包,就是导入__init__.py文件,因为此文件中已经导入m1模块
aaa.m1.f1()#就可以在执行文件中调用m1模块下的f1属性

如果想在执行文件中直接调m1模块的f1属性
#点的左边必须是包,from...import后必须是一个明确的名字,不能带点
from aaa.m1 import f1 #在__init__.py中导入的方式
在执行文件中调用的方式
import aaa #先导入包,因为__init__.py中已经导入f1属性
aaa.f1() #就可以在执行文件中直接调用f1属性

以上导入包的方式都是绝对路径的导入,都是从包的顶级目录开始找
也可以用相对路径的方式导入包
from .. ccc import f4 #..表示上一级目录,加一个点就表示上一级
from . bbb.m3 import f3 #. 表示当前目录,和linux里面的一样

如果执行文件和导入的包不在同一目录下,需要在执行文件中先将包所在的目录加入环境变量,才能导入包
import sys
sys.path.append(r'C:\Users\Administrator\PycharmProjects\python19期\day5\7 包的使用\xxx\yyy') 
import aaa

也可以不依赖于__init__.py文件,直接在执行文件中把包文件导入
import aaa.ccc.m4 #导入aaa包下的ccc包下的m4.py文件
aaa.ccc.m4.f4() #调用的时候就要把包名都写上,可以把整个包起别名,调用的时候简单

十、软件开发规范

import os
print(os.path.abspath(__file__)) #打印当前文件的绝对路径
print(os.path.dirname(os.path.abspath(__file__))) #当前文件所在的目录
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #当前文件的上一级目录

#start.py
#目录结构ATM/bin/start.py   ATM/core/src.py  ATM/conf/setting.py
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #将ATM目录加入到path变量里,因为已经添加到环境变量里了,在任意文件中都可以用这个环境变量
from core import src
if __name__ == '__main__':
    src.run()
#src.py
from conf import settings
def shop():
    print('shopping',settings.DB_PATH)
def run():
    while True:
        print('''
        1 购物
        2 付款
        3 还款
        4 转账
        ''')
        choice=input('>>: ').strip()
        if not choice:continue
        if choice == '1':
            shop()
#setting.py
DB_PATH=r'C:\Users\Administrator\PycharmProjects\python19期\day5\8 软件开发规范\ATM\db'

相关文章

  • 第五篇 匿名函数、内置函数、import的使用、包的使用

    一、函数的递归调用 二、二分法 三、匿名函数 四、内置函数 五、import的使用 六、from...import...

  • 函数进阶_2

    目录 常用内置函数 匿名函数 高阶函数 闭包 装饰器 1. 常用内置函数 1.1 range()函数 语法:ran...

  • 匿名函数与闭包

    程序语言支持匿名函数时, 可以由匿名函数形成闭包 闭包的作用在函数外部使用函数内部的变量函数内部变量的持久化 参考...

  • 匿名函数与闭包

    转自匿名函数与闭包的区别 匿名函数没有函数名称的函数; 闭包一个可以使用另外一个函数作用域中的变量的函数,或者说是...

  • golang函数闭包

    定义 Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。匿名函数的优越性在于可以直接使用函数...

  • Java8-lambda表达式

    匿名接口方法 方法引用 集合排序与遍历 匿名排序比较 系统内置的一些函数式接口 闭包中使用的变量变final修饰的...

  • Go 语言函数闭包

    Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。 匿名函数的优越性在于可以直接使用函数内的...

  • Kotlin:高阶函数与 Lambda 表达式(四)

    本篇内容清单如下: 高阶函数 函数类型 Lambda 表达式 匿名函数 闭包 内联函数 Kotlin 函数使用场景...

  • go 匿名函数

    Go支持匿名函数,如果我们某个函数只是希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用1、匿名函数使...

  • php中的匿名函数和闭包

    php中的匿名函数和闭包(closure) 一:匿名函数 (在php5.3.0 或以上才能使用) php中的匿名函...

网友评论

      本文标题:第五篇 匿名函数、内置函数、import的使用、包的使用

      本文链接:https://www.haomeiwen.com/subject/nhlyeftx.html