पायथन में वेतन वृद्धि और वेतन वृद्धि ऑपरेटरों का व्यवहार


796

मुझे लगता है कि एक पूर्व-वेतन वृद्धि / कमी ऑपरेटर एक चर (जैसे ++count) पर लागू किया जा सकता है । यह संकलन करता है, लेकिन यह वास्तव में चर के मूल्य को नहीं बदलता है!

पायथन में प्री-इन्क्रीमेंट / डिक्रीमेंट ऑपरेटर्स (++ / -) का व्यवहार क्या है?

C / C ++ में देखे गए इन ऑपरेटरों के व्यवहार से अजगर क्यों विचलित होता है?


19
अजगर C या C ++ नहीं है। विभिन्न डिजाइन निर्णय भाषा बनाने में चले गए। विशेष रूप से, पायथन जानबूझकर असाइनमेंट ऑपरेटरों को परिभाषित नहीं करता है जो एक मनमाना अभिव्यक्ति में इस्तेमाल किया जा सकता है; बल्कि, असाइनमेंट स्टेटमेंट और संवर्धित असाइनमेंट स्टेटमेंट हैं। नीचे संदर्भ देखें।
नेड डिली

8
क्या आपको लगता है कि अजगर के पास ++और --ऑपरेटर थे?
u0b34a0f6ae

29
कैसर: C / C ++ से आते हुए, मैं ++ काउंट लिखता हूं और यह पायथन में संकलित होता है। इसलिए, मुझे लगा कि भाषा के संचालक हैं।
अश्विन नंजप्पा

3
@ फ़ॉक्स आप किसी योजना और संगठन के स्तर को प्रमाण में नहीं मान रहे हैं
बेसिक

4
@mehaase ++ और - सी में मौजूद नहीं है "पॉइंटर अंकगणित के लिए सिंटैक्टिक शुगर" के रूप में, वे मौजूद हैं क्योंकि कई प्रोसेसरों में स्वत: वेतन वृद्धि और डिक्रीमेंट मेमोरी एक्सेस मैकेनिज्म (सामान्य पॉइंटर इंडेक्सिंग, स्टैक इंडेक्सिंग में) उनके मूल निर्देश के भाग के रूप में होता है। सेट। उदाहरण के लिए, 6809 असेंबलर में: sta x++... परमाणु निर्देश जिसके परिणामस्वरूप aसंचयकर्ता xको इंगित करता है, जहां संचयकर्ता xका आकार बढ़ जाता है। यह किया जाता है क्योंकि यह सूचक अंकगणित की तुलना में तेज़ है, क्योंकि यह बहुत आम है, और क्योंकि यह समझना आसान है। दोनों पूर्व और -पोस्ट।
fyngyrz

जवाबों:


1058

++संचालक नहीं है। यह दो +ऑपरेटरों है। +ऑपरेटर है पहचान ऑपरेटर, जो कुछ नहीं करता है। (स्पष्टिकरण: +और -एकतरफा ऑपरेटर केवल संख्याओं पर काम करते हैं, लेकिन मुझे लगता है कि आप एक काल्पनिक ++ऑपरेटर को स्ट्रिंग्स पर काम करने की उम्मीद नहीं करेंगे ।)

++count

पर्स के रूप में

+(+count)

जिसका अनुवाद है

count

आपको जो करना है उसे करने के लिए आपको थोड़े लंबे +=ऑपरेटर का उपयोग करना होगा:

count += 1

