web-dev-qa-db-ja.com

iter()が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
_

now()ごとに従来のnext()動作を出力する代わりに。

Python 3.3で同様のコードが機能しているのを見ましたが、何かが足りないのですか、それともバージョン3.6.1で何かが変更されていますか?

44
Vidak

これは間違いなくPython 3.6.0b1で導入されたバグです。iter()実装は最近_PyObject_FastCall()の使用に切り替わりました(最適化。 を参照)問題27128 )、そしてこれを破っているのはこの呼び出しでなければなりません。

同じ問題が、引数クリニックの構文解析に裏打ちされた他の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)
_

私は issue 30524-iter(classmethod、sentinel)broken for Argument Clinic class methods? with Pythonプロジェクト。これに対する修正が適用され、3.6.2rc1の一部になっています。

43
Martijn Pieters

別のPython実装ではなく、CPythonを使用していると仮定します。CPython3.6.1で問題を再現できます(PyPy、Jython、IronPythonなどがありません...だから私はこれらを確認することはできません)。

この場合の違反者は、CでPyObject_Callに相当する _PyObject_CallNoArgcallable_iterator.__next__ に置き換えることです(オブジェクトはcallable_iterator)メソッド。

PyObject_Callは新しいdatetime.datetimeインスタンスを返しますが、_PyObject_CallNoArgNULLを返します(これはPythonの例外とほぼ同等です)。

CPythonソースコードを少し掘り下げます。

_PyObject_CallNoArg_PyObject_FastCall の単なるマクロであり、これは _PyObject_FastCallDict のマクロです。

この_PyObject_FastCallDict関数 関数のタイプ(C-関数またはPython関数など)をチェックし、-に委任します _PyCFunction_FastCallDict この場合、datetime.nowはC関数であるため。

datetime.datetime.nowにはMETH_FASTCALLフラグがあるため、4番目のcaseになりますが、 _PyStack_UnpackDictNULLと関数を返します呼び出されることさえありません。

ここで停止して、Python開発者にそこで何が問題なのかを理解させます。@ MartijnPietersはすでにバグレポートを提出しており、修正する予定です(すぐに修正されることを願っています)。

したがって、これは3.6で導入されたバグであり、修正されるまで、メソッドが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)
16
MSeifert