因为字典是通过键来索引的,关联到相对的值,理论上他的查询复杂度是O(1)。
创新互联公司专注于曲水网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供曲水营销型网站建设,曲水网站制作、曲水网页设计、曲水网站官网定制、小程序制作服务,打造曲水网络公司原创品牌,更为您提供曲水网站排名全网营销落地服务。
哈希表(也叫散列表),根据关键值对(Key-value)而直接进行访问的数据结构。它通过把key和value映射到表中一个位置来访问记录,这种查询速度非常快,更新也快。而这个映射函数叫做哈希函数,存放值的数组叫做哈希表。 哈希函数的实现方式决定了哈希表的搜索效率。
1. PIL.Image.open
代码在这里:Pillow/Image.py at 3.1.x · python-pillow/Pillow · GitHub
open() 函数打开图像,但并不读入,直到有操作发生。
具体的读取操作是在 ImageFile.py 写的。大体流程是先检测文件类型,整块地读入文件内容,然后调用解码器解码,做了很多优化,效率应该还是很高的。
2. scipy.ndimage.imread
代码在这里:scipy/io.py at v0.17.1 · scipy/scipy · GitHub
imread 调用 scipy.misc.pilutil.imread。从名字就能看出来其实调用的还是 Pillow。
根据 pilutil 代码:scipy/pilutil.py at v0.17.1 · scipy/scipy · GitHub
确实是调用 pil.image.open(),然后返回一个 fromimage()。
3. scipy.misc.imread
misc 的 __init__.py 在这里:scipy/__init__.py at v0.17.1 · scipy/scipy · GitHub
调用的还是 pilutil 中的 imread
相关代码如下
try:
from .pilutil import *
from . import pilutil
__all__ += pilutil.__all__
del pilutil
except ImportError:
pass
也算是学了一招,从 pilutil 导入其所有函数添加到当前空间,然后又删除了 pilutil 消除影响。
4. skimage.io.imread
代码在这里:scikit-image/_io.py at master · scikit-image/scikit-image · GitHub
是通过插件 plugin 来读入不同的文件,而且会试用几个不同的 plugins 来找到合适的。
使用 call_plugin 来调用,代码在这里:scikit-image/manage_plugins.py at master · scikit-image/scikit-image · GitHub
可以根据如下代码查看插件调用的优先级
# For each plugin type, default to the first available plugin as defined by
# the following preferences.
preferred_plugins = {
# Default plugins for all types (overridden by specific types below).
'all': ['pil', 'matplotlib', 'qt', 'freeimage'],
'imshow': ['matplotlib'],
'imshow_collection': ['matplotlib']
}
plugins 的源代码在这里:scikit-image/skimage/io/_plugins at master · scikit-image/scikit-image · GitHub。可以看到 pil 的 imread,是用 open 打开图像之后,再转换成 ndarray。
5. cv2.imread
这里是调用的 CV::imread(),代码在这里:opencv/loadsave.cpp at master · opencv/opencv · GitHub。一般来说 C\C++ 的实现,应该比 python 速度快一点。
6. matplotlib.image.imread
matplotlib 的文档里面说,matplotlib 原生只可以读取 PNG 文件,有 PIL 的时候,可以读取其他类型的文件。如果使用 URL 打开在线图像文件,需要符合 PIL 的文档要求。
matplotlib.image.imread 的代码在这里:matplotlib/image.py at master · matplotlib/matplotlib · GitHub。matplotlib 的原生 PNG 读取和写入,是用 C 实现的,代码在这里:matplotlib/_png.cpp at master · matplotlib/matplotlib · GitHub。
matplotlib 是先用 pil 的 open 打开图像,如果格式是 png,就用原生方法打开。相关代码如下:
handlers = {'png': _png.read_png, }
if format is None:
if cbook.is_string_like(fname):
parsed = urlparse(fname)
# If the string is a URL, assume png
if len(parsed.scheme) 1:
ext = 'png'
else:
basename, ext = os.path.splitext(fname)
ext = ext.lower()[1:]
elif hasattr(fname, 'name'):
basename, ext = os.path.splitext(fname.name)
ext = ext.lower()[1:]
else:
ext = 'png'
else:
ext = format
if ext not in handlers:
im = pilread(fname)
if im is None:
raise ValueError('Only know how to handle extensions: %s; '
'with Pillow installed matplotlib can handle '
'more images' % list(six.iterkeys(handlers)))
return im
声明的处理器只有 png。如果是 png 文件,调用 _png.read_png。如果不是 png 直接使用 pilread(就是用 pil 的 Image.open 然后 pil_to_array)。
matplotlib 的源码确实比较复杂,一大部分主体是用 C 写的,改动很激进,功能更新猛烈。
super()函数的用处是调用当前类的父类函数。在要调用父类的函数之外,还需要加一点别的操作的时候,特别有用。
例:
结果是:
上面是单继承的例子,用super()而不是直接用父类的名字去调用父类函数的好处是不用管父类的名字。即使父类改名了,super()的调用依然有效。
多重继承的时候需要根据MRO来决定调用顺序。详见官方文档:
Python中有许多内置函数,不像print、len那么广为人知,但它们的功能却异常强大,用好了可以大大提高代码效率,同时提升代码的简洁度,增强可阅读性
Counter
collections在python官方文档中的解释是High-performance container datatypes,直接的中文翻译解释高性能容量数据类型。这个模块实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择。在python3.10.1中它总共包含以下几种数据类型:
容器名简介
namedtuple() 创建命名元组子类的工厂函数
deque 类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
ChainMap 类似字典(dict)的容器类,将多个映射集合到一个视图里面
Counter 字典的子类,提供了可哈希对象的计数功能
OrderedDict 字典的子类,保存了他们被添加的顺序
defaultdict 字典的子类,提供了一个工厂函数,为字典查询提供一个默认值
UserDict 封装了字典对象,简化了字典子类化
UserList 封装了列表对象,简化了列表子类化
UserString 封装了字符串对象,简化了字符串子类化
其中Counter中文意思是计数器,也就是我们常用于统计的一种数据类型,在使用Counter之后可以让我们的代码更加简单易读。Counter类继承dict类,所以它能使用dict类里面的方法
举例
#统计词频
fruits = ['apple', 'peach', 'apple', 'lemon', 'peach', 'peach']
result = {}
for fruit in fruits:
if not result.get(fruit):
result[fruit] = 1
else:
result[fruit] += 1
print(result)
#{'apple': 2, 'peach': 3, 'lemon': 1}下面我们看用Counter怎么实现:
from collections import Counter
fruits = ['apple', 'peach', 'apple', 'lemon', 'peach', 'peach']
c = Counter(fruits)
print(dict(c))
#{'apple': 2, 'peach': 3, 'lemon': 1}显然代码更加简单了,也更容易阅读和维护了。
elements()
返回一个迭代器,其中每个元素将重复出现计数值所指定次。元素会按首次出现的顺序返回。如果一个元素的计数值小于1,elements()将会忽略它。
c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']most_common([n])
返回一个列表,其中包含n个最常见的元素及出现次数,按常见程度由高到低排序。如果n被省略或为None,most_common()将返回计数器中的所有元素。计数值相等的元素按首次出现的顺序排序:
Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]这两个方法是Counter中最常用的方法,其他方法可以参考 python3.10.1官方文档
实战
Leetcode 1002.查找共用字符
给你一个字符串数组words,请你找出所有在words的每个字符串中都出现的共用字符(包括重复字符),并以数组形式返回。你可以按任意顺序返回答案。
输入:words = ["bella", "label", "roller"]
输出:["e", "l", "l"]
输入:words = ["cool", "lock", "cook"]
输出:["c", "o"]看到统计字符,典型的可以用Counter完美解决。这道题是找出字符串列表里面每个元素都包含的字符,首先可以用Counter计算出每个元素每个字符出现的次数,依次取交集最后得出所有元素共同存在的字符,然后利用elements输出共用字符出现的次数
class Solution:
def commonChars(self, words: List[str]) - List[str]:
from collections import Counter
ans = Counter(words[0])
for i in words[1:]:
ans = Counter(i)
return list(ans.elements())提交一下,发现83个测试用例耗时48ms,速度还是不错的
sorted
在处理数据过程中,我们经常会用到排序操作,比如将列表、字典、元组里面的元素正/倒排序。这时候就需要用到sorted(),它可以对任何可迭代对象进行排序,并返回列表
对列表升序操作:
a = sorted([2, 4, 3, 7, 1, 9])
print(a)
# 输出:[1, 2, 3, 4, 7, 9]对元组倒序操作:
sorted((4,1,9,6),reverse=True)
print(a)
# 输出:[9, 6, 4, 1]使用参数:key,根据自定义规则,按字符串长度来排序:
fruits = ['apple', 'watermelon', 'pear', 'banana']
a = sorted(fruits, key = lambda x : len(x))
print(a)
# 输出:['pear', 'apple', 'banana', 'watermelon']all
all() 函数用于判断给定的可迭代参数iterable中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。元素除了是 0、空、None、False外都算True。注意:空元组、空列表返回值为True。
all(['a', 'b', 'c', 'd']) # 列表list,元素都不为空或0
True
all(['a', 'b', '', 'd']) # 列表list,存在一个为空的元素
False
all([0, 1,2, 3]) # 列表list,存在一个为0的元素
False
all(('a', 'b', 'c', 'd')) # 元组tuple,元素都不为空或0
True
all(('a', 'b', '', 'd')) # 元组tuple,存在一个为空的元素
False
all((0, 1, 2, 3)) # 元组tuple,存在一个为0的元素
False
all([]) # 空列表
True
all(()) # 空元组
Trueany函数正好和all函数相反:判断一个tuple或者list是否全为空,0,False。如果全为空,0,False,则返回False;如果不全为空,则返回True。
F-strings
在python3.6.2版本中,PEP 498提出一种新型字符串格式化机制,被称为 “字符串插值” 或者更常见的一种称呼是F-strings,F-strings提供了一种明确且方便的方式将python表达式嵌入到字符串中来进行格式化:
s1='Hello'
s2='World'
print(f'{s1} {s2}!')
# Hello World!在F-strings中我们也可以执行函数:
def power(x):
return x*x
x=4
print(f'{x} * {x} = {power(x)}')
# 4 * 4 = 16而且F-strings的运行速度很快,比传统的%-string和str.format()这两种格式化方法都快得多,书写起来也更加简单。
本文主要讲解了python几种冷门但好用的函数,更多内容以后会陆陆续续更新~
pairplot函数。7在python中快速浏览数据集调用pairplot函数,此函数使用散点图和直方图,还可以在非对角线上绘制回归图,在对角线上绘制核密度估计图。
1.把range全部换成xrange
2.生成器,如 list=(item for item in fp)
3.利用psyco库,提高函数和类的运行效率。
4.字符串拼接:尽量少用“+”的方式,而采用''.join ,还有"%s"%i这样赋值的手段
5.函数的开销很大。尽量把循环放在函数内进行。而不要让每次迭代都调用函数。
6.“前提工作”先做好,比如该赋值,该拼接的,然后再引入到函数中,或者进行下面的循环。
7.尽量使用内置方法,因为内置的是C写的,效率肯定高很多
8.每当要对序列中的内容进行循环处理时,就应当尝试用列表解析来代替它,如:[i for i in xrang(10) if i%2==0]
9.学会使用itertools模块。当python中添加了迭代器后,就为常见模式提供了一个新的模块,因为它是以C语言编写,所以提供了最高效的迭代器。
--多记录一些。列表,字符串,字典,xrange,类文件对象,这些都是可迭代对象,换句话说,都可以直接用在for循环中进行迭代,如for item in open('1.txt')
--直接使用速度会快。另外,我对比了itertools里工具和xrange,比如都循环100000次打印数字,使用islice(count(),100000)均要比xrange(100000)快
--而xrange还要比range快。
10.用列表解析取代for循环。列表解析的效率等于或高于map。
11.垃圾回收机制,会对列表的操作有重大影响,如列表的append,或者列表解析。import gc,然后在数据载入模块前gc.disable(),结束后再gc.enable()。