numbers --- کلاسهای پایه انتزاعی عددی¶
کد منبع: Lib/numbers.py
ماژول numbers (PEP 3141) سلسلهمراتبی از کلاسهای پایه انتزاعی عددی را تعریف میکند که بهتدریج عملیات بیشتری را تعریف میکنند. هیچکدام از انواع تعریفشده در این ماژول برای نمونهسازی در نظر گرفته نشدهاند.
- class numbers.Number¶
ریشهی سلسلهمراتب عددی. اگر فقط میخواهید بررسی کنید که آرگومان x یک عدد است، بدون توجه به نوع آن، از
isinstance(x, Number)استفاده کنید.
برج عددی¶
- class numbers.Complex¶
زیرکلاسهای این نوع، اعداد مختلط را توصیف میکنند و شامل عملیاتهایی میشوند که بر نوع توکار
complexاعمال میشوند. این موارد عبارتاند از: تبدیلها بهcomplexوbool،real،imag،+،-،*،/،**،abs()،conjugate()،==، و!=. همه بهجز-و!=انتزاعی هستند.- real¶
انتزاعی. کامپوننت حقیقی این عدد را بازیابی میکند.
- imag¶
انتزاعی. کامپوننت موهومی این عدد را بازیابی میکند.
- abstractmethod conjugate()¶
انتزاعی. مزدوج مختلط را برمیگرداند. برای مثال،
(1+3j).conjugate() == (1-3j).
- class numbers.Real¶
به
Complex، کلاسRealعملگرهایی را میافزاید که روی اعداد حقیقی کار میکنند.بهطور خلاصه، آنها عبارتند از: تبدیل به
float،math.trunc()،round()،math.floor()،math.ceil()،divmod()،//،%،<،<=،>، و>=.Real همچنین برای
complex()،real،imagوconjugate()پیشفرضهایی فراهم میکند.
- class numbers.Rational¶
زیرنوعی از
Realاست و ویژگیهایnumeratorوdenominatorرا میافزاید. همچنین یک پیادهسازی پیشفرض برایfloat()فراهم میکند.مقدارهای
numeratorوdenominatorباید نمونههایی ازIntegralباشند و باید در سادهترین شکل باشند، بهطوری کهdenominatorمثبت باشد.- numerator¶
انتزاعی. صورت این عدد گویا.
- denominator¶
انتزاعی. مخرج این عدد گویا.
نکاتی برای پیادهسازان نوع¶
پیادهسازان باید دقت کنند که اعداد برابر، برابر باشند و برای آنها مقادیر هش یکسانی تولید کنند. اگر دو گسترش متفاوت از اعداد حقیقی وجود داشته باشد، این موضوع ممکن است ظریف باشد. همچنین درهمسازی انواع عددی را ببینید.
Adding more numeric ABCs¶
البته، کلاسهای پایه انتزاعی (ABC) بیشتری برای اعداد امکانپذیر هستند، و این سلسلهمراتب ضعیفی خواهد بود اگر امکان افزودن آنها را از بین ببرد. میتوانید MyFoo را بین Complex و Real به این صورت اضافه کنید:
class MyFoo(Complex): ...
MyFoo.register(Real)
پیادهسازی عملیات حسابی¶
ما میخواهیم عملیات حسابی را بهگونهای پیادهسازی کنیم که عملیات حالت مختلط، یا یک پیادهسازی را فراخوانی کنند که نویسندهی آن از نوع هر دو آرگومان آگاه بوده است، یا هر دو را به نزدیکترین نوع توکار تبدیل کنند و عملیات را در آنجا انجام دهند. برای زیرنوعهای Integral، این بدان معنا است که __add__() و __radd__() باید بهصورت زیر تعریف شوند:
class MyIntegral(Integral):
def __add__(self, other):
if isinstance(other, MyIntegral):
return do_my_adding_stuff(self, other)
elif isinstance(other, OtherTypeIKnowAbout):
return do_my_other_adding_stuff(self, other)
else:
return NotImplemented
def __radd__(self, other):
if isinstance(other, MyIntegral):
return do_my_adding_stuff(other, self)
elif isinstance(other, OtherTypeIKnowAbout):
return do_my_other_adding_stuff(other, self)
elif isinstance(other, Integral):
return int(other) + int(self)
elif isinstance(other, Real):
return float(other) + float(self)
elif isinstance(other, Complex):
return complex(other) + complex(self)
else:
return NotImplemented
There are 5 different cases for a mixed-type operation on subclasses
of Complex. All of the above code that doesn't refer to
MyIntegral and OtherTypeIKnowAbout is referred to as "boilerplate".
In this description, a is an instance of A and b is an
instance of B, where A and B are both subtypes of Complex.
Consider a + b:
اگر
Aمتد__add__()را تعریف کند کهbرا بپذیرد، همهچیز درست است.اگر
Aبه کد پیشساخته متوسل شود و قرار باشد مقداری را از__add__()برگرداند، این امکان را از دست میدهیم کهB__radd__()هوشمندتری تعریف کرده باشد؛ بنابراین کد پیشساخته بایدNotImplementedرا از__add__()برگرداند. (یا ممکن استAاصلاً__add__()را پیادهسازی نکرده باشد.)سپس نوبت به
__radd__()متعلق بهBمیرسد. اگرaرا بپذیرد، همهچیز درست است.اگر به کد پیشساخته (boilerplate) بازگردد، دیگر هیچ متد ممکنی برای امتحان باقی نمانده است، بنابراین این جایی است که پیادهسازی پیشفرض باید در آن قرار داشته باشد.
If
Bis a subtype ofA, Python triesB.__radd__beforeA.__add__. This is ok, because it was implemented with knowledge ofA, so it can handle those instances before delegating toComplex.
If A is a subtype of Complex and B is a subtype of
Real without sharing any other knowledge, then the appropriate
shared operation is the one involving the built
in complex, and both __radd__() s land there, so a+b
== b+a.
از آنجا که بیشتر عملیات روی هر نوع دادهای بسیار مشابه خواهد بود، تعریف یک تابع کمکی که نمونههای مستقیم و معکوس هر عملگر معین را تولید میکند، میتواند مفید باشد. برای مثال، fractions.Fraction از این روش استفاده میکند:
def _operator_fallbacks(monomorphic_operator, fallback_operator):
def forward(a, b):
if isinstance(b, (int, Fraction)):
return monomorphic_operator(a, b)
elif isinstance(b, float):
return fallback_operator(float(a), b)
elif isinstance(b, complex):
return fallback_operator(complex(a), b)
else:
return NotImplemented
forward.__name__ = '__' + fallback_operator.__name__ + '__'
forward.__doc__ = monomorphic_operator.__doc__
def reverse(b, a):
if isinstance(a, Rational):
# Includes ints.
return monomorphic_operator(a, b)
elif isinstance(a, Real):
return fallback_operator(float(a), float(b))
elif isinstance(a, Complex):
return fallback_operator(complex(a), complex(b))
else:
return NotImplemented
reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
reverse.__doc__ = monomorphic_operator.__doc__
return forward, reverse
def _add(a, b):
"""a + b"""
return Fraction(a.numerator * b.denominator +
b.numerator * a.denominator,
a.denominator * b.denominator)
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
# ...