python性能分析与优化_python 性能分析-程序员宅基地

技术标签: python  PYTHNON  后端  开发语言  

性能分析:

1.种类:

基于事件的性能分析
    通过收集程序执行过程中的具体事件进行工作,每个调用都会触发,输出数据量大,精度高
    def profiler(frame, event, arg):
        print 'PROFILER: %r %r' % (event, arg)
    sys.setprofile(profiler)        # 此后的所有调用都会触发函数
统计式性能分析
    以固定的时间间隔对程序计数器(program counter)进行抽样统计,掌握目标程序在每个函数上消耗的时间
    优点:
        分析的数据更少
        对性能造成的影响更小
    如statprof

2.瓶颈

沉重的I/O操作,比如读取和分析大文件,长时间执行数据库查询,调用外部服务(比如HTTP请求),等等。
出现了内存泄漏,消耗了所有的内存,导致后面的程序没有内存来正常执行。
未经优化的代码被频繁地执行。
密集的操作在可以缓存时没有缓存,占用了大量资源。

3.运行时间

常数时间
    如字典查找
线性时间
    遍历序列
对数时间
    随着输入数量的增加,对数函数开始增长很快,然后慢慢减速
    如二分查找
线性对数时间
    如一些高级排序法
阶乘时间
    暴力破解法
平分时间
    冒泡排序,遍历二维数组,插入排序
# 运行包括最好情况、正常情况和最差情况,也与输入数据有关

4.性能测试套件

建立回归测试套件,预处理数据,对数据进行可视化

性能分析器:

1.cProfile:

概述:
2.5以后版本,pypy没有
作用:
统计每个函数消耗的CPU时间。同时它还提供了其他细节,比如函数被调用的次数。
只测量CPU时间,并不关心内存消耗和其他与内存相关的信息统计

示例:
import cProfile
cProfile.run('fib_seq(2)')

15 function calls (11 primitive calls) in 0.000 seconds                    # 11个原生调用
ncalls  tottime  percall  cumtime  percall filename:lineno(function)    
1      0.000    0.000    0.000    0.000 <string>:1(<module>)
5/3    0.000    0.000    0.000    0.000 test1.py:14(fib)

ncalls 表示函数调用的次数,两个数值时,总调用次数/原生调用的次数,数值过大时表示bug或者需内联函数扩展的位置(即不回调函数,而是直接写)
tottime是函数内部消耗的总时间,不包括调用其他函数的时间
percall是tottime除以ncalls,表示一个函数每次调用的平均消耗时间
cumtime是之前所有子函数消耗时间的累计和(也包含递归调用时间),可以整体式识别性能,如算法选择错误
另一个percall是用cumtime除以原生调用的数量,表示到该函数调用时,每个原生调用的平均消耗时间
filename:lineno(function)显示了被分析函数所在的文件名、行号、函数名。

命令行测试:
对源代码干扰更少,不需要增加任何代码,运行脚本时需要添加参数
python -m cProfile your_script.py -o your_script.profile

局限:
测试时,会影响实际性能
代码内部时钟有一个精度范围,小于该精度的测量会测不出来

方法:
run(command, filename=None, sort=-1)
    内部执行exec(command, __main__.__dict__, __main__.__dict__)
runctx(command, globals, locals, filename=None)        # 能在函数内运行,能识别内部导入的模块
    内部执行exec(command, globals, locals)
Profile(timer=None, timeunit=0.0,subcalls=True,builtins=True)方
    返回类的其他方法:
        enable():表示开始收集性能分析数据。
        disable():表示停止收集性能分析数据。
        create_stats():表示停止收集数据,并为已收集的数据创建stats对象。
        print_stats(sort=-1):创建一个stats对象,打印分析结果。
        dump_stats(filename):把当前性能分析的内容写进一个文件。
        run(cmd):和之前介绍过的run函数相同。
        runctx(cmd, globals, locals):和之前介绍过的runctx函数相同。
        runcall(func, *args, **kwargs):收集被调用函数func的性能分析信息。
    示例:
        prof = cProfile.Profile()
        prof.enable()
        xx
        prof.create_stats()
        prof.print_stats()

Stats类:
概述:
pstats模块为开发者提供了Stats类,可以读取和操作stats文件

