時間を費やす: Pythonでは、明示的な型変換を行わなくても、さまざまな種類の数値を算術演算に直接使用できます。ただし、Pythonの数値は同じ抽象基本クラスから派生した特殊な種類のオブジェクトであるため、その「暗黙的な型変換」は他の言語とは異なる場合があります。 [前回の記事](http://mp.weixin.qq.com/s?__biz=MzUyOTk2MTcwNg==&mid=2247486538&idx=1&sn=72eb29bfd6d5079761c9752846992b64&chksm=fa584bcfcd2fc2d9415a1a1f905bd8d1e9530b9e6a889ac41f6e7d80460108b03031a807d9e1&scene=21#wechat_redirect)では、Pythonの数値の計算について説明した後、「Pythonの数値オブジェクトとは」というトピックを探求したかったので、このPEPを翻訳しました。お役に立てば幸いです。 。
PEPの元のテキスト: https://www.python.org/dev/peps/pep-3141
PEPタイトル: PEP3141-番号のタイプ階層
PEP作成者: Jeffrey Yasskin
作成日: 2007-04-23
翻訳者:猫の下のエンドウ豆@Python猫公号
PEP翻訳計画: https://github.com/chinesehuazhou/peps-cn
この提案は、数のようなクラスを表すために、抽象基本クラス(ABC)(PEP 3119)の階層構造を定義します。これは、Number:> Complex:> Real:> Rational:> Integralの階層構造を提案します。ここで、A:> Bは「AはBのスーパークラス」を意味します。この階層は、Schemeの数値タワーに触発されています。 (注釈:数値-複素数-実数-合理的な数値-整数)
数値をパラメーターとして受け取る関数は、これらの数値の属性を判別でき、数値のタイプに基づいて、つまりパラメーターのタイプに基づいて、オーバーロードできるかどうか、いつオーバーロードする必要があるかを判別できる必要があります。
たとえば、sliceではパラメータが Integrals
である必要がありますが、 math
モジュールの関数ではパラメータが Real
である必要があります。
このPEPは、一連の抽象基本クラス(抽象基本クラス)を指定し、特定のメソッドを実装するための一般的な戦略を提案します。これはPEP3119の用語を使用していますが、階層は特定のクラスのセットのシステムアプローチに意味をなすように意図されています。
標準ライブラリでの型チェックでは、特定の組み込み型ではなく、これらのクラスを使用する必要があります。
まず、人々が想像する数のタイプの漠然とした概念であるNumberクラスから始めます。このクラスはオーバーロードにのみ使用され、操作は提供しません。
classNumber(metaclass=ABCMeta): pass
複素数のほとんどの実装はハッシュ可能ですが、それに依存する必要がある場合は、明示的に確認する必要があります。この階層は可変数をサポートします。
classComplex(Number):"""Complex defines the operations that work on the builtin complex type.
In short, those are: conversion to complex,bool(),.real,.imag,+,-,*,/,**,abs(),.conjugate(),==, and !=.
If it is given heterogenous arguments, and doesn't have special
knowledge about them, it should fall back to the builtin complex
type as described below."""
@ abstractmethod
def __complex__(self):"""Return a builtin complex instance."""
def __bool__(self):"""True if self != 0."""return self !=0
@ abstractproperty
def real(self):"""Retrieve the real component ofthis number.
This should subclass Real."""
raise NotImplementedError
@ abstractproperty
def imag(self):"""Retrieve the real component ofthis number.
This should subclass Real."""
raise NotImplementedError
@ abstractmethod
def __add__(self, other):
raise NotImplementedError
@ abstractmethod
def __radd__(self, other):
raise NotImplementedError
@ abstractmethod
def __neg__(self):
raise NotImplementedError
def __pos__(self):"""Coerces self to whatever class defines the method."""
raise NotImplementedError
def __sub__(self, other):return self +-other
def __rsub__(self, other):return-self + other
@ abstractmethod
def __mul__(self, other):
raise NotImplementedError
@ abstractmethod
def __rmul__(self, other):
raise NotImplementedError
@ abstractmethod
def __div__(self, other):"""a/b; should promote to float or complex when necessary."""
raise NotImplementedError
@ abstractmethod
def __rdiv__(self, other):
raise NotImplementedError
@ abstractmethod
def __pow__(self, exponent):"""a**b; should promote to float or complex when necessary."""
raise NotImplementedError
@ abstractmethod
def __rpow__(self, base):
raise NotImplementedError
@ abstractmethod
def __abs__(self):"""Returns the Real distance from 0."""
raise NotImplementedError
@ abstractmethod
def conjugate(self):"""(x+y*i).conjugate() returns (x-y*i)."""
raise NotImplementedError
@ abstractmethod
def __eq__(self, other):
raise NotImplementedError
# __ ne__ is inherited from object and negates whatever __eq__ does.
Real
抽象基本クラスは、実数軸上の値を表し、組み込みの float
操作をサポートします。 NaNを除いて、実際の番号は完全に順序付けられています(このPEPは基本的にそれを考慮していません)。
classReal(Complex):"""To Complex, Real adds the operations that work on real numbers.
In short, those are: conversion to float,trunc(), math.floor(),
math.ceil(),round(),divmod(),//, %, <, <=, >, and >=.
Real also provides defaults for some of the derived operations."""
# XXX What to do about the __int__ implementation that's
# currently present on float? Get rid of it?
@ abstractmethod
def __float__(self):"""Any Real can be converted to a native float object."""
raise NotImplementedError
@ abstractmethod
def __trunc__(self):"""Truncates self to an Integral.
Returns an Integral i such that:* i>=0 iff self>0;*abs(i)<=abs(self);*for any Integral j satisfying the first two conditions,abs(i)>=abs(j)[i.e. i has "maximal" abs among those].
i.e."truncate towards 0"."""
raise NotImplementedError
@ abstractmethod
def __floor__(self):"""Finds the greatest Integral <= self."""
raise NotImplementedError
@ abstractmethod
def __ceil__(self):"""Finds the least Integral >= self."""
raise NotImplementedError
@ abstractmethod
def __round__(self, ndigits:Integral=None):"""Rounds self to ndigits decimal places, defaulting to 0.
If ndigits is omitted or None, returns an Integral,
otherwise returns a Real, preferably of the same type as
self. Types may choose which direction to round half. For
example, float rounds half toward even."""
raise NotImplementedError
def __divmod__(self, other):"""The pair(self // other, self % other).
Sometimes this can be computed faster than the pair of
operations."""
return(self // other, self % other)
def __rdivmod__(self, other):"""The pair(self // other, self % other).
Sometimes this can be computed faster than the pair of
operations."""
return(other // self, other % self)
@ abstractmethod
def __floordiv__(self, other):"""The floor() of self/other. Integral."""
raise NotImplementedError
@ abstractmethod
def __rfloordiv__(self, other):"""The floor() of other/self."""
raise NotImplementedError
@ abstractmethod
def __mod__(self, other):"""self % other
See
https://mail.python.org/pipermail/python-3000/2006-May/001735.html
and consider using "self/other - trunc(self/other)"
instead if you're worried about round-off errors."""
raise NotImplementedError
@ abstractmethod
def __rmod__(self, other):"""other % self"""
raise NotImplementedError
@ abstractmethod
def __lt__(self, other):"""< on Reals defines a total ordering, except perhaps for NaN."""
raise NotImplementedError
@ abstractmethod
def __le__(self, other):
raise NotImplementedError
# __ gt__ and __ge__ are automatically done by reversing the arguments.
# ( But __le__ is not computed as the opposite of __gt__!)
# Concrete implementations of Complex abstract methods.
# Subclasses may override these, but don't have to.
def __complex__(self):returncomplex(float(self))
@ property
def real(self):return+self
@ property
def imag(self):return0
def conjugate(self):"""Conjugate is a no-op for Reals."""return+self
Demo / classes / Rat.pyを整理し、Rational.pyにアップグレードして、標準ライブラリに追加する必要があります。次に、有理数の抽象基本クラス(Rational)を実装します。
classRational(Real, Exact):""".numerator and .denominator should be in lowest terms."""
@ abstractproperty
def numerator(self):
raise NotImplementedError
@ abstractproperty
def denominator(self):
raise NotImplementedError
# Concrete implementation of Real's conversion to float.
# ( This invokes Integer.__div__().)
def __float__(self):return self.numerator / self.denominator
最後に、整数クラス:
classIntegral(Rational):"""Integral adds a conversion to int and the bit-string operations."""
@ abstractmethod
def __int__(self):
raise NotImplementedError
def __index__(self):"""__index__() exists because float has __int__()."""returnint(self)
def __lshift__(self, other):returnint(self)<<int(other)
def __rlshift__(self, other):returnint(other)<<int(self)
def __rshift__(self, other):returnint(self)>>int(other)
def __rrshift__(self, other):returnint(other)>>int(self)
def __and__(self, other):returnint(self)&int(other)
def __rand__(self, other):returnint(other)&int(self)
def __xor__(self, other):returnint(self)^int(other)
def __rxor__(self, other):returnint(other)^int(self)
def __or__(self, other):returnint(self)|int(other)
def __ror__(self, other):returnint(other)|int(self)
def __invert__(self):return~int(self)
# Concrete implementations of Rational and Real abstract methods.
def __float__(self):"""float(self) == float(int(self))"""returnfloat(int(self))
@ property
def numerator(self):"""Integers are their own numerators."""return+self
@ property
def denominator(self):"""Integers have a denominator of 1."""return1
floatからintへの(正確にはRealからIntegralへの)正確な縮小をサポートするために、対応するライブラリ関数から呼び出すことができる次の新しい__magic__メソッドを提案します。これらのメソッドはすべて、RealではなくIntergralを返します。
バージョン2.6では、math.floor、math.ceil、およびroundは引き続き浮動小数点数を返します。
floatのint()変換は、trunc()と同等です。一般的に、int()の変換では、最初に__int __()が試行され、見つからない場合は__trunc __()が試行されます。
complex .__ {divmod、mod、floordiv、int、float} __も消えました。紛らわしいポーターを助けるために良いエラーメッセージを提供するのは良いことですが、もっと重要なことに、それはhelp(complex)に表示されません。
実装者は、等しい数を等しくし、それらを同じ値にハッシュするように注意する必要があります。実数に2つの異なる拡張子がある場合、これは微妙になる可能性があります。たとえば、複合型は次のようにhash()を合理的に実装できます。
def __hash__(self):returnhash(complex(self))
ただし、組み込みの複素数の範囲または精度を超えるすべての値に注意する必要があります。
もちろん、数字はより抽象的な基本クラスを持っているかもしれません。これらの数字を追加する可能性が除外されている場合、これは悪い階層になります。次のメソッドを使用して、ComplexとRealの間にMyFooを追加できます。
classMyFoo(Complex):...
MyFoo.register(Real)
混合モード操作で、呼び出し元が2つのパラメータータイプの処理方法を知っているか、両方が最も近い組み込みタイプに変換されてそれに応じて操作されるように、算術演算を実装したいと考えています。
Integralのサブタイプの場合、これは__add__および__radd__を次のように定義する必要があることを意味します。
classMyIntegral(Integral):
def __add__(self, other):ifisinstance(other, MyIntegral):returndo_my_adding_stuff(self, other)
elif isinstance(other, OtherTypeIKnowAbout):returndo_my_other_adding_stuff(self, other)else:return NotImplemented
def __radd__(self, other):ifisinstance(other, MyIntegral):returndo_my_adding_stuff(other, self)
elif isinstance(other, OtherTypeIKnowAbout):returndo_my_other_adding_stuff(other, self)
elif isinstance(other, Integral):returnint(other)+int(self)
elif isinstance(other, Real):returnfloat(other)+float(self)
elif isinstance(other, Complex):returncomplex(other)+complex(self)else:return NotImplemented
複雑なサブクラスでの混合型操作には、5つの異なる状況があります。 MyIntegralとOtherTypeIKnowAboutを含まない上記のすべてのコードを「ボイラープレート」と呼びます。
aはAのインスタンスであり、 Complex(a:A <:Complex)
および b:B <:Complex
のサブタイプです。 a + bの場合、私はこれを考慮します。
A <:ComplexとB <:Realに他の関係がない場合、適切な共有操作は組み込みの複合番号の操作であり、それらの__radd__が含まれているため、a + b == b + aです。 (注釈:これらの段落をあまり明確に読んでいませんでした。おそらく正しく翻訳されていませんでした)
このPEPの初期バージョンは、Haskell Numeric Preludeに触発された代数階層を定義します。これには、MonoidUnderPlus、AdditiveGroup、Ring、およびFieldが含まれ、数値を取得する前に、他のいくつかの可能な代数タイプがあります。
これがベクトルや行列を使用する人々に役立つことを当初は望んでいましたが、NumPyコミュニティは実際にはそれに興味がなく、xがX <:MonoidUnderPlusのインスタンスであり、yがY <:MonoidUnderPlusのインスタンスであっても問題が発生しました。 、X + yはまだ機能しない可能性があります。
次に、GaussianIntegerやZ / nZなど、数値の分岐構造をさらに提供します。これらは複雑になる可能性がありますが、必ずしも「除算」などの操作をサポートするとは限りません。
コミュニティは、これはPythonには複雑すぎると考えているため、提案の範囲を狭めて、Schemeデジタルタワーに近づけます。
筆者との協議の結果、現時点ではデジタルタワーの一部としてデシマルタイプを使用しないことを決定しました。
1、 抽象基本クラスの概要:http://www.python.org/dev/peps/pep-3119/
2、 Python 3クラスツリーかもしれませんか? Bill JanssenのWikiページ:http://wiki.python.org/moin/AbstractBaseClasses
3、 NumericPrelude:数値型クラスの実験的な代替階層:http://darcs.haskell.org/numericprelude/docs/html/index.html
4、 スキームデジタルタワー:https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_8.html#SEC50
(注釈:翻訳後、「PEP中国語翻訳プロジェクト」に翻訳が含まれていて、翻訳の一部が同じではないことがわかりました。読者はクリックして元のテキストを読み、比較して読むことができます。)
最初にこのPEPの作成を勧めてくれたニール・ノーウィッツ、厄介なコミュニティは代数の概念をあまり気にしていないことを指摘してくれたトラビス・オリファント、スキームがそれを行ったことを思い出させてくれたアラン・アイザック、そしてこのセットの改善を支援してくれたメールグループのギド・ヴァン・ロッサムなどに感謝します。概念。
ドキュメントはパブリックドメインに配置されました。
ソースファイル:https://github.com/python/peps/blob/master/pep-3141.txt
Recommended Posts