लैम्ब्डा में ऑटो ट्यूपल अनपैकिंग के लिए अच्छा पायथन 3 क्या है?


92

निम्नलिखित python2 कोड पर विचार करें

In [5]: points = [ (1,2), (2,3)]

In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)

यह python3 में समर्थित नहीं है और मुझे निम्नलिखित कार्य करने हैं:

>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)

यह बहुत बदसूरत है। यदि लंबोदर एक समारोह था, तो मैं कर सकता था

def some_name_to_think_of(p):
  x, y = p
  return x*x + y*y

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

मुझे लगता है कि कम से कम लैम्बदास को फीचर को वापस जोड़ा जाना चाहिए। क्या कोई अच्छा विकल्प है?


अद्यतन: मैं उत्तर में विचार का विस्तार करने वाले निम्नलिखित सहायक का उपयोग कर रहा हूं

def star(f):
  return lambda args: f(*args)

min(points, key=star(lambda x,y: (x*x + y*y))

Update2: के लिए एक क्लीनर संस्करणstar

import functools

def star(f):
    @functools.wraps(f):
    def f_inner(args):
        return f(*args)
    return f_inner

4
संभवतः lambdaभाषा से पूरी तरह से हटा दिए जाने के बाद संभवतः उन परिवर्तनों को रिवर्स करने की संभावना है जो इसे उपयोग करने के लिए कठिन बना रहे हैं, लेकिन आप अजगर-विचारों पर पोस्ट करने का प्रयास कर सकते हैं यदि आप फीचर को वापस देखने की इच्छा व्यक्त करना चाहते हैं।
Wooble

3
मुझे यह नहीं मिलता है, लेकिन ऐसा लगता है जैसे बीडीएफएल lambdaउसी भावना से विरोध करता है जैसे वह विरोध करता है map, reduceऔर filter
क्यूड्यू

3
lambdapy3k में हटाने के लिए स्लेट किया गया था क्योंकि यह मूल रूप से भाषा पर एक दोष है। लेकिन कोई भी अनाम कार्यों को परिभाषित करने के लिए एक उचित विकल्प पर सहमत नहीं हो सकता है, इसलिए अंततः गुइडो ने हार में अपने हथियार फेंक दिए और वह यही था।
रोजी

5
अनाम फ़ंक्शन किसी भी उचित भाषा में होने चाहिए, और मुझे लैम्ब्डा पसंद है। मुझे इस तरह की बहस के बारे में पढ़ना होगा। (इसके अलावा, भले ही mapऔर filterसमझ से सबसे अच्छी जगह है, मुझे पसंद है reduce)
njzk2

13
एक चीज जिसे मैं पायथन 3 के बारे में नापसंद करता हूं ...
टाइमजैब

जवाबों:


32

नहीं, कोई दूसरा रास्ता नहीं है। आपने यह सब कवर किया। जाने का तरीका पायथन विचारों की मेलिंग सूची में इस मुद्दे को उठाना होगा , लेकिन कुछ कर्षण हासिल करने के लिए वहाँ पर बहुत बहस करने के लिए तैयार रहें।

वास्तव में, सिर्फ यह कहने के लिए नहीं कि "कोई रास्ता नहीं है", एक तीसरा तरीका लैंबडा कॉलिंग के एक और स्तर को लागू करने के लिए सिर्फ मापदंडों को प्रकट करने के लिए हो सकता है - लेकिन यह आपके दो सुझावों की तुलना में पढ़ने में अधिक अक्षम और कठिन होगा:

min(points, key=lambda p: (lambda x,y: (x*x + y*y))(*p))

पायथन 3.8 को अपडेट करें

अब तक, पायथन 3.8 अल्फ़ा 1 उपलब्ध है, और पीईपी 572- असाइनमेंट एक्सप्रेशन लागू हैं।

इसलिए, यदि कोई लंबोदर के अंदर कई भावों को निष्पादित करने के लिए एक ट्रिक का उपयोग करता है - मैं आमतौर पर ऐसा करता हूं कि एक ट्यूपल बनाकर और उसके अंतिम घटक को वापस करते हुए, यह करना संभव है:

>>> a = lambda p:(x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
>>> a((3,4))
25

एक को ध्यान में रखना चाहिए कि इस तरह का कोड शायद ही कभी पूर्ण कार्य करने की तुलना में अधिक पठनीय या व्यावहारिक होगा। फिर भी, संभव उपयोग हैं - यदि विभिन्न वन-लाइनर्स हैं जो इस पर काम करेंगे point, तो यह एक नामित नाम के लायक हो सकता है, और असाइनमेंट अभिव्यक्ति का उपयोग प्रभावी रूप से नामित करने के लिए आने वाले अनुक्रम को "कास्ट" करने के लिए किया जा सकता है:

>>> from collections import namedtuple
>>> point = namedtuple("point", "x y")
>>> b = lambda s: (p:=point(*s), p.x ** 2 + p.y ** 2)[-1]

3
और निश्चित रूप से, मैं यह उल्लेख करना भूल गया कि ऐसा करने का "एक और स्पष्ट" तरीका वास्तव में तीन पंक्तियों के फ़ंक्शन का उपयोग करना है defजो कि nme के तहत प्रश्न में उल्लेख किया गया है some_name_to_think-of
jsbueno

2
यह उत्तर अभी भी कुछ आगंतुकों को देखता है - PEP 572 कार्यान्वयन के साथ, key = lambda p: (x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
लैंबडा

1
असाइनमेंट के भाव !! मैं (सुखद रूप से) आश्चर्यचकित हूं कि उन्होंने इसे बनाया
javadba

23

Http://www.python.org/dev/peps/pep-3113/ टपल अनपैकिंग के अनुसार चले गए हैं, और 2to3उन्हें इस तरह अनुवाद करेंगे:

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

lambda (x, y): x + y

इसमें अनुवाद किया जाएगा:

lambda x_y: x_y[0] + x_y[1]

जो आपके कार्यान्वयन के लिए काफी समान है।


3
अच्छा है कि इसे लूप या समझ के लिए नहीं हटाया जाता है
बाल्की

11

मैं पायथन 2 के अनपैकिंग व्यवहार के बारे में कोई अच्छा सामान्य विकल्प नहीं जानता। यहाँ कुछ सुझाव दिए गए हैं जो कुछ मामलों में उपयोगी हो सकते हैं:

  • यदि आप एक नाम के बारे में नहीं सोच सकते हैं; कीवर्ड पैरामीटर के नाम का उपयोग करें:

    def key(p): # more specific name would be better
        x, y = p
        return x**2 + y**3
    
    result = min(points, key=key)
  • आप देख सकते हैं namedtupleकि सूची में कई स्थानों पर उपयोग किए जाने पर क्या आपका कोड अधिक पठनीय बनता है:

    from collections import namedtuple
    from itertools import starmap
    
    points = [ (1,2), (2,3)]
    Point = namedtuple('Point', 'x y')
    points = list(starmap(Point, points))
    
    result = min(points, key=lambda p: p.x**2 + p.y**3)

इस प्रश्न के सभी जवाबों के बीच, अब तक नामांकित का उपयोग करना यहां कार्रवाई का सबसे अच्छा कोर्स है। न केवल आप अपने लैम्ब्डा रख सकते लेकिन यह भी मुझे लगता है namedtuple संस्करण के बीच अंतर के रूप में अधिक पठनीय है कि lambda (x, y):और lambda x, y:पहली नजर में स्पष्ट नहीं है।
बराक अर्सलान

5

जबकि पायथन 3 में विनाशकारी तर्कों को हटा दिया गया था, इसे समझ से नहीं हटाया गया था। पायथन 3 में समान व्यवहार प्राप्त करने के लिए इसका दुरुपयोग करना संभव है। संक्षेप में, हम इस तथ्य का लाभ उठाते हैं कि सह-दिनचर्या हमें कार्यों को अंदर बाहर करने की अनुमति देती है, और उपज एक बयान नहीं है, और इसलिए लंबोदर के भीतर अनुमति दी जाती है।

उदाहरण के लिए:

points = [(1,2), (2,3)]
print(min(points, key=lambda y: next(x*x + y*y for x,y in (lambda a: (yield a))(y))))

एक आवरण का उपयोग करने के स्वीकृत उत्तर की तुलना में, यह समाधान तर्कों को पूरी तरह से नष्ट करने में सक्षम है, जबकि आवरण केवल पहले स्तर को नष्ट करता है। अर्थात्,

values = [(('A',1),'a'), (('B',0),'b')]
print(min(values, key=lambda y: next(b for (a,b),c in (lambda x: (yield x))(y))))

की तुलना में

values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda p: (lambda a,b: (lambda x,y: (y))(*a))(*p)))

वैकल्पिक रूप से एक भी कर सकते हैं

values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda y: next(b for (a,b),c in [y])))

