পাইথন মাল্টি-লাইন ল্যাম্বডাসকে অনুমতি দেয় না কেন?


50

বিডিএফএল কেন পাইথন ল্যাম্বডাসকে একক লাইন বানাতে বেছে নিয়েছে তার কোনও নিখুঁত কারণ ব্যাখ্যা করতে পারেন?

এটা ভাল:

lambda x: x**x

এটি একটি ত্রুটিতে ফলাফল:

lambda x:
    x**x

আমি বুঝতে পারি যে ল্যাম্বডা মাল্টি-লাইন তৈরি করা কোনওভাবেই স্বাভাবিক ইনডেন্টেশন নিয়মগুলিকে "বিঘ্নিত" করবে এবং আরও ব্যতিক্রম যুক্ত করার প্রয়োজন হবে, তবে এটি কি সুবিধার জন্য উপযুক্ত নয়?

উদাহরণস্বরূপ জাভাস্ক্রিপ্ট দেখুন। কীভাবে এই অজ্ঞাতনামা কাজগুলি ছাড়া কেউ বাঁচতে পারে? তারা অনিবার্য। পাইথনিস্টরা কি যুক্তি হিসাবে পাস করার জন্য প্রতিটি বহু-লাইন ক্রিয়াকলাপের নামকরণ থেকে মুক্তি পেতে চান না?


3
আপনি কেন গুডো একাধিক-এক্সপ্রেশন ল্যাম্বডাসকে মঞ্জুরি দেয় না এবং তারপরে তাদের বরখাস্ত করার সুনির্দিষ্ট কারণগুলি লক্ষ্য করে তা বিবেচনা করে, আমি ধরে নিচ্ছি যে আপনি সত্যিকারের উত্তরের চেয়ে বৈধতা চাইছেন।
জেসন বেকার

3
সাতটি চরিত্র সংরক্ষণ ছাড়াও এটি কোনওর চেয়ে ভাল কীভাবে def? এটিতে এখন ঠিক একই ভিজ্যুয়াল কাঠামো রয়েছে।
স্পষ্টত

উত্তর:


42

গিডো ভ্যান ভ্যান রসুম নিজেই এর উত্তর দিয়েছেন:

তবে এই জাতীয় সমাধানগুলিতে প্রায়শই "পাইথোনিসিটির" ঘাটতি থাকে - এটি একটি ভাল পাইথন বৈশিষ্ট্যের অধরা বৈশিষ্ট্য। পাইথোনিসিটিকে একটি শক্ত প্রতিবন্ধকতা হিসাবে প্রকাশ করা অসম্ভব। এমনকি পাইথনের জেন পাইথোনিসিটির একটি সাধারণ পরীক্ষায় অনুবাদ করে না ...

উপরের উদাহরণে, প্রস্তাবিত সমাধানের অ্যাকিলিস হিল সন্ধান করা সহজ: ডাবল কোলন, যদিও প্রকৃতপক্ষে সিন্ট্যাক্টিকভাবে দ্ব্যর্থহীন ("ধাঁধার প্রতিবন্ধকতাগুলির মধ্যে একটি") সম্পূর্ণ নির্বিচারে এবং পাইথনের অন্য কোনও কিছুর সাথে সাদৃশ্যপূর্ণ নয় ...

তবে আমি সেটিকেও প্রত্যাখ্যান করছি, কারণ শেষ পর্যন্ত (এবং এটিই আমি অনাহুতভাবে দাখিলকারীকে বিভ্রান্ত করার স্বীকার করেছি) আমি এমন কোনও সমাধান পাই যা গ্রহণযোগ্য নয় যা অভিব্যক্তির মাঝখানে একটি ইন্ডেন্টেশন-ভিত্তিক ব্লক এম্বেড করে। যেহেতু আমি বিবৃতি গোষ্ঠীকরণের জন্য বিকল্প বাক্য গঠন (যেমন ব্রেসেস বা শুরু / শেষ কীওয়ার্ডগুলি) সমানভাবে গ্রহণযোগ্য নয়, তাই এটি বেশিরভাগ ক্ষেত্রে একটি বহু-লাইন ল্যাম্বডাকে একটি অবিশ্বাস্য ধাঁধা তৈরি করে।

