क्या हम किसी हालत में असाइनमेंट कर सकते हैं?


92

क्या किसी हालत में असाइनमेंट करना संभव है?

पूर्व के लिए।

if (a=some_func()):
    # Use a

कि दो सवालों का एक ही जवाब है इसका मतलब यह नहीं है कि वे डुप्लिकेट हैं। अपने आप को जवाब देने के लिए तुच्छ, लेकिन तर्क को देखने के लिए तुच्छ नहीं, या यदि कोई रास्ता है।
— mehmet

जवाबों:


111

क्यों न इसे आज़माएं?

>>> def some_func():
...   return 2
... 
>>> a = 2
>>> if (a = some_func()):
  File "<stdin>", line 1
    if (a = some_func()):
          ^
SyntaxError: invalid syntax
>>> 

तो, नहीं।

अपडेट: पायथन 3.8 में यह (विभिन्न सिंटैक्स के साथ) संभव है


35
यह जानबूझकर मना किया जाता है क्योंकि Guido, परोपकारी अजगर तानाशाह, उन्हें अनावश्यक और उपयोगी से अधिक भ्रमित करता है। यही कारण है कि कोई पोस्ट-इन्क्रीमेंट या प्री-इन्क्रीमेंट ऑपरेटर (++) नहीं है।
— मैट बोहेम

4
वह के अलावा की अनुमति देने के लिए किया था संवर्धित असाइनमेंट 2.0 में क्योंकि x = x + 1अतिरिक्त देखने समय की आवश्यकता है, जबकि x += 1कुछ हद तक तेजी से गया था, लेकिन मुझे यकीन है कि कर रहा हूँ वह भी कर रही पसंद नहीं आया कि ज्यादा। :-)
— वास्कपी

आशा है, यह जल्द ही संभव हो जाएगा। अजगर को विकसित करने के लिए बस धीमी है
— निक ओ'लाई

4
"क्यों नहीं इसे आज़माएं" - क्योंकि कौन जानता है कि वाक्यविन्यास क्या हो सकता है? शायद ओपी ने कोशिश की और यह काम नहीं किया, लेकिन इसका मतलब यह नहीं है कि वाक्यविन्यास अलग नहीं है, या ऐसा करने का कोई तरीका नहीं है जिसका इरादा नहीं है
— लेवी एच

57

अद्यतन - मूल जवाब नीचे के पास है

PEP572 में अजगर 3.8 लाएगा

सार
यह नोटेशन NAME: = expr का उपयोग करके किसी अभिव्यक्ति के भीतर चर को असाइन करने का एक तरीका बनाने के लिए एक प्रस्ताव है। एक नया अपवाद, TargetScopeError जोड़ा गया है, और मूल्यांकन क्रम में एक बदलाव है।

https://lwn.net/Articles/757713/

"PEP 572 मेस" जीवन के लिए परोपकारी तानाशाह (BDFL) गुइडो वैन रोसुम के नेतृत्व में 2018 पायथन लैंग्वेज समिट सत्र का विषय था। PEP 572 भाषा में असाइनमेंट एक्सप्रेशंस (या "इनलाइन असाइनमेंट") जोड़ना चाहता है, लेकिन इसने अजगर-देव मेलिंग सूची पर कई विशाल थ्रेड पर एक लंबी चर्चा को देखा है - अजगर-विचारों के कई दौर के बाद भी। वे धागे अक्सर विवादास्पद थे और स्पष्ट रूप से उस बिंदु पर प्रकाशमान थे जहां कई शायद सिर्फ उन्हें बाहर निकालते थे। शिखर सम्मेलन में, वैन रोसुम ने फीचर प्रस्ताव का अवलोकन किया, जो उन्हें स्वीकार करने की ओर झुकाव है, लेकिन वह यह भी चर्चा करना चाहता था कि भविष्य में इस तरह के थ्रेड विस्फोट से कैसे बचा जाए।

https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library

पायथन मानक पुस्तकालय से उदाहरण

site.py env_base का उपयोग केवल इन पंक्तियों पर किया जाता है, यदि इसका असाइनमेंट ब्लॉक के "हेडर" के रूप में चलता है।

वर्तमान:

env_base = os.environ.get("PYTHONUSERBASE", None)
if env_base:
    return env_base

बेहतर:

if env_base := os.environ.get("PYTHONUSERBASE", None):
    return env_base
_pydecimal.py

नेस्टेड से बचें और एक इंडेंटेशन स्तर को हटा दें।

वर्तमान:

if self._is_special:
    ans = self._check_nans(context=context)
    if ans:
        return ans

बेहतर:

if self._is_special and (ans := self._check_nans(context=context)):
    return ans

copy.py कोड अधिक नियमित दिखता है और यदि कोई हो तो कई नेस्टेड से बचें। (इस उदाहरण की उत्पत्ति के लिए परिशिष्ट A देखें।)