方法:
strip_dirs():删除报告中所有函数文件名的路径信息。这个方法会改变stats实例内部的顺序
add(*filenames):这个方法将文件名对应的文件的信息加载到当前的stats对象中
dump_stats(filename):就像cProfile.Profile类,这个方法把加载到Stats类的数据保存为一个文件。
sort_stats(*keys):依次对所有项目进行排序,从而调整stats对象的
reverse_order():这个方法会逆反原来参数的排序方法
print_stats(*restrictions):这个方法是把信息打印到STDOUT。
print_callers(*restrictions)显示程序执行过程中调用的每个函数的调用次数、总时间和累计时间,以及文件名、行号和函数名的组合。
print_callees(*restrictions)方法打印一列调用其他函数的函数。

示例:
prof = cProfile.Profile()
prof.enable()        # 开始性能分析
运行函数()    
prof.create_stats()
p=pstats.Stats(prof)                # stats接收cProfile.Profile()的实例参数
p.print_stats(10,1.0,'.*.py.*')        # p.print_callers()
stats.strip_dirs().sort_stats('cumulative').print_stats()

总结:
获取每个函数的调用次数和总调用次数。
是确定性分析,即基于事件的性能分析器的另一种说法

2.line_profiler

概述:
一行一行地分析函数性能,而不是像cProfile那样做确定性性能分析。

安装:
pip install line_profiler
失败可以尝试whl安装

优点:
弥补cProfile和类似性能分析器的不足(主要关注函数调用消耗的CPU时间),
能发现发生在函数的某一行中的问题

方法:
和cProfile.Profile一样,也提供了run、runctx、runcall、enable和disable方法。
但是最后两个函数在嵌入模块统计性能时并不安全,使用时要当心。
示例:
    prof = line_profiler.LineProfiler(test) # 把函数传递到性能分析器中
    prof.enable() # 开始性能分析
    test()
    prof.disable() # 停止性能分析
    prof.print_stats(sys.stdout) # 打印性能分析结果

kernprof工具:
安装后自带。
kernprof会创建一个性能分析器实例,并把名字添加到__builtins__命名空间的profile中
使用:
    @profile
    def func(n):
    然后命令行启动:kernprof -l -v script_to_profile.py     # -v属性立刻输出结果在命令行
注意事项:
    时间问题,在性能分析函数调用另一个函数时,没有把每一行消耗的时间增加到总时间上:
    列表综合(list comprehension)表达式的Hit比它们实际消耗的要多很多

优化点:
函数结果缓存
lambda函数多次调用时事先创建函数
多余的变量声明和查询
dict和defaultdict类
字符串连接+比c语言%快

可视化性能分析:

1. KCacheGrind/pyprof2calltree

概述:
通过pyprof2calltree这个工具把cProfile的输出结果转换成KCacheGrind可以读取的形式。

安装:
pip install pyprof2calltree
sudo apt-get install kcachegrind

用法:
1.命令行形式,命令行加参数
pyprof2calltree -o [output-file-name] -i input-file.prof
-k:如果想立即运行KCacheGrind,就可以加上这个参数。
-r:如果还没有性能分析数据,可以用这个参数直接分析Python脚本文件生成最终结果。

2.在REPL(read-eval-print loop,读取-求值-输出循环)交互式编程环境里运行(也可以根据需要在性能分析的脚本中运行)
convert:会输出性能分析结果文件
visualize:直接启动KCacheGrind显示结果
示例: 
    from xml.etree import ElementTree
    from cProfile import Profile
    import pstats
    xml_content = '<a>\n' + '\t<b/><c><d>text</d></c>\n' * 100 + '</a>'
    profiler = Profile()            # 实例化
    profiler.runctx("ElementTree.fromstring(xml_content)", locals(), globals()) # 执行脚本
    from pyprof2calltree import convert, visualize      # 导入
    stats = pstats.Stats(profiler)                      # 获取stat
    visualize(stats)        # 运行kcachegrind
结果分析

1.Incl.列:这个指标表示函数的累计消耗时间。包含被它调用的函数消耗的时间
2.Self列:只包含函数本身消耗的时间,不包括它调用的函数需要的时间。

2. RunSnakeRun

概述:
KCacheGrind也适用于C和C++开发者,而RunSnakeRun是专门为Python开发者定制的。        

区别:
无需像KCacheGrind一样借助pyprof2calltree,本身读取和解释分析结果,只要设置好文件路径就行。

安装:
pip install wxpython
pip install SquareMap RunSnakeRun