http://www.artima.com/weblogs/viewpost.jsp?thread=147358

মূলত, তিনি বলেছেন যে সমাধান সম্ভব হলেও এটি পাইথন কীভাবে তা একত্রিত নয়।


2
থ্রেড লিঙ্কটির জন্য +1 ধন্যবাদ - তবে আমি এখনও বহু-লাইন ল্যাম্বডাসের প্রশংসা করব - তারা অমূল্য - জাভাস্ক্রিপ্ট দেখুন, পিএইচপি সেগুলিও অন্তর্ভুক্ত করেছে।
বিশ্বাসঘাতক

2
@ গ্রিনজিট আপনি কেবল নেস্টেড ডিএফ ব্যবহার করতে পারেন। এটি বেনাম ফাংশনগুলির মতো নয়, তবে তারা যথেষ্ট পরিমাণে কাছে রয়েছে।
জাস্টারবার্গ

2
আর্গুমেন্ট হিসাবে ফাংশনগুলি পাস করার সময় নেস্টেড ডিফগুলি সহায়তা করে না - এটিই এক কারণ যা আমি বহু-লাইন মেষশাবক পছন্দ করি
বিশ্বাসঘাতক

1
@ গ্রিনজিট - আমি মনে করি আপনি এখানে আপনার মন্তব্য পোস্ট করার চেয়ে GvR এর সাথে এটি গ্রহণ করা ভাল।
জেসন বেকার

9
@ গ্রিনজিট: আপনি কি জানেন যে আপনি অন্য ফাংশনের যুক্তি হিসাবে ফাংশনটি পাস করতে পারবেন? আপনি এটিকে ইনলাইন লিখতে পারবেন না, তবে এমন কোনও প্রোগ্রামিং প্রযুক্তি নেই যা আপনার কাছে উপলভ্য নয়।
btilly

24

পাইথনে মাল্টি লাইন ল্যাম্বদা করা পুরোপুরি ঠিক: দেখুন

>>> f = lambda x: (
...   x**x)
>>> f
<function <lambda> at 0x7f95d8f85488>
>>> f(3)
27

আসল ল্যাম্বডা সীমাবদ্ধতা হ'ল লাম্বদা অবশ্যই একক প্রকাশ হতে পারে ; এটা শব্দ (python2 মত ধারণ করে না পারেন printবা return)।

জিভিআর ল্যাম্বডার আকার সীমাবদ্ধ করতে এটি করা বেছে নেয়, কারণ তারা সাধারণত পরামিতি হিসাবে ব্যবহৃত হয়। আপনি যদি আসল ফাংশন চান তবে ব্যবহার করুনdef


1
মাল্টি লাইন 'character n' অক্ষর সন্নিবেশ সম্পর্কে: ডি পাইথনটির বহু বিবৃতি লাম্বদা নেই। আপনি সত্যিই ব্যবহার করতে চান def। এটি সম্পর্কে চিন্তা করুন: আপনার ফাংশনটির প্যারামিটার হিসাবে আপনাকে সত্যই কল করতে হবে? এবং সেই ফাংশনের ব্যবহারকারীদের আপনার ডিফল্ট কলযোগ্য পাস করার অনুমতি নেই ? আপনি তাদের এটি না দিলে তারা কীভাবে এটি পাস করতে পারে?
ভিটো ডি তুলিও

বিটিডব্লিউ, আপনি কি কোনও অনিয়মী কার্যের প্রয়োজনের উদাহরণ দিতে পারেন?
ভিটো ডি তুলিও