वर्तमान:

reductor = dispatch_table.get(cls)
if reductor:
    rv = reductor(x)
else:
    reductor = getattr(x, "__reduce_ex__", None)
    if reductor:
        rv = reductor(4)
    else:
        reductor = getattr(x, "__reduce__", None)
        if reductor:
            rv = reductor()
        else:
            raise Error(
                "un(deep)copyable object of type %s" % cls)

बेहतर:

if reductor := dispatch_table.get(cls):
    rv = reductor(x)
elif reductor := getattr(x, "__reduce_ex__", None):
    rv = reductor(4)
elif reductor := getattr(x, "__reduce__", None):
    rv = reductor()
else:
    raise Error("un(deep)copyable object of type %s" % cls)
datetime.py

tz का उपयोग केवल s + = tz के लिए किया जाता है, यदि इसके कार्यक्षेत्र को इसके दायरे को दिखाने में मदद करता है।

वर्तमान:

s = _format_time(self._hour, self._minute,
                 self._second, self._microsecond,
                 timespec)
tz = self._tzstr()
if tz:
    s += tz
return s

बेहतर:

s = _format_time(self._hour, self._minute,
                 self._second, self._microsecond,
                 timespec)
if tz := self._tzstr():
    s += tz
return s

sysconfig.py कॉलिंग fp.readline (), जबकि कंडीशन और कॉलिंग .match () यदि लाइनों के बिना कोड को अधिक कॉम्पैक्ट बनाता है

इसे समझना कठिन है।

वर्तमान:

while True:
    line = fp.readline()
    if not line:
        break
    m = define_rx.match(line)
    if m:
        n, v = m.group(1, 2)
        try:
            v = int(v)
        except ValueError:
            pass
        vars[n] = v
    else:
        m = undef_rx.match(line)
        if m:
            vars[m.group(1)] = 0

बेहतर:

while line := fp.readline():
    if m := define_rx.match(line):
        n, v = m.group(1, 2)
        try:
            v = int(v)
        except ValueError:
            pass
        vars[n] = v
    elif m := undef_rx.match(line):
        vars[m.group(1)] = 0

सूची बोध को सरल बनाना एक सूची की समझ, स्थिति को कैप्चर करके कुशलता से मैप और फ़िल्टर कर सकता है:

results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]

इसी तरह, मुख्य अभिव्यक्ति के भीतर एक उपसंचाई का पुन: उपयोग किया जा सकता है, इसे पहले उपयोग पर एक नाम देकर:

stuff = [[y := f(x), x/y] for x in range(5)]

ध्यान दें कि दोनों स्थितियों में चर y युक्त स्कोप (यानी परिणाम या सामान के समान स्तर पर) में बद्ध है।

स्थिति मान कैप्चर करना असाइनमेंट अभिव्यक्तियों का उपयोग इफ़र या स्टेटमेंट के हेडर में अच्छे प्रभाव के लिए किया जा सकता है:

# Loop-and-a-half
while (command := input("> ")) != "quit":
    print("You entered:", command)

# Capturing regular expression match objects
# See, for instance, Lib/pydoc.py, which uses a multiline spelling
# of this effect
if match := re.search(pat, text):
    print("Found:", match.group(0))
# The same syntax chains nicely into 'elif' statements, unlike the
# equivalent using assignment statements.
elif match := re.search(otherpat, text):
    print("Alternate found:", match.group(0))
elif match := re.search(third, text):
    print("Fallback found:", match.group(0))

# Reading socket data until an empty string is returned
while data := sock.recv(8192):
    print("Received data:", data)

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

कांटा निम्न-स्तरीय UNIX दुनिया से एक उदाहरण है:

if pid := os.fork():
    # Parent code
else:
    # Child code

मूल उत्तर

http://docs.python.org/tutorial/datastructures.html

ध्यान दें कि पायथन में, सी के विपरीत, असाइनमेंट अभिव्यक्तियों के अंदर नहीं हो सकता है। सी प्रोग्रामर इस बारे में बड़बड़ा सकते हैं, लेकिन यह सी कार्यक्रमों में सामने आने वाली समस्याओं के एक सामान्य वर्ग से बचता है: टाइपिंग = एक अभिव्यक्ति में == जब इरादा था।

और देखें:

http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm


मुझे यह उत्तर पसंद है क्योंकि यह वास्तव में इंगित करता है कि इस तरह के "फ़ीचर" को जानबूझकर पायथन से क्यों छोड़ा गया हो सकता है। शुरुआत की प्रोग्रामिंग सिखाते समय, मैंने कई बार इस गलती को देखा है, if (foo = 'bar')जबकि मूल्य का परीक्षण करना चाहते हैं foo।
— जोनाथन

2
@ जोनाथनक्रॉस, यह "फीचर" वास्तव में 3.8 में जोड़ा जाएगा। इसे शायद ही कभी इस्तेमाल करने की संभावना नहीं है क्योंकि यह होना चाहिए - लेकिन कम से कम यह एक सादा नहीं है=
— जॉन ला रोय

@ जॉनलोय: उदाहरणों को देखते हुए, मुझे लगता है कि "जितना संभव हो उतना कम इस्तेमाल होने की संभावना नहीं है" यह स्पॉट-ऑन था; ~ 10 उदाहरणों में से, मुझे लगता है कि केवल दो वास्तव में कोड में सुधार करते हैं। (अर्थात्, थोड़ी देर की स्थिति में एकमात्र अभिव्यक्ति के रूप में, लाइन को डुप्लिकेट करने के लिए या शरीर में लूप की स्थिति से बचने के लिए, या नेस्टिंग से बचने के लिए एक एलिफ-चेन में)
— एलेक्सी तोरहामो

39

नहींं, BDFL उस सुविधा को पसंद नहीं करता था।

जहां से मैं बैठता हूं, गुइडो वैन रोसुम, "बेनेवोलेंट डिक्टेटर फॉर लाइफ", ने अजगर को जितना हो सके उतना आसान रखने के लिए कड़ा संघर्ष किया है। हम उनके द्वारा किए गए कुछ फैसलों से वंचित कर सकते हैं - मैंने पसंद किया होगा 'मैंने कहा' 'अधिक बार। लेकिन यह तथ्य कि पायथन को डिजाइन करने वाली समिति नहीं रही है, लेकिन एक भरोसेमंद "सलाहकार बोर्ड", जो काफी हद तक योग्यता के आधार पर है, एक डिजाइनर की संवेदनाओं को छानकर , एक अच्छी भाषा का एक नरक, IMHO का उत्पादन किया है।


15
सरल? यह सुविधा मेरे कुछ कोड को सरल बना सकती है क्योंकि यह इसे और अधिक कॉम्पैक्ट बना सकता है और अधिक पठनीय है। अब मुझे दो लाइनों की आवश्यकता है जहां मुझे एक की आवश्यकता थी। मुझे कभी यह बात नहीं मिली कि पायथन ने अन्य प्रोग्रामिंग भाषाओं को कई सालों तक (और अक्सर बहुत अच्छे कारण के लिए) क्यों अस्वीकार किया। विशेष रूप से इस विशेषता के बारे में हम यहाँ बात कर रहे हैं, बहुत उपयोगी है।
— रेगिस मई

6
कम कोड हमेशा सरल या पढ़ने योग्य नहीं होता है। उदाहरण के लिए एक पुनरावर्ती कार्य करें। यह लूप-समतुल्य अधिक पठनीय है।
— FMF

1
मुझे इसका C संस्करण पसंद नहीं है, लेकिन मुझे वास्तव में जंग की तरह कुछ याद आ रहा है, if letजब मेरे पास एक if elif श्रृंखला है, लेकिन प्रत्येक मामले में स्थिति के मूल्य को संग्रहीत और उपयोग करने की आवश्यकता है।
— थायने जूल

1
मुझे यह कहना होगा कि मैं अब जो कोड लिख रहा हूं (जिस कारण से मैंने इस मुद्दे को खोजा) वह इस सुविधा के बिना बहुत खराब है। इसके बजाय अगर बहुत सारे आईएफ के बाद उपयोग किया जाता है, तो मुझे अगले को इंडेंट करने की आवश्यकता है अगर पिछले किसी और के तहत।
— माइककूल

17

सीधे नहीं, मेरी इस पुरानी रेसिपी के अनुसार - लेकिन जैसा कि रेसिपी कहती है कि शब्दार्थ समतुल्य का निर्माण करना आसान है, उदाहरण के लिए यदि आपको सी-कोडेड रेफरेंस अल्गोरिदम से सीधे ट्रांसलेट करने की आवश्यकता है (अधिक-मुहावरेदार पाइथन को रिफैक्ट करने से पहले); -)। अर्थात:

class DataHolder(object):
    def __init__(self, value=None): self.value = value
    def set(self, value): self.value = value; return value
    def get(self): return self.value

data = DataHolder()

while data.set(somefunc()):
  a = data.get()
  # use a

BTW, आपके विशिष्ट मामले के लिए एक बहुत ही मुहावरेदार रूप है, यदि आप जानते हैं कि फालिश मूल्य क्या somefuncहो सकता है जब वह एक फालिश मूल्य (जैसे 0) लौटाता है ,

for a in iter(somefunc, 0):
  # use a

तो इस विशिष्ट मामले में रिफैक्टरिंग बहुत आसान होगा ;-)।

वापसी हो सकता है किसी भी falsish मूल्य की तरह (0, None, '', ...), एक संभावना है:

import itertools

for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
    # use a

लेकिन आप एक साधारण कस्टम जनरेटर पसंद कर सकते हैं:

def getwhile(func, *a, **k):
    while True:
      x = func(*a, **k)
      if not x: break
      yield x

for a in getwhile(somefunc):
    # use a

अगर मैं ऐसा कर सकता हूं तो मैं इसे दो बार वोट करूंगा। यह उन समय के लिए एक महान समाधान है जब इस तरह की चीज की वास्तव में आवश्यकता होती है। मैंने आपके समाधान को एक रेगेक्स माचिस वर्ग के लिए अनुकूलित किया, जो कि एक बार और फिर .चेक () का उपयोग किया जाता है यदि कथन में .result () का उपयोग उसके शरीर के अंदर किया जाता है, तो मैच को पुनः प्राप्त करने के लिए, यदि एक था। धन्यवाद! :)
— Teekin

16

हां, लेकिन केवल पायथन 3.8 और उसके बाद से।

PEP 572 असाइनमेंट एक्सप्रेशंस का प्रस्ताव करता है और पहले ही स्वीकार कर लिया गया है।

PEP के सिंटैक्स और शब्दार्थ भाग का उद्धरण :

# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match

# A loop that can't be trivially rewritten using 2-arg iter()
while chunk := file.read(8192):
   process(chunk)

# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]

# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]

आपके विशिष्ट मामले में, आप लिख पाएंगे

if a := some_func():
    # Use a

5

नहीं, पायथन में असाइनमेंट एक कथन है, एक अभिव्यक्ति नहीं है।


और Guido यह किसी भी अन्य तरीका नहीं होगा।
— मार्क रैनसम

1
@ मर्करांसोम ऑल गीलो। सही .. आहें।
— StephenBoesch

@javadba आदमी गलत होने की तुलना में अक्सर अधिक सही रहा है। मैं इस बात की सराहना करता हूं कि समिति द्वारा डिजाइन की तुलना में दृष्टि के प्रभारी एक व्यक्ति के पास एक अधिक सुसंगत रणनीति है; मैं सी ++ के साथ तुलना और इसके विपरीत कर सकता हूं जो मेरी मुख्य रोटी और मक्खन है।
— मार्क रैनसम

मुझे लगता है कि रूबी और स्कैला दोनों (अलग-अलग भाषाएं) इसे अजगर की तुलना में सही रूप से ठीक करती हैं: लेकिन किसी भी मामले में यहां जगह नहीं है ..
— स्टीफनबॉश

4

पायथन 3.8 नई सुविधा के लिए धन्यवाद , इस संस्करण से ऐसा काम करना संभव होगा, हालांकि उपयोग नहीं करना, =लेकिन एडा जैसे असाइनमेंट ऑपरेटर :=। डॉक्स से उदाहरण:

# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match

2

आप अपने लिए असाइनमेंट करने के लिए एक फ़ंक्शन को परिभाषित कर सकते हैं:

def assign(name, value):
    import inspect
    frame = inspect.currentframe()
    try:
        locals_ = frame.f_back.f_locals
    finally:
        del frame 
    locals_[name] = value
    return value

if assign('test', 0):
    print("first", test)
elif assign('xyz', 123):
    print("second", xyz)

1

असाइनमेंट की शर्तों में अवैध होने के कारणों में से एक यह है कि गलती करना आसान है और सही या गलत असाइन करना:

some_variable = 5

# This does not work
# if True = some_variable:
#   do_something()

# This only works in Python 2.x
True = some_variable

print True  # returns 5

पायथन में 3 ट्रू और गलत कीवर्ड हैं, इसलिए अब कोई जोखिम नहीं है।


1
[१६१] में: l_empty == [] बाहर [१६१]: सच में [१६२]: [] == [] बाहर [१६२]: सच मुझे नहीं लगता कि इसका कारण है
— ज्वालामुखी

बहुत यकीन है कि ज्यादातर लोग == Trueवैसे भी दाईं ओर डालते हैं ।
— नंबरमानसी

1

असाइनमेंट ऑपरेटर - जिसे अनौपचारिक रूप से वालरस ऑपरेटर के रूप में भी जाना जाता है - PEP572 में 28-फरवरी -2018 को बनाया गया था ।

पूर्णता के लिए, मैं संबंधित भागों को पोस्ट करूंगा ताकि आप 3.7 और 3.8 के बीच के अंतरों की तुलना कर सकें:

3.7
---
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
test: or_test ['if' or_test 'else' test] | lambdef
test_nocond: or_test | lambdef_nocond
lambdef: 'lambda' [varargslist] ':' test
lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*

3.8
---
if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite]
namedexpr_test: test [':=' test]                         <---- WALRUS OPERATOR!!!
test: or_test ['if' or_test 'else' test] | lambdef
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.