python - पायथन में ऑपरेटर ओवरलोडिंग: मापदंडों के विभिन्न प्रकारों और आदेशों को नियंत्रित करना
class operator-overloading (2)
आपको __rmul__
को भी लागू __rmul__
जब शुरुआती कॉल को int.__mul__(7, v)
विफल रहता है, तो पायथन अगले type(v).__rmul__(v, 7)
प्रयास करेगा type(v).__rmul__(v, 7)
।
def __rmul__(self, lhs):
return self * lhs # Effectively, turn 7 * v into v * 7
जैसा कि रॉइंग बताते हैं, आप इस परिभाषा के लिए बस __rmul__ = __mul__
लिख सकते हैं। __rmul__
गैर-कम्यूटेटिक गुणन के लिए अनुमति देने के लिए मौजूद है जहां बस __mul__
को उलट कर दिया गया ऑपरेंड के साथ पर्याप्त नहीं है।
उदाहरण के लिए, यदि आप Matrix
क्लास लिख रहे थे और नेस्टेड सूची द्वारा गुणा समर्थन करना चाहते थे, उदाहरण के लिए,
m = Matrix(...) # Some 2 x 2 matrix
n = [[1, 2], [3,4]]
p = n * m
यहां, list
वर्ग को Matrix
आवृत्ति से एक सूची के बारे में कितनी जानकारी नहीं होगी, इसलिए जब list.__mul__(n, m)
विफल हो जाती है, तो अजगर Matrix.__rmul__(m, n)
प्रयास करेगा Matrix.__rmul__(m, n)
। हालांकि, n * m
और m * n
सामान्य रूप से दो अलग-अलग परिणाम होते हैं, इसलिए Matrix.__rmul__(m, n) != Matrix.__mul__(m, n)
; सही उत्तर उत्पन्न करने के लिए __rmul__
को थोड़ा अतिरिक्त काम करना है।
इस सवाल का पहले से ही उत्तर दिया गया है:
- पायथन कम्यूटेटिक ऑपरेटर 1 जवाब ओवरराइड
मेरे पास एक साधारण वर्ग है जो कि वैक्टर पर गणितीय संचालन (संख्याओं की सूची) के साथ मदद करता है। मेरे Vector
को Vector
या एक स्केलर ( float
या int
) के अन्य उदाहरणों से गुणा किया जा सकता है
दूसरे में, अधिक जोरदार टाइप किया गया, भाषाओं में मैं दो vector
को गुणा करने के लिए एक विधि बनाऊँगा और एक vector
द्वारा और int
/ float
को गुणा करने के लिए एक अलग विधि। मैं अभी भी पायथन के लिए बहुत नया हूँ और मुझे यकीन नहीं है कि मैं इसे कैसे लागू करूंगा। एकमात्र तरीका मैं यह करने का विचार कर सकता है __mul__()
ओवरराइड और आने वाले पैरामीटर की जांच कर रहा है:
class Vector(object):
...
def __mul__(self, rhs):
if isinstance(rhs, Vector):
...
if isinstance(rhs, int) or isinstance(rhs, float):
...
यहां तक कि अगर मैं इस तरह से करता हूँ, तो मुझे इस तरह एक स्केलर द्वारा Vector
को गुणा करने के लिए मजबूर किया जाएगा:
v = Vector([1,2,3])
result = v * 7
क्या होगा अगर मैं गुणा में ऑपरेंडों के क्रम को बदलना चाहता हूं?
result = 7 * v
पायथन में ऐसा करने का सही तरीका क्या है?
उलट कार्रवाई के लिए विशेष तरीके हैं:
-
__rmul__
के पीछे के लिए__mul__
- और
__radd__
लिए__add__
, - ...
इन्हें कहा जाता है कि जब बाएं हाथ के ऑपरेटर को सामान्य ऑपरेशन के लिए रिटर्न नहीं देता है (इसलिए ऑपरेशन 2 + vector_instance
पहले प्रयास करेगा: (2).__add__(vector_instance)
लेकिन अगर यह रिटर्न NotImplemented
तो vector_instance.__radd__(2)
NotImplemented
तो vector_instance.__radd__(2)
को कहा जाता है)।
हालांकि मैं अंकगणित विशेष विधियों में isinstance
चेक का उपयोग नहीं isinstance
, जो बहुत सारे कोड पुनरावृत्ति के लिए प्रेरित करेगा।
आप वास्तव में __init__
में एक विशेष मामला बना सकते हैं और स्केलर से Vector
को एक रूपांतरण लागू कर सकते हैं:
class Vector(object):
def __init__(self, x, y=None, z=None):
if y is None and z is None:
if isinstance(x, Vector):
self.x, self.y, self.z = x.x, x.y, x.z
else:
self.x, self.y, self.z = x, x, x
elif y is None or z is None:
raise ValueError('Either x, y and z must be given or only x')
else:
self.x, self.y, self.z = x, y, z
def __mul__(self, other):
other = Vector(other)
return Vector(self.x*other.x, self.y*other.y, self.z*other.z)
__rmul__ = __mul__ # commutative operation
def __sub__(self, other):
other = Vector(other)
return Vector(self.x-other.x, self.y-other.y, self.z-other.z)
def __rsub__(self, other): # not commutative operation
other = Vector(other)
return other - self
def __repr__(self):
return 'Vector({self.x}, {self.y}, {self.z})'.format(self=self)
यह अपेक्षा के अनुरूप काम करना चाहिए:
>>> 2 - Vector(1, 2, 3)
Vector(1, 0, -1)
>>> Vector(1, 2, 3) - 2
Vector(-1, 0, 1)
>>> Vector(1, 2, 3) * 2
Vector(2, 4, 6)
>>> 2 * Vector(1, 2, 3)
Vector(2, 4, 6)
ध्यान दें कि यह एक त्वरित और गंदे मसौदा था (जो कई बग हो सकता है)। मैं सिर्फ "सामान्य विचार" पेश करना चाहता था कि कैसे प्रत्येक अंकगणितीय ऑपरेशन में टाइप को विशेष आवरण के बिना हल किया जा सकता है।