1
হ্যাঁ, আমি একক অভিব্যক্তিটির সীমাবদ্ধতাটি সত্যিই হতাশাবোধ করি। সত্য, তারা যদি মাল্টি-এক্সপ্রেশন ল্যাম্বডাসকে অনুমতি দেয় তবে লোকেরা অবশ্যই এটির অপব্যবহার শুরু করবে তবে অন্যভাবে খুব নিষিদ্ধ ওমো।
rbaleksandar

10

আমি জানি এটি অত্যন্ত পুরানো, তবে এখানে একটি রেফারেন্স হিসাবে রাখছি।

ল্যাম্বদা ব্যবহারের বিকল্প defএকটি অপ্রচলিত উপায়ে ব্যবহার করতে পারে । লক্ষ্যটি হ'ল defকোনও ফাংশনে একটি পাস করা , যা কেবলমাত্র এক পরিস্থিতিতে করা যেতে পারে - একটি সজ্জাকারী। লক্ষ্য করুন যে এই বাস্তবায়নটি def resultকোনও ক্রিয়াকলাপ তৈরি করে না, এটি এর ফলাফল তৈরি করে reduce(), যা একটি হিসাবে শেষ হয় dict

লজ্জাহীন প্লাগ : আমি এই অনেক কাজ এখানে

>>> xs = [('a', 1), ('b', 2), ('a', 3), ('b', 4)]
>>> foldl = lambda xs, initial: lambda f: reduce(f, xs, initial)
>>> @foldl(xs, {})
... def result(acc, (k, v)):
...     acc.setdefault(k, 0)
...     acc[k] += v
...     return acc
...
>>> result
{'a': 4, 'b': 6} 

নোট করুন যে মাল্টি-স্টেটমেন্ট ল্যাম্বডাস করা যেতে পারে তবে কেবল সত্যই, সত্যই কুরুচিপূর্ণ কোড সহ। তবে মজার বিষয়টি হল কীভাবে স্কোপিং এই প্রয়োগের সাথে কাজ করে ( nameভেরিয়েবলের একাধিক ব্যবহার এবং ভেরিয়েবলের ছায়া গোপন নোট করুন message

>>> from __future__ import print_function
>>> bind = lambda x, f=(lambda x: x): f(x)
>>> main = lambda: bind(
...     print('Enter your name.'), lambda _: bind(
...     raw_input('> '), lambda name: bind(
...     'Hello {}!'.format(name), lambda message: bind(
...     print(message), lambda _: bind(
...     'Bye {}!'.format(name), lambda message: bind(
...     print(message)
... ))))))
>>> main()
Enter your name.
> foo
Hello foo!
Bye foo!


মনডসকে জাভা স্ক্রিপ্ট বিটিডব্লিউতে ততক্ষণ বা ভবিষ্যত / প্রতিশ্রুতি এমনকি কলব্যাকও বলা হয়।
aoeu256

3

পাইরোস্পাড যেমন তৈরি করেছিলেন তেমন একটি মাল্টি-স্টেটমেন্ট ল্যাম্বডাকে একসাথে হ্যাক করা ঠিক ততটা খারাপ নয়: আমরা হ্যাস্কেলের মতো বাঁধ ব্যবহার করে একগুচ্ছ মনডাফিক ফাংশন রচনা করতে পারি , তবে যেহেতু আমরা পাইথনের অপরিষ্কার বিশ্বে রয়েছি, আমরাও সম্ভবত একই জিনিস অর্জন করতে পার্শ্ব প্রতিক্রিয়া ব্যবহার করুন।

আমি আমার ব্লগে এটি করার কয়েকটি উপায় কভার করি

উদাহরণস্বরূপ, পাইথন একটি টিউপলের উপাদানগুলিকে ক্রমে মূল্যায়ন করার গ্যারান্টি দেয়, সুতরাং আমরা ,অনেকটা অত্যাবশ্যকীয়র মতো ব্যবহার করতে পারি ;। আমরা printমতামত, মত মত অনেক বিবৃতি প্রতিস্থাপন করতে পারেন sys.stdout.write

সুতরাং নিম্নলিখিতটি সমতুল্য:

def print_in_tag_def(tag, text):
    print "<" + tag + ">"
    print text
    print "</" + tag + ">"

import sys
print_ = sys.stdout.write
print_in_tag_lambda = lambda tag, text: (print_("<" + tag + ">"),
                                         print_(text),
                                         print_("</" + tag + ">"),
                                         None)[-1]

নোট করুন যে আমি Noneশেষে একটি যুক্ত করেছি , এবং এটি ব্যবহার করে উত্তোলন করেছি [-1]; এটি সুস্পষ্টভাবে রিটার্ন মান সেট করে। আমাদের এটি করতে হবে না, তবে তা ছাড়া আমরা একটি মজাদার (None, None, None)রিটার্ন মান পেতে চাই , যা আমরা যত্ন নিতে পারি না এবং নাও পারি।

সুতরাং আমরা ক্রিয়াকলাপ IO ক্রিয়াকলাপ করতে পারেন। স্থানীয় ভেরিয়েবল সম্পর্কে কী?

পাইথন =একটি বিবৃতি গঠন করে, তাই আমাদের একটি সমতুল্য অভিব্যক্তি খুঁজে পাওয়া দরকার। একটি উপায় হ'ল একটি আর্গুমেন্ট হিসাবে পাস করা ডেটাস্ট্রাক্টের বিষয়বস্তুগুলিকে পরিবর্তন করা। উদাহরণ স্বরূপ:

def stateful_def():
    foo = 10
    bar = foo * foo
    foo = 2
    return foo + bar

stateful_lambda = (lambda state: lambda *_: (state.setdefault('foo', 10),
                                             state.setdefault('bar', state.get('foo') * state.get('foo')),
                                             state.pop('foo'),
                                             state.setdefault('foo', 2),
                                             state.get('foo') + state.get('bar'))[-1])({})

এখানে কয়েকটি কৌশল ব্যবহার করা হচ্ছে stateful_lambda:

  • *_যুক্তি আমাদের ল্যামডা নিতে পারবেন কোন আর্গুমেন্ট সংখ্যা। যেহেতু এটি শূন্য আর্গুমেন্টকে মঞ্জুরি দেয় তাই আমরা কলিং কনভেনশনটি পুনরুদ্ধার করি stateful_def
    • আর্গুমেন্ট _বলা কেবল একটি সম্মেলন যা "আমি এই পরিবর্তনশীলটি ব্যবহার করব না" বলে
  • আমাদের একটি ("মোড়ক") ফাংশন অন্য ("প্রধান") ফাংশনটি ফিরিয়ে নিয়েছে: lambda state: lambda *_: ...
    • লেজিকাল স্কোপকে ধন্যবাদ , প্রথম ফাংশনের আর্গুমেন্টটি দ্বিতীয় ফাংশনের জন্য ইন-স্কোপ হবে
    • কিছু আর্গুমেন্ট এখনই গ্রহণ করা এবং বাকিগুলি পরে মেনে নেওয়ার জন্য অন্য ক্রিয়াকলাপ ফিরিয়ে দেওয়া কারিগরি হিসাবে পরিচিত
  • আমরা অবিলম্বে "র‍্যাপার" ফাংশনটিকে কল করি, এটি একটি খালি অভিধানটি পাস করে: (lambda state: ...)({})
    • এটি আমাদের একটি অ্যাসাইনমেন্ট স্টেটমেন্ট (উদাহরণস্বরূপ ) ব্যবহার না করে stateএকটি মানকে একটি ভেরিয়েবল বরাদ্দ করতে দেয়{}state = {}
  • আমরা কী এবং মানগুলিকে stateভেরিয়েবল নাম এবং সীমাবদ্ধ মান হিসাবে বিবেচনা করি
    • এটি তাত্ক্ষণিক-বলা ল্যাম্বডাস ব্যবহারের চেয়ে কম জটিল
    • এটি আমাদেরকে ভেরিয়েবলের মানগুলি পরিবর্তন করতে দেয়
    • আমরা state.setdefault(a, b)পরিবর্তে a = bএবং state.get(a)পরিবর্তে ব্যবহার করিa
  • আমরা আগের মত আমাদের পার্শ্ব প্রতিক্রিয়াগুলি এক সাথে শৃঙ্খলাবদ্ধ করতে একটি টুপল ব্যবহার করি
  • আমরা [-1]সর্বশেষ মানটি বের করতে ব্যবহার করি , যা returnবিবৃতিটির মতো কাজ করে

অবশ্যই এটি বেশ জটিল, তবে আমরা সহায়ক ফাংশনগুলির সাহায্যে একটি সুন্দর এপিআই তৈরি করতে পারি:

# Keeps arguments and values close together for immediately-called functions
callWith = lambda x, f: f(x)

# Returns the `get` and `setdefault` methods of a new dictionary
mkEnv = lambda *_: callWith({},
                            lambda d: (d.get,
                                       lambda k, v: (d.pop(k), d.setdefault(k, v))))

# A helper for providing a function with a fresh `get` and `setdefault`
inEnv = lambda f: callWith(mkEnv(), f)

# Delays the execution of a function
delay = lambda f x: lambda *_: f(x)

# Uses `get` and `set`(default) to mutate values
stateful_lambda = delay(inEnv, lambda get, set: (set('foo', 10),
                                                 set('bar', get('foo') * get('foo')),
                                                 set('foo', 2),
                                                 get('foo') + get('bar'))[-1])

আপনি কি মজা করছেন, এটি এক দুঃস্বপ্নের মতো দেখাচ্ছে
আলেকজান্ডার মিলস

1
@AlexanderMills হেহ, এই একটি বাস্তব জগতের উদাহরণ হিসাবে, pyrospade এর lambdas-ইন-lambdas-ইন-lambdas পদ্ধতির একটি অপ্রমাণ আরো দেখাতে হবে যে জিনিষ না দেয়ার উদ্দেশ্যে করা হয়নি, যে খারাপ। আসলে, এটি এখন আরও সরল করা যেতে পারে যে আমরা পাইথন.আর
দেবদেব /

1

আমি যদিও অবদান রাখতে পারতাম, একটি লাইন ব্রেকার ব্যবহার করুন:

x = lambda x,y: x-y if x<y \ 
                     else y-x if y<x \
                     else 0

উদাহরণস্বরূপ, পাইথন অনলাইনারদের লিখতে সক্ষম এমন খুব সুন্দর জিনিসটি ভুলে যাবেন না:

a=b=0; c=b+a; d = a+b**2 #etc etc

এবং ল্যাম্বদা খুব শক্তিশালী, তবে এটি 1 টি পুরো ফাংশনটির বিকল্প হিসাবে বোঝানো হয়নি, আমি আপনাকে বোঝাতে চাইছি এটি এটিকে হ্যাক করতে পারে (উপরের সহকর্মীর কাছ থেকে উদাহরণ ধার করে):

makeTag = lambda tagName: "<{}>".format(tagName)
closeTag = lambda tagName: makeTag("/"+str(tagName))
openTag = lambda tagName: makeTag(tagName)
writeHMTLline = lambda tag,content: ""+opetTag(tag)+str(content)+closeTag(tag)

তবে আপনি কি সত্যিই এটির মতো করতে চান? এটি বেশিরভাগ সময় অপঠনযোগ্য কিছু সময়ের পরে, এটি দাগের গোছা থেকে শুরু করে দেওয়ালহীন প্রান্ত দিয়ে শুরু করার মতো। অবারিত দড়ি

ল্যাম্বডাস ফাংশনাল ওরিয়েন্টেড প্রোগ্রামিং (অন্যান্য বিষয়গুলির মধ্যে) এর ফাংশনগুলিকে ফিল্টার করে এবং হ্রাস করে, একক-একমাত্র ফাংশন হিসাবে কাজ করে। উদাহরণস্বরূপ 2 টি দ্বারা পূর্ণসংখ্যা এবং বিভাজ্য মানগুলির অক্ষরের মানগুলি পাওয়া

chrDev2 = lambda INT: chr(INT) if isinstance(INT,int) and INT%2==0 else INT
someStringList = map( chrDev2, range(30) )
>>> ['\x00', 1, '\x02', 3, '\x04', 5, '\x06', 7, '\x08', 9, '\n', 11, '\x0c', 13, '\x0e', 15, '\x10', 17, '\x12', 19, '\x14', 21, '\x16', 23, '\x18', 25, '\x1a', 27, '\x1c', 29]

আপনি জটিল ফাংশন (বা আরও এবং আরও বেশ কয়েকটি ল্যাম্বডাস ডিফিনেশন করে এবং অন্য ল্যাম্বডায় রেখে) ফাংশন এক্সপ্রেশন ফাংশন হিসাবে এটি ব্যবহার করতে পারেন:

def someAnon(*args): return sum(list(args))
defAnon = lambda list: [ x*someAnon(*list) for x in list]

তবে পাইথনের ফাংশনের এক্সপ্রেশন সমর্থন রয়েছে অন্যভাবে: -রলেটস বলে যে আপনার কাছে কিছু ফাংশন বলা হয়েছে superAwesomeFunctionএবং সেই ফাংশনটি কিছু দুর্দান্ত ভয়ঙ্কর স্টাফ করতে পারে, আপনি এটিকে কল না করে এটি একটি ভেরিয়েবলের কাছে বরাদ্দ করতে পারেন:

SAF = superAwesomeFunction # there is no () at the end, 

সুতরাং এখন আপনি যখন SAF কল করবেন তখন আপনি সুপারআওউজফিউশন বা পদ্ধতিটি কল করবেন। আপনি যদি আপনার লিবি ফোল্ডারটি গর্তটি অনুসন্ধান করেন তবে দেখতে পাবেন বেশিরভাগ পাইথন __builtin__মডিউলগুলি সেভাবে লেখা হয়েছিল। এটি করা হয় কারণ কখনও কখনও আপনার কিছু ফাংশন প্রয়োজন যা নির্দিষ্ট টাস্ক করে যা ব্যবহারকারীর দ্বারা ব্যবহারযোগ্য হওয়ার পক্ষে যথেষ্ট নয় তবে এটি বেশ কয়েকটি ফাংশনের জন্য প্রয়োজনীয়। সুতরাং আপনার কাছে একটি পছন্দ রয়েছে যা "সুপারআউইউজুফফানশন" নাম সহ আপনার দুটি ফাংশন নাও থাকতে পারে, আপনার কাছে "সুপারআউইউজফিউজডডিংবাসিকস্টুফ" এবং "রিয়েলসুপারআউইউইজফান্শন" থাকতে পারে এবং "সুপারআউওয়াইজ ফাংশন" ভেরিয়েবলটিতে কেবল "রিয়েলসুপারআউজফিউজ ফাংশন" রেখে আপনি কাজটি সম্পন্ন করেছেন।

আপনি কনসোলে লিখে আমদানিকৃত মডিউল অবস্থান জানতে পারেন importedModule.__file__(প্রকৃত উদাহরণ import os;os.__file__), এবং শুধু যে ডিরেক্টরি নামক ফাইলে অনুসরণ importedModule.py এবং সম্পাদকে এটি খুলুন এবং কিভাবে আপনি আপনার নিজস্ব "জ্ঞান" বৃদ্ধি করতে পারেন খুঁজে।

আমি আশা করি এটি আপনাকে এবং সম্ভবত অন্যান্য সহকর্মীদের সমস্যায় সহায়তা করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.