मुझे संदेह है कि ऑपरेटरों ++और --ऑपरेटरों को स्थिरता और सादगी के लिए छोड़ दिया गया था। मुझे नहीं पता कि सटीक तर्क गुइडो वैन रोसुम ने निर्णय के लिए दिया था, लेकिन मैं कुछ तर्कों की कल्पना कर सकता हूं:

  • सरल पार्सिंग। तकनीकी तौर पर, पार्स ++countअस्पष्ट है, के रूप में यह हो सकता है +, +, count(दो एकल +ऑपरेटरों) बस के रूप में आसानी से यह हो सकता है के रूप में ++, count(एक एकल ++ऑपरेटर)। यह एक महत्वपूर्ण वाक्यात्मक अस्पष्टता नहीं है, लेकिन यह मौजूद है।
  • सरल भाषा। ++के लिए एक पर्याय से अधिक कुछ नहीं है += 1। यह एक शॉर्टहैंड का आविष्कार किया गया था क्योंकि सी कंपाइलर बेवकूफ थे और यह नहीं जानते थे कि अधिकांश कंप्यूटरों को निर्देश a += 1में कैसे अनुकूलित incकिया जाए। संकलक और बाइटकोड की व्याख्या करने वाले भाषाओं के इस दिन में, प्रोग्रामर्स को अपने कोड को ऑप्टिमाइज़ करने की अनुमति देने के लिए एक भाषा में ऑपरेटरों को जोड़ना आमतौर पर, विशेष रूप से पायथन जैसी भाषा में संगत और पठनीय के रूप में तैयार किया जाता है।
  • भ्रामक दुष्परिणाम। ++ऑपरेटरों के साथ भाषा में एक सामान्य नौसिखिया त्रुटि पूर्व और बाद के वेतन वृद्धि / परिचालकों के बीच मतभेदों (पूर्ववर्तीता और बदले में मूल्य दोनों) को मिला रही है, और पायथन भाषा "गेटा" -s को खत्म करना पसंद करती है। पूर्वता मुद्दों की सी में पूर्व / पोस्ट की वृद्धि दर्शाने वाले गंदगी के लिए सुंदर बालों कर रहे हैं, और अविश्वसनीय रूप से आसान।

13
"+ ऑपरेटर" पहचान "ऑपरेटर है, जो कुछ भी नहीं करता है।" केवल संख्यात्मक प्रकारों के लिए; अन्य प्रकार के लिए यह डिफ़ॉल्ट रूप से एक त्रुटि है।
newacct

45
इसके अलावा, इस बात का ध्यान रखें कि, पायथन में, + = और मित्र ऐसे ऑपरेटर नहीं हैं जिनका उपयोग अभिव्यक्तियों में किया जा सकता है। बल्कि, पायथन में उन्हें "संवर्धित असाइनमेंट स्टेटमेंट" के हिस्से के रूप में परिभाषित किया गया है। यह नहीं की अनुमति देने के काम ( "=") मनमाना भाव के भीतर एक ऑपरेटर के रूप में करने के लिए अजगर में भाषा डिजाइन निर्णय के अनुरूप है एक सी देखें में क्या कर सकते हैं के विपरीत docs.python.org/reference/...
नेड Deily

15
एकरी +संचालक का उपयोग होता है। दशमलव के लिए। दशमलव वस्तुओं के लिए, यह वर्तमान परिशुद्धता के लिए गोल है।
u0b34a0f6ae

21
मैं पार्सर सरलीकरण पर दांव लगा रहा हूं। PEP 3099 में एक आइटम नोट करें , "चीजें जो पायथन 3000 में नहीं बदलेगी": "पार्सर एलएल (1) की तुलना में अधिक जटिल नहीं होगा। सरल जटिल से बेहतर है। यह विचार पार्सर तक फैला हुआ है। अजगर के व्याकरण पर प्रतिबंध लगाना। एक एलएल (1) पार्सर एक आशीर्वाद है, अभिशाप नहीं। यह हमें हथकड़ी में डाल देता है जो हमें ओवरबोर्ड पर जाने से रोकता है और कुछ अन्य गतिशील भाषाओं की तरह कायरतापूर्ण व्याकरण के नियमों को समाप्त करता है जो अनलॉक्ड हो जाएंगे, जैसे पर्ल। " मैं यह नहीं देखता कि एलएलबी (1) को तोड़ना + +और ++तोड़ना कैसे ।
माइक डीस्मोन

7
यह कहना सही नहीं है कि ++इसके लिए पर्यायवाची से ज्यादा कुछ नहीं है += 1। ++ के प्री-इन्क्रीमेंट और पोस्ट-इन्क्रीमेंट वेरिएंट हैं, इसलिए यह स्पष्ट रूप से एक ही बात नहीं है। मैं आपके बाकी बिंदुओं से सहमत हूँ, हालाँकि।
फिलिब्स

384

जब आप वेतन वृद्धि या वृद्धि चाहते हैं, तो आप आम तौर पर एक पूर्णांक पर करना चाहते हैं। इस तरह:

b++

लेकिन पायथन में, पूर्णांक अपरिवर्तनीय हैं । यही कारण है कि आप उन्हें बदल नहीं सकते हैं। ऐसा इसलिए है क्योंकि पूर्णांक वस्तुओं का उपयोग कई नामों के तहत किया जा सकता है। इसे इस्तेमाल करे:

>>> b = 5
>>> a = 5
>>> id(a)
162334512
>>> id(b)
162334512
>>> a is b
True

ए और बी ऊपर वास्तव में एक ही वस्तु हैं। यदि आप एक वृद्धि करते हैं, तो आप भी वेतन वृद्धि करेंगे। वही नहीं जो आप चाहते हैं। इसलिए आपको फिर से भरोसा करना होगा। ऐशे ही:

b = b + 1

या सरल:

b += 1

कौन सा पुन: असाइन जाएगा bकरने के लिए b+1। यह एक वेतन वृद्धि ऑपरेटर नहीं है, क्योंकि यह वेतन वृद्धि नहीं करता है b, यह इसे पुन: सौंपता है।

संक्षेप में: पायथन यहां अलग तरह से व्यवहार करता है, क्योंकि यह C नहीं है, और मशीन कोड के आसपास निम्न स्तर का आवरण नहीं है, लेकिन एक उच्च-स्तरीय गतिशील भाषा है, जहां वेतन वृद्धि का कोई मतलब नहीं है, और C के रूप में भी आवश्यक नहीं है। , उदाहरण के लिए, लूप होने पर आप हर बार उनका उपयोग करते हैं।


75
यह उदाहरण गलत है (और आप शायद पहचान के साथ अपरिवर्तनीयता को भ्रमित कर रहे हैं) - उनके पास कुछ vm ऑप्टिमाइज़ेशन के कारण एक ही आईडी है जो 255 तक की संख्या के लिए समान वस्तुओं का उपयोग करता है (या ऐसा कुछ)। जैसे (बड़ा संख्या): >>> एक = 1231231231231 >>> ख = 1231231231231 >>> आईडी (क), आईडी (ख) (32,171,144, 32,171,168)
ionelmc

56
अपरिवर्तनीयता का दावा है। वैचारिक रूप से, i++आवंटित करने के लिए मतलब होगा i + 1करने के लिए चर ii = 5; i++द्वारा निर्दिष्ट वस्तु को संशोधित नहीं करने के लिए निर्दिष्ट 6करने का मतलब है । यही है, इसका मतलब मूल्य वृद्धि करना नहीं है ! iinti5
मेकैनिकल घोंघा

3
@ मेकेनिकल घोंघा: जिस स्थिति में यह वेतन वृद्धि ऑपरेटर नहीं होगा। और फिर + = ऑपरेटर स्पष्ट, अधिक स्पष्ट, अधिक लचीला होता है और वैसे भी वही काम करता है।
लेन्नर्ट रेग्रोब

7
@LennartRegebro: C ++ और Java में, i++केवल अंतराल पर काम करता है। यदि इसका उद्देश्य उस वस्तु की वृद्धि करना है i, जो यह प्रतिबंध अनावश्यक होगा।
मैकेनिकल घोंघा

4
मुझे यह उत्तर बहुत चौंकाने वाला लगता है। आप यह क्यों मान रहे हैं कि ++ का मतलब + = 1 के लिए शॉर्टहैंड के अलावा कुछ भी होगा? इसका ठीक यही अर्थ है कि C में इसका क्या अर्थ है (रिटर्न मान का उपयोग नहीं किया गया है)। आपको लगता है कि हवा से कुछ और अर्थ निकाला गया है।
डॉन हैच

52

जबकि अन्य उत्तर सही हैं, जहां तक ​​वे दिखाते हैं कि +आम तौर पर क्या करता है (अर्थात्, संख्या को छोड़ दें जैसा कि यह है, यदि यह एक है), तो वे अभी तक अपूर्ण हैं क्योंकि वे यह नहीं बताते हैं कि क्या होता है।

सटीक होने के लिए, का +xमूल्यांकन करता है x.__pos__()और ++xकरने के लिए x.__pos__().__pos__()

मैं एक बहुत अजीब वर्ग संरचना की कल्पना कर सकता था (बच्चे, घर पर ऐसा मत करो!) इस तरह:

class ValueKeeper(object):
    def __init__(self, value): self.value = value
    def __str__(self): return str(self.value)

class A(ValueKeeper):
    def __pos__(self):
        print 'called A.__pos__'
        return B(self.value - 3)

class B(ValueKeeper):
    def __pos__(self):
        print 'called B.__pos__'
        return A(self.value + 19)

x = A(430)
print x, type(x)
print +x, type(+x)
print ++x, type(++x)
print +++x, type(+++x)

13

अजगर के पास ये ऑपरेटर नहीं हैं, लेकिन अगर आपको वास्तव में उनकी आवश्यकता है तो आप एक फ़ंक्शन लिख सकते हैं जिसमें समान कार्यक्षमता हो।

def PreIncrement(name, local={}):
    #Equivalent to ++name
    if name in local:
        local[name]+=1
        return local[name]
    globals()[name]+=1
    return globals()[name]

def PostIncrement(name, local={}):
    #Equivalent to name++
    if name in local:
        local[name]+=1
        return local[name]-1
    globals()[name]+=1
    return globals()[name]-1

उपयोग:

x = 1
y = PreIncrement('x') #y and x are both 2
a = 1
b = PostIncrement('a') #b is 1 and a is 2

एक फ़ंक्शन के अंदर आपको स्थानीय तर्क को बदलना चाहते हैं, तो एक दूसरे तर्क के रूप में स्थानीय लोगों को जोड़ना होगा (अन्यथा) यह वैश्विक परिवर्तन करने का प्रयास करेगा।

x = 1
def test():
    x = 10
    y = PreIncrement('x') #y will be 2, local x will be still 10 and global x will be changed to 2
    z = PreIncrement('x', locals()) #z will be 11, local x will be 11 and global x will be unaltered
test()

इन कार्यों के साथ भी आप कर सकते हैं:

x = 1
print(PreIncrement('x'))   #print(x+=1) is illegal!

लेकिन मेरी राय में निम्नलिखित दृष्टिकोण बहुत स्पष्ट है:

x = 1
x+=1
print(x)

कमी ऑपरेटर:

def PreDecrement(name, local={}):
    #Equivalent to --name
    if name in local:
        local[name]-=1
        return local[name]
    globals()[name]-=1
    return globals()[name]

def PostDecrement(name, local={}):
    #Equivalent to name--
    if name in local:
        local[name]-=1
        return local[name]+1
    globals()[name]-=1
    return globals()[name]+1

मैंने अपने मॉड्यूल में इन कार्यों का उपयोग जावास्क्रिप्ट के लिए अजगर का अनुवाद किया।


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

11

पाइथन में, सामान्य लिस्प, स्कीम, या रूबी जैसी भाषाओं के विपरीत, अभिव्यक्ति और कथनों के बीच का अंतर कठोरता से लागू किया जाता है।

विकिपीडिया

तो ऐसे ऑपरेटरों को शुरू करने से, आप अभिव्यक्ति / कथन विभाजन को तोड़ देंगे।

उसी कारण से आप लिख नहीं सकते

if x = 0:
  y = 1

जैसा कि आप कुछ अन्य भाषाओं में कर सकते हैं जहाँ इस तरह के भेद को संरक्षित नहीं किया गया है।


दिलचस्प है, यह प्रतिबंध आगामी रिलीज अजगर 3.8 में असाइनमेंट एक्सप्रेशन (PEP-572 python.org/dev/peps/pep-0572 ) के लिए नए सिंटैक्स के साथ उठाया जाएगा । हम if (n := len(a)) > 10: y = n + 1उदाहरण के लिए लिख सकेंगे । ध्यान दें कि उस उद्देश्य के लिए एक नए ऑपरेटर की शुरूआत के कारण भेद स्पष्ट है ( :=)
Zertrin

8

टी एल; डॉ

अजगर में एकतरफा वेतन वृद्धि / वेतन वृद्धि ऑपरेटर ( --/ ++) नहीं है। इसके बजाय, एक मूल्य बढ़ाने के लिए, का उपयोग करें

a += 1

अधिक विस्तार और गोचर

लेकिन यहां सावधान रहें। यदि आप C से आ रहे हैं, तो भी यह अजगर में अलग है। पायथन के पास उस अर्थ में "वैरिएबल" नहीं है जो C करता है, इसके बजाय अजगर नाम और वस्तुओं का उपयोग करता है , और अजगर ints में अपरिवर्तनीय हैं।

तो चलो आप कहते हैं

a = 1

अजगर में इसका क्या अर्थ है: intमूल्य वाले प्रकार की एक वस्तु बनाएं 1और नाम aको बांधें । वस्तु का एक उदाहरण है intहोने मूल्य 1, और नाम a यह करने के लिए संदर्भित करता है। यह जिस नाम aऔर वस्तु को संदर्भित करता है, वह अलग है।

अब आप कहते हैं कि करते हैं

a += 1

चूँकि intअपरिवर्तनीय हैं, इसलिए यहाँ क्या होता है:

  1. उस ऑब्जेक्ट को देखें जो aइसे संदर्भित करता है (यह intआईडी के साथ है 0x559239eeb380)
  2. वस्तु का मूल्य देखें 0x559239eeb380(यह है 1)
  3. उस मान में 1 जोड़ें (1 + 1 = 2)
  4. मूल्य के साथ एक नई int वस्तु बनाएं 2(इसमें ऑब्जेक्ट आईडी है 0x559239eeb3a0)
  5. aइस नई वस्तु को नाम रिबंड करें
  6. अब aऑब्जेक्ट को संदर्भित करता है 0x559239eeb3a0और मूल ऑब्जेक्ट ( 0x559239eeb380) अब नाम से संदर्भित नहीं है a। यदि मूल वस्तु को संदर्भित करने वाले कोई अन्य नाम नहीं हैं, तो इसे बाद में एकत्र किया जाएगा।

इसे स्वयं आज़माएँ:

a = 1
print(hex(id(a)))
a += 1
print(hex(id(a)))

6

हाँ, मुझे ++ और - साथ ही कार्यक्षमता याद आ गई। सी कोड की कुछ मिलियन लाइनों ने मेरे पुराने सिर में इस तरह की सोच को उलझा दिया, और इसे लड़ने के बजाय ... यहाँ एक वर्ग है जिसे मैंने लागू किया है:

pre- and post-increment, pre- and post-decrement, addition,
subtraction, multiplication, division, results assignable
as integer, printable, settable.

यहाँ 'tis:

class counter(object):
    def __init__(self,v=0):
        self.set(v)

    def preinc(self):
        self.v += 1
        return self.v
    def predec(self):
        self.v -= 1
        return self.v

    def postinc(self):
        self.v += 1
        return self.v - 1
    def postdec(self):
        self.v -= 1
        return self.v + 1

    def __add__(self,addend):
        return self.v + addend
    def __sub__(self,subtrahend):
        return self.v - subtrahend
    def __mul__(self,multiplier):
        return self.v * multiplier
    def __div__(self,divisor):
        return self.v / divisor

    def __getitem__(self):
        return self.v

    def __str__(self):
        return str(self.v)

    def set(self,v):
        if type(v) != int:
            v = 0
        self.v = v

