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)