当我遇到一组奇怪的计时结果时,我正在搞乱一个小型的自定义数据对象,该对象必须是可散列的,可比的和快速的。该对象的某些比较(和哈希方法)只是委托给一个属性,所以我使用的是:
def __hash__(self):
return self.foo.__hash__()
但是,经过测试,我发现它hash(self.foo)
的速度明显更快。出于好奇,我测试__eq__
,__ne__
和其他神奇的比较,才发现
所有的 人跑得更快,如果我用含糖的形式(==
,!=
,<
等)。为什么是这样?我以为加糖形式必须在幕后进行相同的函数调用,但也许不是这样吗?
设置:控制所有比较的instance属性周围的薄包装器。
Python 3.3.4 (v3.3.4:7ff62415e426, Feb 10 2014, 18:13:51) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>>
>>> sugar_setup = '''\
... import datetime
... class Thin(object):
... def __init__(self, f):
... self._foo = f
... def __hash__(self):
... return hash(self._foo)
... def __eq__(self, other):
... return self._foo == other._foo
... def __ne__(self, other):
... return self._foo != other._foo
... def __lt__(self, other):
... return self._foo < other._foo
... def __gt__(self, other):
... return self._foo > other._foo
... '''
>>> explicit_setup = '''\
... import datetime
... class Thin(object):
... def __init__(self, f):
... self._foo = f
... def __hash__(self):
... return self._foo.__hash__()
... def __eq__(self, other):
... return self._foo.__eq__(other._foo)
... def __ne__(self, other):
... return self._foo.__ne__(other._foo)
... def __lt__(self, other):
... return self._foo.__lt__(other._foo)
... def __gt__(self, other):
... return self._foo.__gt__(other._foo)
... '''
我的自定义对象包装了datetime
,所以这就是我使用的内容,但不应有任何区别。是的,我正在测试中创建日期时间,因此那里显然存在一些相关的开销,但是从一项测试到另一项测试的开销是恒定的,因此不应有所作为。为了简洁起见,我省略了__ne__
和__gt__
测试,但是结果基本上与此处显示的相同。
>>> test_hash = '''\
... for i in range(1, 1000):
... hash(Thin(datetime.datetime.fromordinal(i)))
... '''
>>> test_eq = '''\
... for i in range(1, 1000):
... a = Thin(datetime.datetime.fromordinal(i))
... b = Thin(datetime.datetime.fromordinal(i+1))
... a == a # True
... a == b # False
... '''
>>> test_lt = '''\
... for i in range(1, 1000):
... a = Thin(datetime.datetime.fromordinal(i))
... b = Thin(datetime.datetime.fromordinal(i+1))
... a < b # True
... b < a # False
... '''
>>> min(timeit.repeat(test_hash, explicit_setup, number=1000, repeat=20))
1.0805227295846862
>>> min(timeit.repeat(test_hash, sugar_setup, number=1000, repeat=20))
1.0135617737162192
>>> min(timeit.repeat(test_eq, explicit_setup, number=1000, repeat=20))
2.349765956168767
>>> min(timeit.repeat(test_eq, sugar_setup, number=1000, repeat=20))
2.1486044757355103
>>> min(timeit.repeat(test_lt, explicit_setup, number=500, repeat=20))
1.156479287717275
>>> min(timeit.repeat(test_lt, sugar_setup, number=500, repeat=20))
1.0673696685109917
两个原因:
API查找仅查看 类型 。他们不看self.foo.__hash__
,他们寻找type(self.foo).__hash__
。少看一本字典。
C插槽查找比纯Python属性查找(将使用__getattribute__
)快。而是完全在C中绕过来查找方法对象(包括描述符绑定)__getattribute__
。
因此,您必须在type(self._foo).__hash__
本地缓存查找,即使这样,调用也不会像从C代码中那样快。如果速度非常宝贵,请坚持使用标准库功能。
另一个原因,以避免直接调用魔术方法是比较运营商做 更多的 不仅仅是通话一个魔术方法; 这些方法也反映了版本;对于x < y
,如果x.__lt__
未定义或x.__lt__(y)
返回NotImplemented
单例,y.__gt__(x)
则也请参考。
问题内容: 我最近一直在使用Python,而我发现有点奇怪的是,广泛使用了“魔术方法”,例如,使其长度可用,一个对象实现一个方法,然后在你写。 我只是想知道为什么对象不能简单地定义一个方法并直接将其作为对象的成员来调用,例如?我敢肯定,Python这么做的确有充分的理由,但是作为一个新手,我还没有弄清楚它们到底是什么。 问题答案: AFAIK在这方面很特殊,并且具有历史渊源。 这是FAQ中的报价:
所以我试图摆脱我主要方法中的两个神奇数字。我试着让它们成为静态字段,但我只是得到了一个不同的checkstyle错误。我正在寻找一种方法,使我的主要方法完全符合checkstyle。 这些是我得到的检查风格错误: '2000'是个神奇的数字 “262”是一个神奇的数字 以下是我将其设置为静态字段时出现的checkstyle错误: 名称“Twoou”必须与模式“^[A-Z][A-Z0-9]*([A-
问题内容: 当我发现抽象类和接口之间的区别时,这个问题就浮现在脑海中。在这篇文章中,我知道接口很慢,因为它们需要额外的间接访问。但是我没有得到接口而不是抽象类或具体类所需的间接类型,请对此进行澄清。提前致谢 问题答案: 关于性能的神话很多,有些可能在几年前是正确的,而在没有JIT的VM上可能仍然正确。 Android文档(请记住,Android没有JVM,而是Dalvik VM)曾经说过,在接口上
Python 中有很多 __ 开始和结尾的特殊方法,它们多是所有类型都拥有的,通过实现这些 特殊方法可以实现很多有意思的功能,比如最常使用的 __str__、__repr__ 和 __unicode__ 这三个就可以用于输出对象的字符串结果。 GitHub 上有篇翻译不错: 翻译 原文 魔术方法与语法糖 Lisp 的语法极其简单,主要语法“S 表达式”非常接近于数学中的波兰表达式,写法如下: (+
本文向大家介绍php 魔术方法详解,包括了php 魔术方法详解的使用技巧和注意事项,需要的朋友参考一下 从PHP 5以后的版本,PHP中的类就可以使用魔术方法了。其规定以两个下划线(__)开头的方法都保留为魔术方法,所以建议大家函数名最好不用__开头,除非是为了重载已有的魔术方法。PHP 将所有以 _ _(两个下划线)开头的类方法保留为魔术方法。 __toString() 和__invoke()
问题内容: 除非我完全误解,否则and 方法应该允许→ 和的重载。 例如,以下语句应调用该方法: 并且以下应使用该方法: 这在我的代码中不起作用,并且可以通过以下简单示例重现: 这只会导致: 在那儿放一些电话表明它根本没打。 现在,我只是说了一下要解决的问题,并在目前需要的地方手动使用它,但这不是很动态,并且需要知道“重载”代码实际上没有被调用,除非专门调用。我想知道这是否不是应该以我所理解的方式
问题内容: 在Python中的类上定义方法时,它看起来像这样: 但是在某些其他语言(例如C#)中,你可以使用“ this”关键字来引用该方法所绑定的对象,而无需在方法原型中将其声明为参数。 这是Python中的一种故意的语言设计决策,还是有一些实现细节需要传递“ self”作为参数? 问题答案: 我喜欢引用Peters的。“显式比隐式好。” 在Java和.可以推断出’ ‘,除非你拥有无法推断的变量
问题内容: 在用记事本++和sublime进行了许多幸福的编码之后,建议我尝试使用PHP IDE。我正在尝试phpStorm,看起来不错。代码完成和文档编写是一个很棒的功能,但是当使用魔术方法时,对我来说却行不通。 是否有解决办法使phpStorm了解魔术方法的状况? 我们的情况是这样的: 神奇的callStatic方法使我们能够通过1个或多个组成函数调用的参数来获取对象的集合。 我看到在这些情况