使用:
python -m cProfile -o test.prof inverted-index.py
runsnake test.prof

优化细节:

1.函数返回值缓存和函数查询表

把函数、输入参数和返回值全部都保存起来,在函数下次被调用时直接使用存储的结果

2.使用默认参数

默认参数(default argument)可以在函数创建时就确定输入值,而不用在运行阶段才确定输入。
注:函数的接口容易造成混乱。    

3.列表综合表达式与生成器

普通for循环产生的指令集更长。
列表综合产生的指令集就像是for循环指令集的真子集,主要的差异是数值被增加到列表中的方式不同。
在for循环里,数值是一个一个增加的,用到三个指令;列表综合只用了一个简单且已经经过优化的指令
# 适合:列表推导式能替代for循环生成列表
# 如果列表的数量大,就用生成器
生成器:
    只能遍历一次

4.ctypes库

可以接入Windows系统上的kernel32.dll和msvcrt.dll动态链接库,以及Linux系统上的libc.so.6库。
使用: 
    将关键代码写成c语言,编译成一个库,然后导入Python当作模块使用。
    有时,系统的库文件已经写好了c函数,只需加载一个系统库就行

5.字符串连接

由于字符串是不可变的,每当我们要做任何改变字符串内容的操作时,其实都是创建了一个带有新内容的新字符串,我们的变量会指向新创建的字符串。
因此,处理字符串时必须小心谨慎,三思而后行。

细节:
    str = str1+str2+str3用C语言字符串的变量内插法更好,str = "%s%s%s"%(str1,str2,str3)
    或者用locals函数创建子字符串:
        document = "%(title)s%(introduction)s%(main_piece)s%(conclusion)s" % locals()

6.其他:

成员关系测试:
用set或dict比list好

使用标准库:
大都是经过优化的C语言写成,如内置数据类型,数组(array)、迭代工具(itertools)、队列(collections.deque)    
内置函数operator.add比lambda x, y: x+y好

队列collections.deque:
在pop(0)和insert(0,v)操作时比list更好        

不定义嵌套函数:
内置函数代码,虽然可能会损害代码的可读性和维护便利性

尽可能用key函数排序而不是cmp:
list1.sort(cmp=lambda a, b: cmp(a[1], b[1]))
list2.sort(key=lambda a: a[1])

1比True好:
while 1得到了优化,跳转一次就能完成,而while True并没有,因此需要跳转好几次才能完成。
多元赋值(multiple assignments)很慢但变量交换时,它比普通方法要快
因为我们不需要使用临时变量和赋值过程

推荐使用链式比较:
在比较三个变量时,不要用 x<y 和 y<z,可以用 x<y<z。

用命名元组(namedtuple)替换常规对象:
使用常规的类(class)方法创建存储数据的简单对象时,实例中会有一个字典存储属性。这个存储对属性少的对象来说是一种浪费

pypy:

概述:

分析程序运行并对那些频繁执行的部分生成本机机器码,通常可以接近C 代码的速度

安装使用:

window:
下载压缩包,解压后添加系统环境变量

linux:
wget https://bitbucket.org/pypy/pypy/downloads/pypy2.7-v7.0.0-linux64.tar.bz2
tar xf pypy2.7-v7.0.0-linux64.tar.bz2
mv pypy2.7-v7.0.0-linux64/ pypy2.7-7
ln -s ~/data/pypy2.7-7/bin/pypy /usr/bin/

使用pip安装第三方包:

pypy -m ensurepip安装未带pip的安装包
pypy -m pip install xx

问题:

1. 第三方库有些不支持,如内存检测guppy
2. 内存比普通的python高,如跑id level持续高 # python也会存在该问题,貌似pypy速度快,内存上升快
解决方法:
开较少uid的进程,运行完该范围就关闭进程,重新开启进程,尝试过,速度貌似提升不明显,有可能瓶颈不在计算上

3.内存回收好像有问题
原因:可能在于pypy的优化理念与cpython不一样,例如字符串+拼接在pypy很慢

4.pypy的回收机制不同,尝试设置环境变量还是不行
os.environ['PYPY_GC_MAX'] = "1GB"
os.environ['PYPY_GC_MAX'] = "0.5GB"
os.environ['PYPY_GC_GROWTH'] = "1.2"

JIT优化:

