在这里,我们将给大家分享关于Pythontimeit令人惊讶的结果:Counter的知识,让您更了解vsdefaultdict的本质,同时也会涉及到如何更有效地(转)Python3collection
在这里,我们将给大家分享关于Python timeit令人惊讶的结果:Counter的知识,让您更了解vs defaultdict的本质,同时也会涉及到如何更有效地(转)Python 3 collections.defaultdict() 与 dict的使用和区别、Arrays.asList()vs Collections.singletonList()、COUNT(*)vs.COUNT(1)vs.COUNT(pk):哪个更好?、Django ORM-objects.filter()vs.objects.all()filter()-哪个是首选?的内容。
本文目录一览:- Python timeit令人惊讶的结果:Counter()vs defaultdict()vs dict()(python time perf_counter)
- (转)Python 3 collections.defaultdict() 与 dict的使用和区别
- Arrays.asList()vs Collections.singletonList()
- COUNT(*)vs.COUNT(1)vs.COUNT(pk):哪个更好?
- Django ORM-objects.filter()vs.objects.all()filter()-哪个是首选?
Python timeit令人惊讶的结果:Counter()vs defaultdict()vs dict()(python time perf_counter)
我在timeit上获得了非常令人惊讶的结果,有人可以告诉我我做错了什么吗?我正在使用Python 2.7。
这是文件speedtest_init.py的内容:
import randomto_count = [random.randint(0, 100) for r in range(60)]
这些是speedtest.py的内容:
__author__ = ''BlueTrin''import timeitdef test_init1(): print(timeit.timeit(''import speedtest_init''))def test_counter1(): s = """\ d = defaultdict(int); for i in speedtest_init.to_count: d[i] += 1 """ print(timeit.timeit(s, ''from collections import defaultdict; import speedtest_init;''))def test_counter2(): print(timeit.timeit(''d = Counter(speedtest_init.to_count);'', ''from collections import Counter; import speedtest_init;''))if __name__ == "__main__": test_init1() test_counter1() test_counter2()
控制台输出为:
C:\Python27\python.exe C:/Dev/codility/chlorum2014/speedtest.py2.7150196293165.709044450391.2953839048Process finished with exit code 0
我认为默认情况下timeit()运行代码的1000000倍,因此我需要将时间除以1000000,但是令人惊讶的是Counter的速度比defaultdict()慢。
那是预期的吗?
编辑:
同样,使用dict比defaultdict(int)更快:
def test_counter3(): s = """\ d = {}; for i in speedtest_init.to_count: if i not in d: d[i] = 1 else: d[i] += 1 """ print(timeit.timeit(stmt=s, setup=''from collections import defaultdict; import speedtest_init;'')
最后一个版本比defaultdict(int)快,这意味着除非您更关心可读性,否则应使用dict()而不是defaultdict()。
答案1
小编典典是的,这是预期的;该Counter()
构造
的用途Counter.update()
,它使用self.get()
加载初始值,而不是依靠__missing__
。
此外,defaultdict
__missing__
工厂完全由C代码处理,尤其是在使用其他类似的类型int()
(本身由C实现)时。Counter
源是纯Python,因此该Counter.__missing__
方法需要Python框架才能执行。
由于dict.get()
仍在C中处理,因此对于,构造器方法是更快的方法Counter()
,只要您使用相同的技巧Counter.update()
和别名self.get
作为本地优先项即可:
>>> import timeit>>> import random>>> import sys>>> sys.version_infosys.version_info(major=2, minor=7, micro=9, releaselevel=''final'', serial=0)>>> to_count = [random.randint(0, 100) for r in range(60)]>>> timeit.timeit(''for i in to_count: c[i] += 1'',... ''from collections import Counter; from __main__ import to_count; c = Counter()'',... number=10000)0.2510359287261963>>> timeit.timeit(''for i in to_count: c[i] = c_get(i, 0) + 1'',... ''from collections import Counter; from __main__ import to_count; c = Counter(); c_get = c.get'',... number=10000)0.20978617668151855
两者defaultdict
并Counter
为他们的功能,而不是他们的表现内置有用的类; 不依赖__missing__
钩子可以更快:
>>> timeit.timeit(''for i in to_count: d[i] = d_get(i, 0) + 1'',... ''from __main__ import to_count; d = {}; d_get = d.get'',... number=10000)0.11437392234802246
这是使用别名dict.get()
方法以实现最大速度的常规词典。但是随后,您还必须重新实现Counter
或Counter.most_common()
方法的bag行为。该defaultdict
用例去的方式数不胜数。
在Python
3.2中,Counter()
通过添加一个处理这种情况的C库来更新速度。参见问题10667。在Python
3.4上进行测试,Counter()
构造函数现在击败了别名dict.get
情况:
>>> timeit.timeit(''Counter(to_count)'',... ''from collections import Counter; from __main__ import to_count'',... number=100000)0.8332311600097455>>> timeit.timeit(''for i in to_count: d[i] = d_get(i, 0) + 1'',... ''from __main__ import to_count; d = {}; d_get = d.get'',... number=100000)0.961191965994658>>> import sys>>> sys.version_infosys.version_info(major=3, minor=4, micro=2, releaselevel=''final'', serial=0)
(注意:要获得有意义的计时结果,迭代次数从10k增加到100k;因此,如果将上述dict.get()
情况与上述情况进行比较,则需要在计时中乘以10倍,即1.144秒)。
(转)Python 3 collections.defaultdict() 与 dict的使用和区别
原文:https://www.cnblogs.com/herbert/archive/2013/01/09/2852843.html
在Python里面有一个模块collections,解释是数据类型容器模块。这里面有一个collections.defaultdict()经常被用到。主要说说这个东西。
综述:
这里的defaultdict(function_factory)构建的是一个类似dictionary的对象,其中keys的值,自行确定赋值,但是values的类型,是function_factory的类实例,而且具有默认值。比如default(int)则创建一个类似dictionary对象,里面任何的values都是int的实例,而且就算是一个不存在的key, d[key] 也有一个默认值,这个默认值是int()的默认值0.
defaultdict
dict subclass that calls a factory function to supply missing values。
这是一个简短的解释
defaultdict属于内建函数dict的一个子类,调用工厂函数提供缺失的值。
比较晕,什么是工厂函数:
来自python 核心编程的解释
Python 2.2 统一了类型和类, 所有的内建类型现在也都是类, 在这基础之上, 原来的
所谓内建转换函数象int(), type(), list() 等等, 现在都成了工厂函数。 也就是说虽然他
们看上去有点象函数, 实质上他们是类。当你调用它们时, 实际上是生成了该类型的一个实
例, 就象工厂生产货物一样。
下面这些大家熟悉的工厂函数在老的Python 版里被称为内建函数:
int(), long(), float(), complex()
str(), unicode(), basestring()
list(), tuple()
type()
以前没有工厂函数的其他类型,现在也都有了工厂函数。除此之外,那些支持新风格的类
的全新的数据类型,也添加了相应的工厂函数。下面列出了这些工厂函数:
dict()
bool()
set(), frozenset()
object()
classmethod()
staticmethod()
super()
property()
file()
再看看它的使用:

import collections
s = [(''yellow'', 1), (''blue'', 2), (''yellow'', 3), (''blue'', 4), (''red'', 1)]
d = collections.defaultdict(list)
for k, v in s:
d[k].append(v)
list(d.items())

这里就开始有点明白了,原来defaultdict可以接受一个内建函数list作为参数。其实呢,list()本身是内建函数,但是再经过更新后,python里面所有东西都是对象,所以list改编成了类,引入list的时候产生一个类的实例。
还是不太明白,再看defaultdict的help解释
- class collections.defaultdict([ default_factory[, ...]])
-
Returns a new dictionary-like object. defaultdict is a subclass of the built-in dict class. It overrides one method and adds one writable instance variable. The remaining functionality is the same as for the dict class and is not documented here.
首先说了,collections.defaultdict会返回一个类似dictionary的对象,注意是类似的对象,不是完全一样的对象。这个defaultdict和dict类,几乎是一样的,除了它重载了一个方法和增加了一个可写的实例变量。(可写的实例变量,我还是没明白)
The first argument provides the initial value for the default_factory attribute; it defaults to None. All remaining arguments are treated the same as if they were passed to the dict constructor, including keyword arguments.
defaultdict objects support the following method in addition to the standard dict operations:
- __missing__( key)
-
If the default_factory attribute is None, this raises a KeyError exception with the key as argument.
If default_factory is not None, it is called without arguments to provide a default value for the given key, this value is inserted in the dictionary for the key, and returned.
-
主要关注这个话,如果default_factory不是None, 这个default_factory将以一个无参数的形式被调用,提供一个默认值给___missing__方法的key。 这个默认值将作为key插入到数据字典里,然后返回。
-
十分晕。有扯出了个__missing__方法,这个__missing__方法是collections.defaultdict()的内建方法。
If calling default_factory raises an exception this exception is propagated unchanged.
This method is called by the __getitem__() method of the dict class when the requested key is not found; whatever it returns or raises is then returned or raised by __getitem__().
Note that __missing__() is not called for any operations besides __getitem__(). This means that get() will, like normal dictionaries, return None as a default rather than using default_factory.
defaultdict objects support the following instance variable:
- default_factory
-
This attribute is used by the __missing__() method; it is initialized from the first argument to the constructor, if present, or to None, if absent.
看样子这个文档是难以看懂了。直接看示例:

import collections
s = [(''yellow'', 1), (''blue'', 2), (''yellow'', 3), (''blue'', 4), (''red'', 1)]
# defaultdict
d = collections.defaultdict(list)
for k, v in s:
d[k].append(v)
# Use dict and setdefault
g = {}
for k, v in s:
g.setdefault(k, []).append(v)
# Use dict
e = {}
for k, v in s:
e[k] = v
##list(d.items())
##list(g.items())
##list(e.items())

看看结果

list(d.items())
[(''blue'', [2, 4]), (''red'', [1]), (''yellow'', [1, 3])]
>>> list(g.items())
[(''blue'', [2, 4]), (''red'', [1]), (''yellow'', [1, 3])]
>>> list(e.items())
[(''blue'', 4), (''red'', 1), (''yellow'', 3)]
>>> d
defaultdict(<class ''list''>, {''blue'': [2, 4], ''red'': [1], ''yellow'': [1, 3]})
>>> g
{''blue'': [2, 4], ''red'': [1], ''yellow'': [1, 3]}
>>> e
{''blue'': 4, ''red'': 1, ''yellow'': 3}
>>> d.items()
dict_items([(''blue'', [2, 4]), (''red'', [1]), (''yellow'', [1, 3])])
>>> d["blue"]
[2, 4]
>>> d.keys()
dict_keys([''blue'', ''red'', ''yellow''])
>>> d.default_factory
<class ''list''>
>>> d.values()
dict_values([[2, 4], [1], [1, 3]])

可以看出
collections.defaultdict(list)使用起来效果和运用dict.setdefault()比较相似
python help上也这么说了
When each key is encountered for the first time, it is not already in the mapping; so an entry is automatically created using the default_factory function which returns an empty list. The list.append() operation then attaches the value to the new list. When keys are encountered again, the look-up proceeds normally (returning the list for that key) and the list.append() operation adds another value to the list. This technique is simpler and faster than an equivalent technique using dict.setdefault():
说这种方法会和dict.setdefault()等价,但是要更快。
有必要看看dict.setdefault()
- setdefault( key[, default])
-
If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.
如果这个key已经在dictionary里面存着,返回value.如果key不存在,插入key和一个default value,返回Default. 默认的defaults是None.
但是这里要注意的是defaultdict是和dict.setdefault等价,和下面那个直接赋值是有区别的。从结果里面就可以看到,直接赋值会覆盖。
从最后的d.values还有d[“blue”]来看,后面的使用其实是和dict的用法一样的,唯一不同的就是初始化的问题。defaultdict可以利用工厂函数,给初始keyi带来一个默认值。
这个默认值也许是空的list[] defaultdict(list), 也许是0, defaultdict(int).
再看看下面的这个例子。
defaultdict(int) 这里的d其实是生成了一个默认为0的带key的数据字典。你可以想象成 d[key] = int default (int工厂函数的默认值为0)
d[k]所以可以直接读取 d[“m”] += 1 就是d[“m”] 就是默认值 0+1 = 1
后面的道理就一样了。

>>> s = ''mississippi''
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> list(d.items())
[(''i'', 4), (''p'', 2), (''s'', 4), (''m'', 1)]

Arrays.asList()vs Collections.singletonList()
Collections.singletonList(something)
是不可变的,
对Collections.singletonList(something)
返回的列表所做的任何更改将导致UnsupportedOperationException
。
Arrays.asList(something)
允许Arrays.asList(something)
更改 。
此外,由Collections.singletonList(something)
返回的List的容量将始终为1,
而Arrays.asList(something)
的容量将为已支持数组的大小。
/**
* Returns an immutable list containing only the specified object.
* The returned list is serializable.
*
* @param <T> the class of the objects in the list
* @param o the sole object to be stored in the returned list.
* @return an immutable list containing only the specified object.
* @since 1.3
*/
public static <T> List<T> singletonList(T o) {
return new SingletonList<>(o);
}
/**
* @serial include
*/
private static class SingletonList<E>
extends AbstractList<E>
implements RandomAccess, Serializable {
private static final long serialVersionUID = 3093736618740652951L;
private final E element;
SingletonList(E obj) {element = obj;}
public Iterator<E> iterator() {
return singletonIterator(element);
}
public int size() {return 1;}
public boolean contains(Object obj) {return eq(obj, element);}
public E get(int index) {
if (index != 0)
throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
return element;
}
// Override default methods for Collection
@Override
public void forEach(Consumer<? super E> action) {
action.accept(element);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
throw new UnsupportedOperationException();
}
@Override
public void sort(Comparator<? super E> c) {
}
@Override
public Spliterator<E> spliterator() {
return singletonSpliterator(element);
}
}
package com.ysyc.invoicecertify.util.mockservice;
import java.util.Arrays;
import java.util.List;
/**
*
* 本类演示了Arrays类中的asList方法
* 通过四个段落来演示,体现出了该方法的相关特性.
*
* (1) 该方法对于基本数据类型的数组支持并不好,当数组是基本数据类型时不建议使用
* (2) 当使用asList()方法时,数组就和列表链接在一起了.
* 当更新其中之一时,另一个将自动获得更新。
* 注意:仅仅针对对象数组类型,基本数据类型数组不具备该特性
* (3) asList得到的数组是的没有add和remove方法的
*
* 通过查看Arrays类的源码可以知道,asList返回的List是Array中的实现的
* 内部类,而该类并没有定义add和remove方法.另外,为什么修改其中一个,另一个也自动
* 获得更新了,因为asList获得List实际引用的就是数组
*/
public class AsListTest {
public static void main(String[] args) {
/* 段落一:基本数据类型使用asList中的问题 */
/* 说明:虽然在JDK1.6中能够将基本数据类型的数组转换成List,但还是有个缺陷 */
int[] a_int = { 1, 2, 3, 4 };
/* 预期输出应该是1,2,3,4,但实际上输出的仅仅是一个引用, 这里它把a_int当成了一个元素 */
List a_int_List = Arrays.asList(a_int);
foreach(a_int_List);
/* 为此我们需要这样遍历其中元素 */
foreachForBase(a_int_List);
System.out.println("1 END 2 START");
/* 段落二:对象类型的数组使用asList,是我们预期的 */
Integer[] a_Integer = new Integer[] { 1, 2, 3, 4 };
List a_Integer_List = Arrays.asList(a_Integer);
foreach(a_Integer_List);
System.out.println("2 END 3 START");
/* 段落三:当更新数组或者asList之后的List,另一个将自动获得更新 */
a_Integer_List.set(0, 0);
foreach(a_Integer_List);
foreach(a_Integer);
System.out.println("3 END 4 START");
a_Integer[0] = 5;
foreach(a_Integer_List);
foreach(a_Integer);
/* 段落四:对基本类型数组,通过asList之后的List修改对应的值后,在运行时会报出异常
* 但是基本类型数组对应的List是会发生变化的,这是毫无疑问的
*/
a_int_List.set(0, 0);
foreach(a_int_List);
foreach(a_int);
System.out.println("4 END 5 START");
a_int[0] = 5;
foreachForBase(a_int_List);
foreach(a_int);
}
/* 打印方法 */
private static void foreach(List list) {
for (Object object : list) {
System.out.print(object + " ");
}
System.out.println();
}
private static void foreachForBase(List a_int_List) {
int[] _a_int = (int[]) a_int_List.get(0);
foreach(_a_int);
}
private static void foreach(int[] a_int) {
for (int i : a_int) {
System.out.print(i + " ");
}
System.out.println();
}
private static void foreach(Integer[] _a_Integer) {
for (int i : _a_Integer) {
System.out.print(i + " ");
}
System.out.println();
}
}
console:
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer
at java.util.Arrays$ArrayList.set(Arrays.java:3847)
at com.ysyc.invoicecertify.util.mockservice.AsListTest.main(AsListTest.java:56)
[I@762efe5d
1 2 3 4
1 END 2 START
1 2 3 4
2 END 3 START
0 2 3 4
0 2 3 4
3 END 4 START
5 2 3 4
5 2 3 4
Disconnected from the target VM, address: ''127.0.0.1:54490'', transport: ''socket''
Process finished with exit code 1
COUNT(*)vs.COUNT(1)vs.COUNT(pk):哪个更好?
我经常会发现以下三种变体:
SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;
据我所知,它们都做相同的事情,我发现自己在代码库中使用了这三个。但是,我不喜欢用不同的方式做同样的事情。我应该坚持哪一个?他们中的任何一个都比其他两个更好吗?
Django ORM-objects.filter()vs.objects.all()filter()-哪个是首选?
我经常看到类似的构造
MyModel.objects.all().filter(...)
这将返回默认Mananger的QuerySet。起初all()
似乎很多余,因为
MyMode.objects.filter(...)
提供相同的结果。
但是,由于Django文档中的以下两个语句,这似乎仅对默认管理器是安全的:
摘自“添加额外的管理器方法”一章
自定义Manager方法可以返回您想要的任何内容。它不必返回QuerySet。
all()
manager方法的定义:
all()返回当前QuerySet(或QuerySet子类)的副本。在您可能想要传入模型管理器或QuerySet并对结果进行进一步过滤的情况下,这很有用。在任一对象上调用all()之后,您肯定会有一个QuerySet可以使用。
对我来说,这似乎有点矛盾。一方面,Django提供了让管理器方法返回首选对象类型的自由,另一方面,它需要该all()
方法的QuerySet
。我知道每个管理器都有一个get_queryset
由调用的方法all()
。但是谁阻止我all()
在我的自定义经理中压倒一切呢?尽管我同意这样做是不好的设计。
-
据我所知,该
all()
方法不能保证返回QuerySet。究竟MyModel.objects
返回什么?此语句调用all()
吗?或`get_queryset()? -
您喜欢
MyModel.objects.filter(...)
还是MyModel.objects.all().filter(...)
。如果是这样,为什么? -
您有没有遇到过会以不希望的方式弄乱那些方法的笨拙的经理?
今天关于Python timeit令人惊讶的结果:Counter和vs defaultdict的介绍到此结束,谢谢您的阅读,有关(转)Python 3 collections.defaultdict() 与 dict的使用和区别、Arrays.asList()vs Collections.singletonList()、COUNT(*)vs.COUNT(1)vs.COUNT(pk):哪个更好?、Django ORM-objects.filter()vs.objects.all()filter()-哪个是首选?等更多相关知识的信息可以在本站进行查询。
本文标签: