मुझे बताया गया है कि कार्यात्मक प्रोग्रामिंग में अपवादों को फेंकना और / या निरीक्षण नहीं करना चाहिए। इसके बजाय एक गलत गणना का मूल्यांकन नीचे मूल्य के रूप में किया जाना चाहिए। पायथन (या अन्य भाषाएं जो कार्यात्मक प्रोग्रामिंग को पूरी तरह से प्रोत्साहित नहीं करती हैं) में कोई भी लौट सकता है None
(या नीचे मूल्य के रूप में इलाज किया गया दूसरा विकल्प, हालांकि None
परिभाषा का सख्ती से पालन नहीं करता है) जब भी कुछ गलत होता है "शुद्ध रहें", लेकिन ऐसा करने के लिए इसलिए किसी को पहली बार में एक त्रुटि का निरीक्षण करना होगा, अर्थात
def fn(*args):
try:
... do something
except SomeException:
return None
क्या इससे पवित्रता का उल्लंघन होता है? और यदि ऐसा है, तो क्या इसका मतलब है, कि पाइथन में त्रुटियों को शुद्ध रूप से संभालना असंभव है?
अद्यतन करें
एरिक लिपर्ट ने अपनी टिप्पणी में मुझे एफपी में अपवादों का इलाज करने का एक और तरीका याद दिलाया। हालाँकि मैंने कभी नहीं देखा है कि अभ्यास में पायथन में किया गया था, मैंने एक साल पहले एफपी का अध्ययन किया था तब मैंने इसके साथ खेला था। यहां कोई भी optional
निर्दिष्ट फ़ंक्शन Optional
मान लौटाता है, जो सामान्य आउटपुट के साथ-साथ अपवादों की निर्दिष्ट सूची के लिए खाली हो सकता है (अनिर्दिष्ट अपवाद अभी भी निष्पादन समाप्त कर सकते हैं)। Carry
एक विलंबित मूल्यांकन बनाता है, जहां प्रत्येक चरण (विलंबित फ़ंक्शन कॉल) या तो Optional
पिछले चरण से एक गैर-रिक्त आउटपुट प्राप्त करता है और बस इसे पास करता है, या अन्यथा एक नया पास करने का मूल्यांकन करता है Optional
। अंत में अंतिम मूल्य या तो सामान्य है या Empty
। यहां try/except
ब्लॉक एक डेकोरेटर के पीछे छिपा हुआ है, इसलिए निर्दिष्ट अपवादों को रिटर्न प्रकार हस्ताक्षर के हिस्से के रूप में माना जा सकता है।
class Empty:
def __repr__(self):
return "Empty"
class Optional:
def __init__(self, value=Empty):
self._value = value
@property
def value(self):
return Empty if self.isempty else self._value
@property
def isempty(self):
return isinstance(self._value, BaseException) or self._value is Empty
def __bool__(self):
raise TypeError("Optional has no boolean value")
def optional(*exception_types):
def build_wrapper(func):
def wrapper(*args, **kwargs):
try:
return Optional(func(*args, **kwargs))
except exception_types as e:
return Optional(e)
wrapper.__isoptional__ = True
return wrapper
return build_wrapper
class Carry:
"""
>>> from functools import partial
>>> @optional(ArithmeticError)
... def rdiv(a, b):
... return b // a
>>> (Carry() >> (rdiv, 0) >> (rdiv, 0) >> partial(rdiv, 1))(1)
1
>>> (Carry() >> (rdiv, 0) >> (rdiv, 1))(1)
1
>>> (Carry() >> rdiv >> rdiv)(0, 1) is Empty
True
"""
def __init__(self, steps=None):
self._steps = tuple(steps) if steps is not None else ()
def _add_step(self, step):
fn, *step_args = step if isinstance(step, Sequence) else (step, )
return type(self)(steps=self._steps + ((fn, step_args), ))
def __rshift__(self, step) -> "Carry":
return self._add_step(step)
def _evaluate(self, *args) -> Optional:
def caller(carried: Optional, step):
fn, step_args = step
return fn(*(*step_args, *args)) if carried.isempty else carried
return reduce(caller, self._steps, Optional())
def __call__(self, *args):
return self._evaluate(*args).value