1.针对函数的优化
JIT可以分析函数热度,即判断哪个函数比其他函数“更热”(hotter,执行次数更多),从而做出优化
# 可能会比直接内联要更快,所以反复调用函数的代码可以利用JIT优化
JIT会实时优化代码

2.考虑用cStringIO连接字符串
想把大量的字符串连接成一个对象,用cStringIO模块

3.禁止JIT的操作
# 执行下面操作时通过sys模块JIT会禁用
_getframe:这个方法会从callstack返回一个frame对象,也可以接受一个从callstack发出的带深度参数的callstack对象作为参数。
        这么做性能损失非常大,非万不得已最好别用,比如系统调试的时候
exc_info:这个方法会返回一个三元素的元组,提供待处理异常的相关信息。三个元素分别是type、value和traceback,具体解释如下。
        type:待处理的异常类型。
        value:异常参数。
        traceback:跟踪traceback对象,当异常被抛出时,里面会封装一个callstack对象。
settrace:这个方法可以设置跟踪函数。它能让你从Python内部跟踪Python代码。
    就像前面提到的,这个方法也是万不得已时才用,因为它在执行时会禁止JIT。

Cython:

概述:

直接将Python代码编译成C语言(CPython不会这么做)
其实是一个转换器,可以简单看成一个软件,它可以把源代码从一种语言翻译成另一种语言

作用:

用Python代码调用原生C/C++
用静态类型声明把Python代码优化成C语言的性能

静态类型:

静态类型是Cython这个翻译器产生优化的C语言代码的主要特征,可以把Python的动态特性转变成静态且更快的代码(有时候可以达到几个数量级)。
坏处是变得更啰嗦

安装:

pip install cython

使用:

将代码中变量和参数改成C语言类型,然后用cython编译成.c文件,然后变成.o 

限制:

1.生成器表达式
由于表达式计算范围(evaluation scope)的限定有问题,因此不能在生成器表达式内部使用可迭代对象    
在处理生成器表达式内部使用可迭代对象时,Cython会在生成器内部计算可迭代对象。而CPython是在生成器外部计算。
CPython的生成器具有一些属性可以让用户查看。但是Cython的生成器的这类属性还不够全面。

2.对比char*常量
字节字符串比较是通过指针实现的,并不是字符串的真实值

3.元组作为函数参数
4.栈帧

数据处理:

1.Numba

能够(通过装饰器)控制Python解释器把函数转变成机器码
只是针对数组操作进行优化,它非常适合配合NumPy使用
安装: 
    pip install numba
作用: 
    即时代码生成(On-the-fly code generation)
    CPU和GPU原生代码生成
    与具有NumPy依赖的Python科学计算软件配合使用
使用: 
    使用@jit装饰器。加上它就表示要用Numba的JIT编译器对函数进行优化。
    1.函数接收类型
        @jit(int32(int32, int32))
    2.没有GIL
        @jit(nogil=True),用多线程运行Python代码
    3.无python模式
        @jit(nopython=True)
        只有一部分函数和方法可以使用。

2.pandas

提供了一系列高性能的数据结构和分析工具。    

3.Parakeet

这是一种用Python子集为科学计算设计的运行时编译器。它非常适合处理科学计算问题。
只支持一小部分Python和NumPy组合的数据类型
限制:
    支持的数据类型包括Python的数字、元组、列表和NumPy的数组。
    Parakeet会自动对数据类型执行向上转换,就是说,无论何时遇到两种不同类型的数据,都会被强制向上转换成统一类型。
    Parakeet里面不能捕捉和处理异常,这是因为Parakeet是用SSA结构展示程序的
    数组传播(array broadcasting,NumPy的特性)是通过对数组参数类型显式地映射操作实现的。
            这种实现方式的限制是它不能实现多维数组传播(比如8×2×3和7×2数组)。
    只实现了一小部分Python和NumPy的内置函数。
    列表综合表达式作为数组综合表达式处理。
使用: 
    在函数上使用一个装饰器,from parakeet import jit

内存泄漏:

1.guppy模块(linux专用)

from guppy import hpy
h = hpy()
heap = h.heap()                # 显示内存占用最多的类型
byrcs = h.heap().byrcs        # 稍微具体的信息

2.tracemalloc

python3.4后版本引入
示例:
    tracemalloc.start(25)
    snapshot = tracemalloc.take_snapshot()
    top_stats = snapshot.statistics('lineno')
    for stat in top_stats[:10]:
        print(stat)
