from example biblioteca python datetime python-3.6 iterable

example - strftime python



iter() no funciona con datetime.now() (2)

Este es definitivamente un error introducido en Python 3.6.0b1. La implementación iter() recientemente cambió a usar _PyObject_FastCall() (una optimización, ver el número 27128 ), y debe ser esta llamada la que está rompiendo esto.

El mismo problema surge con otros métodos de classmethod C respaldados por el análisis de Argument Clinic:

>>> 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

Si necesita una functools.partial() el invocable en un objeto functools.partial() :

from functools import partial j = iter(partial(datetime.datetime.now), None)

Archivé el problema 30524 - iter (classmethod, sentinel) roto para los métodos de clase de Argument Clinic? con el proyecto Python. La solución para esto ha aterrizado y es parte de 3.6.2rc1.

Un fragmento simple en Python 3.6.1:

import datetime j = iter(datetime.datetime.now, None) next(j)

devoluciones:

Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration

en lugar de imprimir el comportamiento clásico de now() con cada next() .

He visto código similar trabajando en Python 3.3, ¿me falta algo o algo ha cambiado en la versión 3.6.1?


Supongo que estás usando CPython y no otra implementación de Python. Y puedo reproducir el problema con CPython 3.6.1 (no tengo PyPy, Jython, IronPython, ... así que no puedo verificar esto).

El infractor en este caso es el reemplazo de PyObject_Call con _PyObject_CallNoArg en el equivalente en C del callable_iterator.__next__ (su objeto es un callable_iterator ).

PyObject_Call devuelve una nueva instancia de datetime.datetime mientras _PyObject_CallNoArg devuelve NULL (que es más o menos equivalente a una excepción en Python).

Excavando un poco a través del código fuente CPython:

_PyObject_CallNoArg es solo una macro para _PyObject_FastCall que a su vez es una macro para _PyObject_FastCallDict .

Esta función _PyObject_FastCallDict comprueba el tipo de la función (función C o función de Python u otra cosa) y delega a _PyCFunction_FastCallDict en este caso porque datetime.now es una función C.

Dado que datetime.datetime.now tiene el indicador METH_FASTCALL , termina en el cuarto case pero allí _PyStack_UnpackDict devuelve NULL y la función nunca se llama.

Me detendré allí y dejaré que los desarrolladores de Python se den cuenta de lo que está mal allí. @Martijn Pieters ya presentó un informe de error y lo arreglarán (solo espero que lo arreglen pronto).

Entonces, es un error que introdujeron en 3.6 y hasta que se solucione, debes asegurarte de que el método no sea una CFunction con el indicador METH_FASTCALL . Como solución alternativa puede envolverlo. Además de las posibilidades que mencionó @Martijn Pieters, también hay un simple:

def now(): return datetime.datetime.now() j = iter(now, None) next(j) # datetime.datetime(2017, 5, 31, 14, 23, 1, 95999)