আমি কীভাবে একটি ল্যাম্বডা এক্সপ্রেশন লিখতে পারি যা এর সমতুল্য:
def x():
raise Exception()
নিম্নলিখিত অনুমোদিত নয়:
y = lambda : raise Exception()
y=lambda...ধরে def y:তারপর?
আমি কীভাবে একটি ল্যাম্বডা এক্সপ্রেশন লিখতে পারি যা এর সমতুল্য:
def x():
raise Exception()
নিম্নলিখিত অনুমোদিত নয়:
y = lambda : raise Exception()
y=lambda...ধরে def y:তারপর?
উত্তর:
পাইথনের ত্বকের একাধিক উপায় রয়েছে:
y = lambda: (_ for _ in ()).throw(Exception('foobar'))
লাম্বদাস বিবৃতি গ্রহণ করে। যেহেতু raise exএকটি বিবৃতি, আপনি একটি সাধারণ উদ্দেশ্য রাইজার লিখতে পারেন:
def raise_(ex):
raise ex
y = lambda: raise_(Exception('foobar'))
তবে যদি আপনার লক্ষ্যটি এড়ানো defহয় তবে এটি অবশ্যই এটি কাটবে না। এটি আপনাকে শর্তসাপেক্ষে ব্যতিক্রমগুলি বাড়ানোর অনুমতি দেয়, যেমন:
y = lambda x: 2*x if x < 10 else raise_(Exception('foobar'))
বিকল্পভাবে আপনি কোনও নামকৃত কার্যকারিতা সংজ্ঞা না দিয়ে ব্যতিক্রম বাড়াতে পারেন। আপনার যা দরকার তা হ'ল শক্ত পেট (এবং প্রদত্ত কোডের জন্য 2.x):
type(lambda:0)(type((lambda:0).func_code)(
1,1,1,67,'|\0\0\202\1\0',(),(),('x',),'','',1,''),{}
)(Exception())
এবং একটি অজগর 3 শক্ত পেট দ্রবণ:
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())
একটি খুব সহজ উত্তর যদি আপনি কি দেখেন না, যা ব্যতিক্রম উত্থাপিত হয় ইশারা জন্য ধন্যবাদ @WarrenSpencer: y = lambda: 1/0।
lambda: 1 / 0। আপনি কেবলমাত্র একটি নিয়মিত ব্যতিক্রমের পরিবর্তে একটি জিরো ডিভিশনইরার নিক্ষেপ করবেন। মনে রাখবেন যে যদি ব্যতিক্রমটিকে প্রস্তাব দেওয়ার অনুমতি দেওয়া হয় তবে জিরো ডিভিশনইরিটির একটি গোছা দেখা শুরু করার জন্য আপনার কোডটি ডিবাগ করা কারও কাছে অবাক লাগবে।
y = 1/0ব্যতিক্রম প্রকার অপ্রাসঙ্গিক হলে সুপার স্মার্ট সমাধান
কেমন:
lambda x: exec('raise(Exception(x))')
SyntaxErrorপাইথন ২.7.১১ এ পেয়েছি।
আসলে, একটি উপায় আছে, কিন্তু এটি খুব স্বীকৃত।
আপনি compile()অন্তর্নির্মিত ফাংশনটি ব্যবহার করে একটি কোড অবজেক্ট তৈরি করতে পারেন । এটি আপনাকে raiseবিবৃতিটি (বা অন্য কোনও বিবৃতি, সেই বিষয়ে) ব্যবহার করতে দেয়, তবে এটি আরেকটি চ্যালেঞ্জ উত্থাপন করে: কোড অবজেক্টটি কার্যকর করে। সাধারণ উপায়টি হ'ল execস্টেটমেন্টটি ব্যবহার করা , তবে এটি আপনাকে মূল সমস্যার দিকে নিয়ে যায়, যথা আপনি কোনও lambda(বা একটিতে) বিবৃতি কার্যকর করতে পারবেন নাeval() , সেই বিষয়ে) ।
সমাধান হ্যাক হয়। lambdaস্টেটমেন্টের ফলাফলের মতো কলযোগ্যগুলির একটি বৈশিষ্ট্য রয়েছে __code__, যা আসলে প্রতিস্থাপন করা যেতে পারে। সুতরাং, আপনি যদি কলযোগ্য তৈরি করেন এবং __code__উপরের কোডের সাথে তার মানটি প্রতিস্থাপন করেন তবে আপনি এমন কিছু পাবেন যা বিবৃতি ব্যবহার না করে মূল্যায়ন করা যায়। যদিও এই সমস্ত কিছু অর্জন করা খুব অস্পষ্ট কোডের ফলাফল:
map(lambda x, y, z: x.__setattr__(y, z) or x, [lambda: 0], ["__code__"], [compile("raise Exception", "", "single"])[0]()
উপরোক্ত নিম্নলিখিতগুলি করে:
compile()কল একটি কোড বস্তু ব্যতিক্রম উত্থাপন তৈরি করে;
lambda: 0আয় একটি callable যে কিছুই না কিন্তু মান 0 আসতে - পরে উপরের কোড বস্তুর চালানো ব্যবহার করা হয়;
lambda x, y, zবাক্যটি একটি ফাংশন তৈরি করে যা __setattr__বাকী যুক্তি দিয়ে প্রথম যুক্তির পদ্ধতিটিকে কল করে এবং প্রথম যুক্তি ফিরিয়ে দেয়! এটি প্রয়োজনীয়, কারণ __setattr__নিজেই ফিরে আসে None;
map()কলের ফলাফলের লাগে lambda: 0, এবং ব্যবহার lambda x, y, zপ্রতিস্থাপিত এটা __code__ফল সঙ্গে বস্তুর compile()কল। এই মানচিত্রের ক্রিয়াকলাপের ফলাফলটি একটি এন্ট্রি সহ একটি তালিকা, সেই দ্বারা ফিরে এসেছে lambda x, y, z, যার জন্য আমাদের এটি প্রয়োজন lambda: আমরা যদি এখনই ব্যবহার করতে __setattr__পারি, তবে আমরা lambda: 0অবজেক্টের রেফারেন্সটি হারাব !
পরিশেষে, map()কলটি দিয়ে ফিরে আসা তালিকার প্রথম (এবং একমাত্র) উপাদানটি কার্যকর করা হয়, যার ফলে কোড অবজেক্ট বলা হয়, শেষ পর্যন্ত কাঙ্ক্ষিত ব্যতিক্রম উত্থাপন করে।
এটি কাজ করে (পাইথন ২.6 এ পরীক্ষিত) তবে এটি অবশ্যই সুন্দর নয়।
একটি সর্বশেষ নোট: যদি আপনার typesমডিউলে অ্যাক্সেস থাকে (যার জন্য আপনার importবিবৃতিটি আগে ব্যবহার করতে হবে eval), তবে আপনি এই কোডটি কিছুটা ছোট করতে পারেন: ব্যবহার করে types.FunctionType()আপনি একটি ফাংশন তৈরি করতে পারেন যা প্রদত্ত কোড অবজেক্টটি কার্যকর করবে, তাই আপনি জিতেছেন এর সাথে একটি ডামি ফাংশন তৈরি করতে lambda: 0এবং এর __code__বৈশিষ্ট্যের মানটি প্রতিস্থাপনের হ্যাকের দরকার নেই ।
ল্যাম্বদা ফর্মগুলির সাথে তৈরি ফাংশনগুলিতে বিবৃতি থাকতে পারে না ।
যদি আপনি চান এমন একটি ল্যাম্বডা এক্সপ্রেশন যা একটি স্বেচ্ছাচারী ব্যতিক্রম উত্থাপন করে তবে আপনি এটি একটি অবৈধ অভিব্যক্তি দিয়ে সম্পন্ন করতে পারেন। উদাহরণস্বরূপ, lambda x: [][0]খালি তালিকায় প্রথম উপাদানটি অ্যাক্সেস করার চেষ্টা করবে, যা সূচিপত্র বাড়িয়ে তুলবে।
দয়া করে নোট করুন : এটি একটি হ্যাক, কোনও বৈশিষ্ট্য নয়। এটিকে কোনও (নন-কোড-গল্ফ) কোডে ব্যবহার করবেন না যা অন্য কোনও মানুষ দেখতে বা ব্যবহার করতে পারে।
TypeError: <lambda>() takes exactly 1 positional argument (2 given)। আপনি কি ইনডেক্সেরর সম্পর্কে নিশ্চিত?
lambda *x: [][0]। (আসল সংস্করণটি কেবল একটি আর্গুমেন্ট গ্রহণ করে; কোনও যুক্তি, ব্যবহারের lambda : [][0]জন্য নয়; দুটির জন্য ব্যবহার lambda x,y: [][0]; ইত্যাদি)
lambda x: {}["I want to show this message. Called with: %s" % x] উত্পাদন:KeyError: 'I want to show this message. Called with: foo'
আমি মার্সেলো ক্যান্টোস দ্বারা প্রদত্ত উত্তরের 3 তম আপডেটের একটি ব্যাখ্যা দিতে চাই :
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())
lambda: 0builtins.functionক্লাস একটি উদাহরণ ।
type(lambda: 0)হয় builtins.functionবর্গ।
(lambda: 0).__code__একটি codeবস্তু।
একটি codeঅবজেক্ট এমন একটি বস্তু যা অন্য বিষয়গুলির মধ্যে সংকলিত বাইটকোড ধারণ করে। এটি সিপিথন https://github.com/python/cpython/blob/master/Include/code.h এ এখানে সংজ্ঞায়িত করা হয়েছে । এর পদ্ধতিগুলি এখানে https://github.com/python/cpython/blob/master/Objects/codeobject.c প্রয়োগ করা হয়েছে । আমরা কোড অবজেক্টে সহায়তা চালাতে পারি:
Help on code object:
class code(object)
| code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,
| constants, names, varnames, filename, name, firstlineno,
| lnotab[, freevars[, cellvars]])
|
| Create a code object. Not for the faint of heart.
type((lambda: 0).__code__)কোড বর্গ হয়।
সুতরাং যখন আমরা বলি
type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b'')
আমরা নিম্নলিখিত যুক্তি দিয়ে কোড অবজেক্টের কনস্ট্রাক্টরকে কল করছি:
PyCodeObject
Https://github.com/python/cpython/blob/master/Include/code.h- এর সংজ্ঞায় আর্গুমেন্টগুলির অর্থ কী তা সম্পর্কে আপনি পড়তে পারেন । flagsযুক্তির জন্য 67 এর মান উদাহরণস্বরূপCO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE ।
সর্বাধিক codestringআমদানি যুক্তিটি হ'ল নির্দেশ নির্দেশকটি থাকে contains আসুন দেখে নেওয়া যাক তাদের অর্থ কী।
>>> import dis
>>> dis.dis(b'|\0\202\1\0')
0 LOAD_FAST 0 (0)
2 RAISE_VARARGS 1
4 <0>
অপকডের ডকুমেন্টেশনটি এখানে https://docs.python.org/3.8/library/dis.html#python-bytecode-instructions পাওয়া যাবে
। প্রথম বাইটটি অপকোডের জন্য LOAD_FAST, দ্বিতীয় বাইটটি তার যুক্তিটি যেমন 0 হয়।
LOAD_FAST(var_num)
Pushes a reference to the local co_varnames[var_num] onto the stack.
সুতরাং আমরা xস্ট্যাকের উপর রেফারেন্স ধাক্কা । দ্যvarnamesশুধুমাত্র 'X ধারণকারী স্ট্রিং একটি তালিকা রয়েছে। আমরা স্ট্যাকটি যে ফাংশনটি সংজ্ঞায়িত করছি তার একমাত্র যুক্তিটিকে আমরা চাপ দেব।
পরের বাইটটি হ'ল অপকোড RAISE_VARARGSএবং পরের বাইটটি এর যুক্তি অর্থাৎ 1 1
RAISE_VARARGS(argc)
Raises an exception using one of the 3 forms of the raise statement, depending on the value of argc:
0: raise (re-raise previous exception)
1: raise TOS (raise exception instance or type at TOS)
2: raise TOS1 from TOS (raise exception instance or type at TOS1 with __cause__ set to TOS)
টিওএস হ'ল টপ-অফ-স্ট্যাক। যেহেতু আমরা xআমাদের ফাংশনের প্রথম যুক্তি ( )টিকে স্ট্যাকের দিকে ঠেলে দিয়েছি এবং argcএটি 1 হ'ল আমরা এটি উত্থাপন করব
xযদি এটি ব্যতিক্রম উদাহরণ হয় বা এর উদাহরণ তৈরি xকরে অন্যথায় উত্থাপন করি।
শেষ বাইট অর্থাৎ 0 ব্যবহার হয় না। এটি একটি বৈধ অপকোড নয়। এটি পাশাপাশি নাও থাকতে পারে।
কোড স্নিপেটে ফিরে আমরা কোনওভাবেই যাচ্ছি:
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())
আমরা কোড অবজেক্টের কনস্ট্রাক্টরকে ফোন করেছি:
type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b'')
আমরা কোনও ফাংশন অবজেক্টের কনস্ট্রাক্টরের কাছে কোড অবজেক্ট এবং একটি খালি অভিধানটি পাস করি:
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)
আর্গুমেন্টের অর্থ কী তা দেখতে একটি ফাংশন অবজেক্টে সহায়তা কল করুন।
Help on class function in module builtins:
class function(object)
| function(code, globals, name=None, argdefs=None, closure=None)
|
| Create a function object.
|
| code
| a code object
| globals
| the globals dictionary
| name
| a string that overrides the name from the code object
| argdefs
| a tuple that specifies the default argument values
| closure
| a tuple that supplies the bindings for free variables
তারপরে আমরা বিলম্বিত ফাংশনটিকে একটি ব্যাতিক্রম হিসাবে পাস করে আর্গুমেন্ট হিসাবে কল করি। ফলস্বরূপ আমরা একটি ল্যাম্বডা ফাংশন বলি যা একটি ব্যতিক্রম উত্থাপন করে। আসুন স্নিপেট চালাও এবং দেখুন যে এটি প্রকৃতপক্ষে উদ্দেশ্য হিসাবে কাজ করে।
>>> type(lambda: 0)(type((lambda: 0).__code__)(
... 1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
... )(Exception())
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
File "", line 1, in
Exception
আমরা দেখেছি বাইকোডের শেষ বাইটটি অকেজো। আসুন এই জটিল অভিব্যক্তিটি অচল করে না ফেলে। আসুন সেই বাইটটি সরান। এছাড়াও যদি আমরা কিছুটা গল্ফ করতে চাই তবে আমরা ব্যতিক্রমের তাত্ক্ষণিকতা বাদ দিতে পারি এবং পরিবর্তে একটি আর্গুমেন্ট হিসাবে ব্যতিক্রম শ্রেণিটি পাস করতে পারি। এই পরিবর্তনগুলির ফলে নিম্নলিখিত কোডের ফলাফল হবে:
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1',(),(),('x',),'','',1,b''),{}
)(Exception)
আমরা এটি চালানোর সময় আমরা আগের মতো ফলাফল পাব। এটি কেবল খাটো।