方法: 
    tracemalloc.start(25)           # Store 25 frames
    tracemalloc.take_snapshot()     
    snapshot.statistics('lineno')
    snapshot2.compare_to(snapshot1, 'lineno')
    stat.traceback.format()
    tracemalloc.clear_traces()      # Clear traces of memory blocks allocated by Python.

3.gc模块

gc.enable(); gc.disable(); gc.isenabled()
    开启gc(默认情况下是开启的);关闭gc;判断gc是否开启
gc.collect(generation=None) 
    执行一次垃圾回收,不管gc是否处于开启状态都能使用。专门针对循环引用(正常的垃圾回收机制不适用)
    没参数进行完全回收
gc.set_threshold(t0, t1, t2); gc.get_threshold()
    设置垃圾回收阈值; 获得当前的垃圾回收阈值,gc.set_threshold(0)也有禁用gc的效果
gc.get_objects()
    返回所有被垃圾回收器(collector)管理的对象。这个函数非常基础!只要python解释器运行起来,就有大量的对象被collector管理,
    因此,该函数的调用比较耗时!
gc.get_referents(*obj)
    返回obj对象直接指向的对象
gc.get_referrers(*obj)
    返回所有直接指向obj的对象
gc.set_debug(flags)            
    进行检测,打印log      # gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_SAVEALL)

4.objgraph

调用了gc的这几个函数:gc.get_objects(), gc.get_referents(), gc.get_referers(),然后构造出对象之间的引用关系。
def count(typename)
    返回该类型对象的数目,其实就是通过gc.get_objects()拿到所用的对象,然后统计指定类型的数目。
def by_type(typename)
    返回该类型的对象列表。线上项目,可以用这个函数很方便找到一个单例对象
def show_most_common_types(limits = 10)
    打印实例最多的前N(limits)个对象,这个函数非常有用。该函数能发现可以用slots进行内存优化的对象
def show_growth()
    统计自上次调用以来增加得最多的对象,这个函数非常有利于发现潜在的内存泄露。
    函数内部调用了gc.collect(),因此即使有循环引用也不会对判断造成影响。
def show_backrefs()
    生产一张有关objs的引用图,看出对象为什么不释放,后面会利用这个API来查内存泄露。
    层数限制(max_depth)、宽度限制(too_many)、输出格式控制(filename output)、节点过滤(filter, extra_ignore)
def find_backref_chain(obj, predicate, max_depth=20, extra_ignore=()):
    找到一条指向obj对象的最短路径,且路径的头部节点需要满足predicate函数 (返回值为True)
    可以快捷、清晰指出对象的被引用的情况
def show_chain():
    将find_backref_chain 找到的路径画出来, 该函数事实上调用show_backrefs,只是排除了所有不在路径中的节点。

5.pyrasite

6.memory_profiler

安装:
pip install memory_profiler

使用:
from memory_profiler import profile
为函数添加装饰器@profile(precision=6)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39890410/article/details/122102789

智能推荐

Postgresql 数据库时区(timezone)设置,以及TIMESTAMPTZ和TIMESTAMP数据类型的选择-程序员宅基地

