[英]iter() not working with datetime.now()
Python 3.6.1中的一个简单片段:
import datetime
j = iter(datetime.datetime.now, None)
next(j)
收益:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
而不是使用每个next()
打印出经典的now()
行为。
我已经看到类似的代码在Python 3.3中工作,我在版本3.6.1中遗漏了什么或者有什么变化?
这绝对是Python 3.6.0b1中引入的错误。 iter()
实现最近切换到使用_PyObject_FastCall()
(一个优化,参见问题27128 ),它必须是这个打破这个的调用。
同样的问题与Argument Clinic解析支持的其他C classmethod
方法方法有关:
>>> from asyncio import Task
>>> Task.all_tasks()
set()
>>> next(iter(Task.all_tasks, None))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
如果需要解决方法,请将callable包装在functools.partial()
对象中:
from functools import partial
j = iter(partial(datetime.datetime.now), None)
我提交了问题30524 - iter(classmethod,sentinel)为Argument Clinic类方法打破了吗? 与Python项目。 对此的修复已落地并且是3.6.2rc1的一部分。
我假设你使用的是CPython而不是另一个Python实现。 我可以用CPython 3.6.1重现这个问题(我没有PyPy,Jython,IronPython,......所以我无法检查这些)。
在这种情况下,违规者用_PyObject_CallNoArg
替换PyObject_Call
,其中C等价于callable_iterator.__next__
(你的对象是一个callable_iterator
)方法。
PyObject_Call
确实返回一个新的datetime.datetime
实例,而_PyObject_CallNoArg
返回NULL
(这大致相当于Python中的一个异常)。
通过CPython源代码挖掘一下:
_PyObject_CallNoArg
只是_PyObject_CallNoArg
的一个宏,而_PyObject_FastCall
又是_PyObject_FastCallDict
的宏。
这个_PyObject_FastCallDict
函数检查函数的类型( C
函数或Python函数或其他东西)并在这种情况下委托给_PyCFunction_FastCallDict
,因为datetime.now
是一个C函数。
由于datetime.datetime.now
具有METH_FASTCALL
标志,因此它在第四种case
结束,但是_PyStack_UnpackDict
返回NULL
并且甚至从不调用该函数。
我会停在那里,让Python开发人员弄清楚那里有什么问题。 @Martijn Pieters已经提交了一份Bug报告,他们将修复它(我希望他们能很快修复它)。
所以这是他们在3.6中引入的一个Bug,直到它被修复,你需要确保该方法不是带有METH_FASTCALL
标志的CFunction
。 作为解决方法,您可以包装它。 除了@Martijn Pieters提到的可能性之外,还有一个简单的:
def now():
return datetime.datetime.now()
j = iter(now, None)
next(j) # datetime.datetime(2017, 5, 31, 14, 23, 1, 95999)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.