या थोड़ा बेहतर है

print(min(values, key=lambda y: next(b for ((a,b),c) in (y,))))

यह केवल सुझाव देना है कि यह किया जा सकता है, और सिफारिश के रूप में नहीं लिया जाना चाहिए।


0

Cuadue सुझाव और unpacking पर आपकी टिप्पणी के आधार पर अभी भी समझ में मौजूद है, आप उपयोग कर सकते हैं numpy.argmin:

result = points[numpy.argmin(x*x + y*y for x, y in points)]

0

एक अन्य विकल्प इसे एक जनरेटर में लिखना है जो एक टपल का उत्पादन करता है जहां कुंजी पहला तत्व है। Tuples की तुलना शुरू से अंत तक की जाती है इसलिए Tuple को सबसे छोटे पहले तत्व के साथ लौटाया जाता है। फिर आप मूल्य प्राप्त करने के लिए परिणाम में अनुक्रमित कर सकते हैं।

min((x * x + y * y, (x, y)) for x, y in points)[1]

0

इस बात पर विचार करें कि क्या आपको पहली जगह में टपल को खोलना है:

min(points, key=lambda p: sum(x**2 for x in p))

या क्या आपको अनपैक करते समय स्पष्ट नामों की आपूर्ति करने की आवश्यकता है:

min(points, key=lambda p: abs(complex(*p))

0

मुझे लगता है कि बेहतर वाक्य रचना है x * x + y * y let x, y = point,let कीवर्ड को अधिक सावधानी से चुना जाना चाहिए।

डबल लैम्बडा निकटतम संस्करण है। lambda point: (lambda x, y: x * x + y * y)(*point)

यदि हम इसे उचित नाम देते हैं, तो उच्च क्रम फ़ंक्शन सहायक उपयोगी होगा।

def destruct_tuple(f):
  return lambda args: f(*args)

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