2017-05-31 15 views
43

एक साधारण स्निपेट के साथ काम नहीं कर रहा:आईटीईआर() पायथन 3.6.1 में datetime.now()

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

रिटर्न:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
बजाय प्रत्येक next() के साथ क्लासिक now() व्यवहार को प्रिंट की

मैंने पाइथन 3.3 में काम कर रहे समान कोड को देखा है, क्या मुझे कुछ याद आ रहा है या संस्करण 3.6.1 में कुछ बदल गया है?

+2

दिलचस्प, मैं यह काम करने की अपेक्षा करता हूं। यह 3.4 और 3.5 में भी काम करता है। –

+2

यह तब काम करता है जब आप 'datetime.datetime.now' को 'lambda: datetime.datetime.now()' या 'आंशिक (datetime.datetime.now)' के साथ बदलते हैं। –

+2

मुझे लगता है कि आपको इसकी रिपोर्ट [बग ट्रैकर] (https://bugs.python.org/) पर करनी चाहिए। – MSeifert

उत्तर

43

यह निश्चित रूप से पाइथन 3.6.0b1 में पेश की गई एक बग है। iter() कार्यान्वयन ने हाल ही में _PyObject_FastCall() (एक अनुकूलन, issue 27128 देखें) का उपयोग करने के लिए स्विच किया है, और यह यह कॉल होना चाहिए जो इसे तोड़ रहा है।

अन्य सी classmethod तरीकों तर्क क्लिनिक पार्स द्वारा समर्थित के साथ एक ही मुद्दा arrises:

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

आप एक काम के आसपास, की जरूरत है एक functools.partial() वस्तु में प्रतिदेय लपेट:

from functools import partial 

j = iter(partial(datetime.datetime.now), None) 

मैं पाइथन परियोजना के साथ issue 30524 -- iter(classmethod, sentinel) broken for Argument Clinic class methods? दायर किया। इसके लिए फिक्स उतरा है और 3.6.2 आरसी 1 का हिस्सा है।

+9

+1, लेकिन ब्याज के बिंदु के रूप में, आप 'lambda' (जैसे आपकी टिप्पणी में) कहने के लिए कुछ' आंशिक 'क्यों पसंद करेंगे? – erip

+10

@erip: क्योंकि यह * तेज * है। कोई पायथन फ्रेम नहीं बनाया जा सकता है, सी कार्यान्वयन सीधे 'datetime.datetime.now' सी फ़ंक्शन को कॉल कर सकता है। –

16

मुझे लगता है कि आप सीपीथन का उपयोग कर रहे हैं और एक और पायथन कार्यान्वयन नहीं कर रहे हैं। और मैं इस मुद्दे को सीपीथन 3.6.1 के साथ पुन: पेश कर सकता हूं (मेरे पास पीपीपी, ज्योथन, आयरनपीथन नहीं है ... इसलिए मैं इन्हें जांच नहीं सकता)।

इस मामले में अपराधी callable_iterator.__next__ की सी बराबर में _PyObject_CallNoArg साथ PyObject_Call के प्रतिस्थापन है विधि (अपने वस्तु एक callable_iterator है)।

PyObject_Call एक नया datetime.datetime उदाहरण वापसी करता है, जबकि _PyObject_CallNoArg रिटर्न NULL (जो मोटे तौर पर पायथन में एक अपवाद के बराबर है)।

CPython स्रोत कोड के माध्यम से थोड़ा खुदाई:

_PyObject_CallNoArg सिर्फ _PyObject_FastCall के लिए एक मैक्रो जो बारी में _PyObject_FastCallDict के लिए एक मैक्रो है।

This _PyObject_FastCallDict function चेकों समारोह के प्रकार (C समारोह या अजगर समारोह या कुछ और) इस मामले क्योंकि datetime.now एक सी समारोह है में _PyCFunction_FastCallDict करने और प्रतिनिधियों।

datetime.datetime.now के बाद से यह चौथी case में समाप्त होता है लेकिन वहाँ _PyStack_UnpackDict रिटर्न NULL और समारोह भी कहा जाता है कभी नहीं है METH_FASTCALL झंडा है।

मैं वहां रुक जाऊंगा और पाइथन देवों को पता चल जाएगा कि वहां क्या गलत है। @ मार्टिजन पीटर्स ने पहले ही एक बग रिपोर्ट दायर की है और वे इसे ठीक कर देंगे (मुझे उम्मीद है कि वे जल्द ही इसे ठीक करेंगे)।

तो यह एक बग है जिसे उन्होंने 3.6 में पेश किया है और जब तक यह तय नहीं हो जाता है, आपको यह सुनिश्चित करने की आवश्यकता है कि विधि CFunctionMETH_FASTCALL ध्वज के साथ नहीं है। कामकाज के रूप में आप इसे लपेट सकते हैं।संभावनाओं के अलावा @ मार्टिजन पीटर्स ने उल्लेख किया कि एक सरल भी है:

def now(): 
    return datetime.datetime.now() 

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

अपराधियों में अतिरिक्त अंतर्दृष्टि के साथ भी महान जवाब। मैं मार्टिजन के उत्तर पर स्वीकृत चिह्न रखूंगा क्योंकि वह पहले से ही पायथन परियोजना के साथ इस मुद्दे को प्रस्तुत कर चुका है। – Vidak

+3

यह फास्टकॉल अनुकूलन में एक पुष्टि की गई बग है, और विक्टर स्टिनर का प्रारंभिक पैच https://github.com/python/cpython/pull/1886 पर है –

संबंधित मुद्दे