文章浏览阅读2.1w次,点赞12次,收藏18次。timestamp和timestamptz都占用8个字节,在存储时间时并没有本质的区别,都不携带时区信息。只是在insert保存数据和select给数据库客户端返回数据时处理方式不同。下边以具体示例解释这两种数据类型的差别,以及他们与数据库链接时区(session对应的时区)和postgresql数据库时区之间的关系。下边例子使用的数据库时区是Etc/UTC (GMT + 0),首先创建表,然后做相应操作:test_db=> CREATE TABLE test_table ( _timestamptz

模拟鼠标点击按钮的简单示例_bat脚本控制鼠标点击-程序员宅基地

文章浏览阅读7.2k次。原理 首先枚举到目标按钮所在程序的窗口,然后在该窗口内枚举控件获取控件的句柄,获取到按钮的句柄后可通过SendMessage或者PostMessage来发送消息模拟鼠标点击按钮等交互方式。但是因为枚举窗口和句柄都是使用WIN32 API,所以只能枚举到WIN32的控件,对于那些不是微软提供的控件则表示无能为力了。本示例简单地模拟一个往打字机里面写入数据,点击确认的方法。_bat脚本控制鼠标点击

筷云解读企业上云:为什么上云?选什么上云?_企业上云和用户上云啥意思-程序员宅基地

文章浏览阅读611次。近段时间,大家都在说企业上云,那么到底什么是企业上云?企业为什么要上云?应该怎么上呢?在新旧动能转换的关键时期,企业上云的确是可以驱动流程创新和业务创新,成为企业新的利润增长点。筷云作为国内知名的互联网生态体系构建者,以云服务为核心,赋能数字经济为使命,在助力企业上云方面有着丰富的经验。企业上云是什么?企业上云是指企业通过网络,将企业的基础设施、管理及业务部署到云端,利用网络便捷..._企业上云和用户上云啥意思

node、 node-sass 和sass-loader的版本对应问题_node-sass 版本-程序员宅基地

文章浏览阅读2.1k次。错误产生原因:node、 node-sass 和sass-loader的版本对应问题。_node-sass 版本

Java中的静态和非静态(有代码实例,超详细!)_java 静态-程序员宅基地

文章浏览阅读1.8k次,点赞10次,收藏39次。静态变量和方法是属于类的,而不属于类的实例或对象。它们可以通过类名直接访问,不需要创建对象。因此,静态成员常常用于描述与类本身有关的信息,比如常量、工具方法等。例如,Math类中的PI常量和abs()方法都是静态的。非静态变量和方法则是属于类的实例或对象的。它们必须依赖于对象的状态,才能进行相应的操作。因此,非静态成员常常用于描述类的实例状态,比如具有不同属性的学生或员工对象。例如,一个Person类中的name和age变量就是非静态的。_java 静态

关于tecplot动画的制作_tecplot动图-程序员宅基地

文章浏览阅读1.2w次。原文地址:关于tecplot动画的制作作者:Cherry参考文献一:http://hi.baidu.com/zhaoyj_111/blog/item/7939c318bb71e37cdab4bdbe.htmltecplot——画等高线和做动画的流程2008-10-10 11:22 Tecplot构筑结构网格有两种方式:point format和blockformat。_tecplot动图

随便推点

spring-security入门4---自定义登录成功和登录失败的行为_spring sso 自定义登录错误-程序员宅基地

文章浏览阅读1.6k次。项目源码地址https://github.com/nieandsun/security_spring sso 自定义登录错误

TypeError: an integer is required (got type is tuple)-程序员宅基地

文章浏览阅读7.6k次。TypeError: an integer is required (got type is tuple ),这个错误。从字面意思理解,需要获取一个整型数据,而原代码是元组。需要做的就是,定位到错误的具体那行,将元组改为整型就行。我这边的是img_tr = [transforms.RandomResizedCrop((int(args.image_size), int(args.image_size)), (args.min_scale, args.max_scale))]将 (int(args.i_an integer is required

100%的BAT招聘岗位都考的知识,你精通了吗?-程序员宅基地

文章浏览阅读176次。程序 = 数据结构 + 算法 ——图灵奖得主,计算机科学家N.Wirth(沃斯)作为程序员,我们做机器学习也好,做Python开发也好,Java开..._bat春招主要考什么

沁恒蓝牙芯片CH58x系列学习与应用_ch58x_bleinit-程序员宅基地

文章浏览阅读1.9k次,点赞6次,收藏30次。在前人的基础上补充一个沁恒CH85x系列蓝牙central例程的记录_ch58x_bleinit

python重复输入字符串a三次_8道Python基础面试练习题-程序员宅基地

文章浏览阅读1.4k次。1.26个字母大小写成对打印,例如:Aa,Bb......for i in range(26):print(chr(65+i)+chr(97+i))2.一个list包含10个数字,然后生成一个新的list,要求新的list里面的数都比之前的数多1list=[2,3,6,4,7,5,1,8,9,0]list1=[]for i in list:list1.append(i+1)print(list1)..._从键盘输入字符串a,字符串重复3次python

unordered_map的find和count函数使用总结_unordered_map find-程序员宅基地

文章浏览阅读1.5w次,点赞11次,收藏43次。一、find函数:如下程序所示,函数形式 哈希表变量名.find(要查找的值),返回值为迭代器在该数据结构所在位置 unordered_map<int,int> map; map[0]=1; if(map.find(0)!=map.end()) printf("这个map中含有键为1的键值对");二、count函数如下程序所示,函数形式 哈希表变量名.count(要查找的值),返回值为找到的个数 unordered_map<int,int> map; map[0]_unordered_map find

推荐文章

热门文章

相关标签