क्या यह एक पुनरावृत्ति चर के बिना रेंज लूप के लिए पायथन को लागू करना संभव है?


187

क्या इसके बिना पालन करना संभव है i?

for i in range(some_number):
    # do something

यदि आप अभी कुछ समय एन की राशि करना चाहते हैं और पुनरावृत्ति की आवश्यकता नहीं है।


21
यह अच्छा प्रश्न है! PyDev ने 'i' को 'अप्रयुक्त चर' के लिए चेतावनी के रूप में भी चिह्नित किया। नीचे दिया गया समाधान इस चेतावनी को हटा देता है।
अश्विन नांजप्पा

@Ashwin आप उस चेतावनी को हटाने के लिए \ @UnusedVariable का उपयोग कर सकते हैं। ध्यान दें कि मुझे यह टिप्पणी करने के लिए 'at' प्रतीक से बचने की आवश्यकता थी।
रफ़ी खाचदौरेन

मैं उसी प्रश्न का उत्तर देता हूं। यह pylint चेतावनियों से परेशान है। बेशक आप @Raffi Khatchadourian प्रस्तावित जैसे अतिरिक्त दमन से चेतावनी को अक्षम कर सकते हैं। अच्छा होगा कि पाइलिंट चेतावनी और दमन टिप्पणियों से बचें ।
टैंगो

जवाबों:


109

मेरे सिर के ऊपर से, नहीं।

मुझे लगता है कि सबसे अच्छा आप कुछ इस तरह कर सकते हैं:

def loop(f,n):
    for i in xrange(n): f()

loop(lambda: <insert expression here>, 5)

लेकिन मुझे लगता है कि आप केवल अतिरिक्त iचर के साथ रह सकते हैं ।

यहां _चर का उपयोग करने का विकल्प है , जो वास्तव में, केवल एक और चर है।

for _ in range(n):
    do_something()

ध्यान दें कि _अंतिम परिणाम जो एक इंटरैक्टिव अजगर सत्र में लौटाया गया है:

>>> 1+2
3
>>> _
3

इस कारण से, मैं इसे इस तरीके से उपयोग नहीं करूंगा। मैं किसी भी मुहावरे से अनजान हूँ जैसा कि रेयान ने उल्लेख किया है। यह आपके दुभाषिया को गड़बड़ कर सकता है।

>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9

और अजगर व्याकरण के अनुसार , यह एक स्वीकार्य चर नाम है:

identifier ::= (letter|"_") (letter | digit | "_")*

4
"लेकिन मुझे लगता है कि आप अतिरिक्त" मैं "के साथ रह सकते हैं" हाँ यह सिर्फ एक अकादमिक बिंदु है।
जेम्स मैकमोहन

1
@ नीमो, आप _ के लिए रेंज में करने की कोशिश कर सकते हैं (n): यदि आप अल्फ़ान्यूमेरिक नामों का उपयोग नहीं करना चाहते हैं।
अज्ञात

उस मामले में एक चर है? या कि पायथन में कुछ और है?
जेम्स मैकमोहन

1
@ नीमो हां इसका सिर्फ एक स्वीकार्य चर नाम है। दुभाषिया में, यह आपके द्वारा की गई अंतिम अभिव्यक्ति को स्वचालित रूप से नियत करता है।
अज्ञात

3
@kurczak एक बिंदु है। उपयोग करने _से यह स्पष्ट हो जाता है कि इसे अनदेखा किया जाना चाहिए। यह कहना कि ऐसा करने का कोई मतलब नहीं है, यह कहने जैसा है कि आपके कोड पर टिप्पणी करने का कोई मतलब नहीं है - क्योंकि यह वैसे भी बिल्कुल वैसा ही करेगा।
लैम्बडा फेयरी

69

आप ढूंढ रहे होंगे

for _ in itertools.repeat(None, times): ...

यह timesपायथन में समय को पुन: व्यवस्थित करने का सबसे तेज़ तरीका है ।


2
मुझे प्रदर्शन से कोई सरोकार नहीं था, मैं सिर्फ उत्सुक था अगर बयान लिखने का कोई तरीका था। जबकि मैं लगभग 2 वर्षों से छिटपुट रूप से पायथन का उपयोग कर रहा हूं अब भी मुझे लगता है कि बहुत कुछ मुझे याद आ रहा है। Itertools उन चीजों में से एक है, जानकारी के लिए धन्यवाद।
जेम्स मैकमोहन

5
यह दिलचस्प है, मुझे इसकी जानकारी नहीं थी। मैंने सिर्फ इटर्टूलस डॉक्स पर एक नज़र डाली; लेकिन मुझे आश्चर्य है कि यह सिर्फ सीमा या xrange का उपयोग करने से क्यों तेज है?
si28719e

5
@blackkettle: यह तेज़ है क्योंकि इसे वर्तमान पुनरावृत्ति सूचकांक को वापस करने की आवश्यकता नहीं है, जो कि xrange (और पायथन 3 की श्रेणी की लागत का एक औसत दर्जे का हिस्सा है, जो एक पुनरावृत्ति देता है, सूची नहीं)। @ नीमो, रेंज उतना ही अनुकूलित किया जा सकता है, लेकिन सूची बनाने और वापस करने की आवश्यकता अनिवार्य रूप से एक पुनरावृत्त की तुलना में भारी काम की है (Py3 में, श्रेणी पुनरावृत्ती लौटाती है, जैसे Py2 की xrange; पीछे की संगतता इस तरह के परिवर्तन की अनुमति देती है) Py2 में), विशेष रूप से एक जिसे अलग-अलग मूल्य वापस करने की आवश्यकता नहीं है।
एलेक्स मार्टेली

4
@ क्रिश्चियन, हाँ, स्पष्ट रूप से तैयार करना और लौटाना हर बार, इंक। जीसी काम, एक औसत दर्जे का खर्च होता है - आंतरिक रूप से काउंटर का उपयोग करना कोई मायने नहीं रखता है।
एलेक्स मार्टेली

4
मैं अब समझता हूँ। अंतर जीसी ओवरहेड से आता है, न कि "एल्गोरिथम" से। वैसे, मैं एक त्वरित समय सीमा बेंचमार्क चलाता हूं और स्पीडअप ~ 1.42x था।
क्रिस्टियन सियुपिटु

59

उपयोग नहीं किए जाने वाले मान को असाइन करने के लिए सामान्य मुहावरा इसका नाम है _

for _ in range(times):
    do_stuff()

18

हर कोई जो आपको _ का उपयोग करने का सुझाव देता है, वह यह नहीं कहता है कि _ अक्सर गेटटेक्स्ट कार्यों में से एक के लिए एक शॉर्टकट के रूप में उपयोग किया जाता है , इसलिए यदि आप चाहते हैं कि आपका सॉफ़्टवेयर एक से अधिक भाषाओं में उपलब्ध हो, तो आप इसका उपयोग करने से बचते हैं। अन्य उद्देश्यों के लिए।

import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')

मेरे लिए यह प्रयोग _एक भयानक विचार की तरह लगता है, मैं इसके साथ विरोध नहीं करूंगा।
कीथॉव

9

यहां एक यादृच्छिक विचार है जो डेटा मॉडल ( Py3 लिंक ) का उपयोग (दुरुपयोग) करता है ।

class Counter(object):
    def __init__(self, val):
        self.val = val

    def __nonzero__(self):
        self.val -= 1
        return self.val >= 0
    __bool__ = __nonzero__  # Alias to Py3 name to make code work unchanged on Py2 and Py3

x = Counter(5)
while x:
    # Do something
    pass

मुझे आश्चर्य है कि क्या मानक पुस्तकालयों में ऐसा कुछ है?


10
मुझे लगता है कि __nonzero__साइड-इफेक्ट के साथ एक विधि होना एक भयानक विचार है।
ThiefMaster

2
मैं __call__इसके बजाय प्रयोग करेंगे । while x():लिखने के लिए इतना कठिन नहीं है।
जसमीजन

1
नाम से बचने के लिए एक तर्क भी है Counter; निश्चित रूप से, यह आरक्षित या बिल्ट-इन स्कोप में नहीं है, बल्कि collections.Counterएक चीज़ है , और एक ही नाम के जोखिम को बनाए रखने वाला एक वर्ग बना हुआ है भ्रम (यह नहीं कि यह पहले से ही जोखिम में नहीं है)।
शैडो रेंजर

7

गेटटेक्स्ट के साथ नाम-विभाजन को रोकने के लिए आप _11 (या किसी भी संख्या या अन्य अमान्य पहचानकर्ता) का उपयोग कर सकते हैं। जब भी आप अंडरस्कोर + अमान्य पहचानकर्ता का उपयोग करते हैं तो आपको एक डमी नाम मिलता है जिसका उपयोग लूप के लिए किया जा सकता है।


अच्छा! प्यदेव आपके साथ सहमत हैं: इससे "अप्रयुक्त चर" पीले चेतावनी से छुटकारा मिलता है।
माइक कृंतक

2

हो सकता है कि इसका उत्तर इस बात पर निर्भर करेगा कि आपको पुनरावृत्ति का उपयोग करने में क्या समस्या है? उपयोग हो सकता है

i = 100
while i:
    print i
    i-=1

या

def loop(N, doSomething):
    if not N:
        return
    print doSomething(N)
    loop(N-1, doSomething)

loop(100, lambda a:a)

लेकिन स्पष्ट रूप से मैं इस तरह के दृष्टिकोण का उपयोग करने में कोई मतलब नहीं देखता


1
ध्यान दें: पायथन (निश्चित रूप से कम से कम सीपीयथन संदर्भ दुभाषिया नहीं है, शायद अन्य लोगों में से अधिकांश नहीं) पूंछ पुनरावृत्ति का अनुकूलन नहीं करता है, इसलिए एन मूल्य के मूल्य के पड़ोस में कुछ तक सीमित होगा sys.getrecursionlimit()(जो कि कम चार में कहीं भी चूक करता है) CPython पर अंक सीमा); उपयोग sys.setrecursionlimitकरने से सीमा बढ़ेगी, लेकिन अंततः आप सी स्टैक सीमा से टकराएंगे और दुभाषिया स्टैक ओवरफ्लो के साथ मर जाएगा (न कि केवल एक अच्छा RuntimeError/ बढ़ाकर RecursionError)।
शैडो रेंजर


1

एक अनावश्यक काउंटर के बजाय, अब आपके पास एक अनावश्यक सूची है। सबसे अच्छा समाधान एक चर का उपयोग करना है जो "_" से शुरू होता है, जो वाक्यविन्यास चेकर्स को बताता है कि आप जानते हैं कि आप चर का उपयोग नहीं कर रहे हैं।

x = range(5)
while x:
  x.pop()
  print "Work!"

0

मैं आम तौर पर ऊपर दिए गए समाधानों से सहमत हूं। इसके साथ नम:

  1. अंडरस्कोर का उपयोग for-लूप (2 और अधिक पंक्तियों) में
  2. एक सामान्य whileकाउंटर को परिभाषित करना (3 और अधिक लाइनें)
  3. __nonzero__कार्यान्वयन के साथ एक कस्टम वर्ग की घोषणा (कई और लाइनें)

यदि कोई # 3 के रूप में एक वस्तु को परिभाषित करने के लिए है, तो मैं कीवर्ड के साथ प्रोटोकॉल को लागू करने या संदर्भ सूची को लागू करने की सिफारिश करूंगा

इसके अलावा मैं अभी तक एक और समाधान का प्रस्ताव है। यह एक 3 लाइनर है और सर्वोच्च लालित्य का नहीं है, लेकिन यह itertools पैकेज का उपयोग करता है और इस प्रकार एक ब्याज का हो सकता है।

from itertools import (chain, repeat)

times = chain(repeat(True, 2), repeat(False))
while next(times):
    print 'do stuff!'

इन उदाहरणों में 2 लूप को पुनरावृत्त करने के लिए कई बार है। श्रृंखला दो पुनरावृत्तियों को लपेट रही है, पहला सीमित है लेकिन दूसरा अनंत है। याद रखें कि ये सत्य पुनरावृत्त वस्तुएं हैं, इसलिए उन्हें अनंत स्मृति की आवश्यकता नहीं है। जाहिर है यह बहुत धीमी है तो समाधान # 1 । जब तक किसी फ़ंक्शन के भाग के रूप में नहीं लिखा जाता है, तो उसे बार चर के लिए क्लीन अप की आवश्यकता हो सकती है ।


2
chainअनावश्यक है, times = repeat(True, 2); while next(times, False):एक ही बात करता है।
एसीफंपियन

0

हमने निम्नलिखित के साथ कुछ मजेदार किया है, दिलचस्प है ताकि साझा करें:

class RepeatFunction:
    def __init__(self,n=1): self.n = n
    def __call__(self,Func):
        for i in xrange(self.n):
            Func()
        return Func


#----usage
k = 0

@RepeatFunction(7)                       #decorator for repeating function
def Job():
    global k
    print k
    k += 1

print '---------'
Job()

परिणाम:

0
1
2
3
4
5
6
---------
7

0

यदि do_somethingएक सरल कार्य है या एक में लपेटा जा सकता है, तो एक सरल समय map()हो सकता do_something range(some_number)है:

# Py2 version - map is eager, so it can be used alone
map(do_something, xrange(some_number))

# Py3 version - map is lazy, so it must be consumed to do the work at all;
# wrapping in list() would be equivalent to Py2, but if you don't use the return
# value, it's wastefully creating a temporary, possibly huge, list of junk.
# collections.deque with maxlen 0 can efficiently run a generator to exhaustion without
# storing any of the results; the itertools consume recipe uses it for that purpose.
from collections import deque

deque(map(do_something, range(some_number)), 0)

यदि आप तर्कों को पारित करना चाहते हैं do_something, तो आप यह भी जानrepeatfunc सकते हैं कि इटर्लस नुस्खा अच्छी तरह से पढ़ता है:

एक ही तर्क पारित करने के लिए:

from collections import deque
from itertools import repeat, starmap

args = (..., my args here, ...)

# Same as Py3 map above, you must consume starmap (it's a lazy generator, even on Py2)
deque(starmap(do_something, repeat(args, some_number)), 0)

विभिन्न तर्कों को पारित करने के लिए:

argses = [(1, 2), (3, 4), ...]

deque(starmap(do_something, argses), 0)

-1

यदि आप वास्तव में किसी नाम के साथ कुछ डालने से बचना चाहते हैं (या तो ओपी में वैरिएबल वैरिएबल, या अवांछित सूची या अवांछित जनरेटर सही समय की वांछित राशि लौटाते हैं) तो आप इसे कर सकते हैं यदि आप वास्तव में चाहते थे:

for type('', (), {}).x in range(somenumber):
    dosomething()

जिस ट्रिक का उपयोग किया जाता है, वह एक अनाम वर्ग बनाने के लिए है type('', (), {})जिसका परिणाम खाली नाम के साथ एक वर्ग में होता है, लेकिन NB कि यह स्थानीय या वैश्विक नाम स्थान (भले ही कोई गैर-रिक्त नाम आपूर्ति की गई हो) में सम्मिलित नहीं है। फिर आप उस वर्ग के एक सदस्य का उपयोग करें जो कि परिवर्तनशील चर के रूप में अनुपलब्ध है क्योंकि यह जिस वर्ग का सदस्य है वह अप्राप्य है।


जाहिर है कि यह जानबूझकर पैथोलॉजिकल है, इसलिए आलोचना करना इस मुद्दे के बगल में है, लेकिन मैं यहां एक अतिरिक्त नुकसान पर ध्यान दूंगा। CPython पर, संदर्भ दुभाषिया, वर्ग की परिभाषाएं स्वाभाविक रूप से चक्रीय हैं (एक वर्ग का निर्माण अप्रत्याशित रूप से एक संदर्भ चक्र बनाता है जो संदर्भ गिनती के आधार पर वर्ग के निर्धारक सफाई को रोकता है)। इसका मतलब है कि आप चक्रीय जीसी पर इंतजार कर रहे हैं ताकि कक्षा में किक और सफाई हो सके। यह आमतौर पर युवा पीढ़ी के हिस्से के रूप में एकत्र किया जाएगा, जो डिफ़ॉल्ट रूप से अक्सर एकत्र किया जाता है, लेकिन फिर भी, प्रत्येक लूप का अर्थ है ~ 1.5 KB कचरा w / गैर-निर्धारक जीवनकाल।
शैडो रेंजर

मूल रूप से, एक नामित चर से बचने के लिए जो (आमतौर पर) नियत रूप से प्रत्येक लूप पर साफ किया जाता है (जब यह पलटाव होता है, और पुराना मूल्य साफ हो जाता है), तो आप एक बड़ा अनाम चर बना रहे हैं जो गैर-निर्धारक रूप से साफ किया जाता है, और आसानी से हो सकता है अब पिछले।
शैडो रेंजर


-7

व्हाट अबाउट:

while range(some_number):
    #do something

3
यह एक अनंत लूप है क्योंकि हालत range(some_number)हमेशा सच होती है!
घातक

@ स्पष्ट: ठीक है, अगर some_numberइससे कम या इसके बराबर है 0, तो यह अनंत नहीं है, यह सिर्फ कभी नहीं चलता है। :-) और यह बजाय एक अनंत लूप (विशेष रूप से Py2 पर) के लिए अक्षम है, क्योंकि यह एक ताजा बनाता है list(Py2) या rangeप्रत्येक परीक्षा के लिए वस्तु (Py3) (यह देखने का दुभाषिया के दृष्टिकोण से एक निरंतर नहीं है, यह लोड करने के लिए है rangeऔर some_numberहर लूप, कॉल करें range, फिर परिणाम का परीक्षण करें)।
शैडो रेंजर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.