आप इसे इस तरह उपयोग कर सकते हैं:

c = counter()                          # defaults to zero
for listItem in myList:                # imaginary task
     doSomething(c.postinc(),listItem) # passes c, but becomes c+1

... पहले से ही ग, आप ऐसा कर सकते हैं ...

c.set(11)
while c.predec() > 0:
    print c

....या केवल...

d = counter(11)
while d.predec() > 0:
    print d

... और पूर्णांक में (पुनः) असाइनमेंट के लिए ...

c = counter(100)
d = c + 223 # assignment as integer
c = c + 223 # re-assignment as integer
print type(c),c # <type 'int'> 323

... जबकि यह c प्रकार काउंटर के रूप में बनाए रखेगा:

c = counter(100)
c.set(c + 223)
print type(c),c # <class '__main__.counter'> 323

संपादित करें:

और फिर यह अप्रत्याशित (और पूरी तरह से अवांछित) व्यवहार का एक सा है ,

c = counter(42)
s = '%s: %d' % ('Expecting 42',c) # but getting non-numeric exception
print s

... क्योंकि उस tuple के अंदर, getitem () का उपयोग नहीं किया जाता है, इसके बजाय ऑब्जेक्ट का एक संदर्भ स्वरूपण फ़ंक्शन को दिया जाता है। आह। इसलिए:

c = counter(42)
s = '%s: %d' % ('Expecting 42',c.v) # and getting 42.
print s

... या, अधिक मौखिक रूप से, और स्पष्ट रूप से हम वास्तव में क्या करना चाहते थे, हालांकि वास्तविक रूप में शब्द-बोध (उपयोग के c.vबजाय) द्वारा इंगित किया गया ...

c = counter(42)
s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42.
print s

2

अजगर में कोई पोस्ट / प्री इन्क्रीमेंट / डिक्रीमेंट ऑपरेटर नहीं हैं, जैसे C।

हम कई संकेतों को देख ++या समझ सकते हैं --, जैसे हम गणित (-1) * (-1) = (+1) में करते हैं।

उदाहरण के लिए

---count

पर्स के रूप में

-(-(-count)))

जिसका अनुवाद है

-(+count)

क्योंकि, -साइन के साथ -साइन का गुणन होता है+

और अंत में,

-count

1
यह क्या कहता है कि अन्य उत्तर नहीं देते हैं?
डैनियल बी।

@DanielB। अन्य उत्तरों ने यह नहीं बताया कि आंतरिक रूप से क्या होता है। और, न तो उन्होंने बताया है कि जब आप लिखेंगे तो क्या होगा -----count
अनुज

पहला, स्वीकृत उत्तर करता है। ...
डैनियल बी।

1
इस बात का कोई उल्लेख नहीं है कि गुणा किया जा रहा है, इसलिए मैंने सोचा कि एक सलाह और बात का जवाब साथी उपयोगकर्ताओं के लिए उपयोगी होगा। यदि आप उस से समझते हैं तो कोई अपराध नहीं है। आप जिस स्रोत से सीखते हैं, उससे अधिक महत्वपूर्ण है सीखना।
अनुज

0

अजगर 3.8+ में आप कर सकते हैं:

(a:=a+1) #same as a++

आप इसके साथ बहुत सारे विचार कर सकते हैं।

>>> a = 0
>>> while (a:=a+1) < 5:
    print(a)


1
2
3
4

या यदि आप अधिक परिष्कृत वाक्य रचना के साथ कुछ लिखना चाहते हैं (लक्ष्य अनुकूलन नहीं है):

>>> del a
>>> while (a := (a if 'a' in locals() else 0) + 1) < 5:
    print(a)


1
2
3
4

यह अच्छी तरह से 0 लौटाता है यदि कोई त्रुटि के बिना मौजूद नहीं है, और फिर इसे 1 पर सेट करेगा

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.