Vid*_*dak 44 python datetime iterable python-3.6
Python 3.6.1中的一个简单片段:
import datetime
j = iter(datetime.datetime.now, None)
next(j)
Run Code Online (Sandbox Code Playgroud)
收益:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Run Code Online (Sandbox Code Playgroud)
而不是打印now()
每个经典行为next()
.
我已经看到类似的代码在Python 3.3中工作,我在版本3.6.1中遗漏了什么或者有什么变化?
Mar*_*ers 43
这绝对是Python 3.6.0b1中引入的错误.iter()
最近的实现已经切换到使用_PyObject_FastCall()
(优化,参见问题27128),并且必须是这个打破这个的调用.
同样的问题与classmethod
Argument Clinic解析支持的其他C 方法有关:
>>> 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
Run Code Online (Sandbox Code Playgroud)
如果需要解决方法,请将callable包装在functools.partial()
对象中:
from functools import partial
j = iter(partial(datetime.datetime.now), None)
Run Code Online (Sandbox Code Playgroud)
我提交了问题30524 - iter(classmethod,sentinel)为Argument Clinic类方法打破了吗?与Python项目.对此的修复已落地并且是3.6.2rc1的一部分.
MSe*_*ert 16
我假设你使用的是CPython而不是另一个Python实现.我可以用CPython 3.6.1重现这个问题(我没有PyPy,Jython,IronPython,......所以我无法检查这些).
在这种情况下,罪犯是PyObject_Call
用_PyObject_CallNoArg
相当于callable_iterator.__next__
(你的对象是a callable_iterator
)方法的C 替换.
该PyObject_Call
不会返回一个新的datetime.datetime
,而实例_PyObject_CallNoArg
收益NULL
(这大致相当于在Python的除外).
通过CPython源代码挖掘一下:
这_PyObject_CallNoArg
只是一个宏,_PyObject_FastCall
而宏又是一个宏_PyObject_FastCallDict
.
此_PyObject_FastCallDict
函数检查函数的类型(C
-function或Python函数或其他内容),并_PyCFunction_FastCallDict
在这种情况下委托为因为datetime.now
是C函数.
因为datetime.datetime.now
有METH_FASTCALL
标志它在第四个结束,case
但_PyStack_UnpackDict
返回NULL
,甚至从未调用该函数.
我会停在那里,让Python开发人员弄清楚那里有什么问题.@Martijn Pieters已经提交了一份Bug报告,他们将修复它(我希望他们能很快修复它).
所以这是他们在3.6中引入的一个Bug,直到它被修复,你需要确保该方法不是CFunction
带有METH_FASTCALL
标志的.作为解决方法,您可以包装它.除了@Martijn Pieters提到的可能性之外,还有一个简单的:
def now():
return datetime.datetime.now()
j = iter(now, None)
next(j) # datetime.datetime(2017, 5, 31, 14, 23, 1, 95999)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1510 次 |
最近记录: |