繁体   English   中英

iter()不使用datetime.now()

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM