Python の古いスタイルのクラスと新しいスタイルのクラスの違いは何ですか?
-
09-06-2019 - |
質問
Python の古いスタイルのクラスと新しいスタイルのクラスの違いは何ですか?どちらかをいつ使用すればよいですか?
解決
から http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes :
Python 2.1 までは、ユーザーが使用できるフレーバーは古いスタイルのクラスだけでした。
(古いスタイルの) クラスの概念は、型の概念とは無関係です。もし
x
が古いスタイルのクラスのインスタンスである場合、x.__class__
のクラスを指定しますx
, 、 しかしtype(x)
いつも<type 'instance'>
.これは、クラスとは無関係に、すべての古いスタイルのインスタンスがインスタンスと呼ばれる単一の組み込みタイプで実装されているという事実を反映しています。
クラスと型の概念を統合するために、新しいスタイルのクラスが Python 2.2 で導入されました。. 。新しいスタイルのクラスは単なるユーザー定義の型であり、それ以上でもそれ以下でもありません。
x が新しいスタイルのクラスのインスタンスの場合、
type(x)
通常、と同じですx.__class__
(これは保証されていませんが、返された値をオーバーライドするために新しいスタイルのクラスインスタンスが許可されていますx.__class__
).新しいスタイルのクラスを導入する主な動機は、完全なメタモデルを備えた統合オブジェクト モデルを提供することです。.
また、ほとんどの組み込みのタイプをサブクラスする能力や、計算されたプロパティを有効にする「記述子」の導入など、多くの即時の利点があります。
互換性上の理由から、クラスはデフォルトで依然として古いスタイルです.
新しいスタイルのクラスは、別の新しいスタイルのクラスを指定することによって作成されます(つまりタイプ)親クラスとして、または他の親が不要な場合は「トップレベルのタイプ」オブジェクトとして。
新しいスタイルのクラスの動作は、どのタイプが戻るかに加えて、多くの重要な詳細で古いスタイルのクラスの動作とは異なります。
これらの変更の一部は、特別な方法が呼び出される方法など、新しいオブジェクトモデルの基本です。その他は、複数の継承の場合のメソッド解像度順序のように、互換性の懸念のために以前に実装できなかった「修正」です。
Python 3 には新しいスタイルのクラスしかありません.
からサブクラス化しても関係ありません
object
または、クラスはPython 3の新しいスタイルです。
他のヒント
宣言に関して:
新しいスタイルのクラスは、オブジェクトまたは別の新しいスタイルのクラスを継承します。
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
古いスタイルのクラスではそうではありません。
class OldStyleClass():
pass
古いスタイルのクラスと新しいスタイルのクラスの間での重要な動作の変更点
- 素晴らしい 追加した
- MRO の変更 (下記で説明)
- 記述子 追加した
- 新しいスタイル クラス オブジェクトは、から派生しない限り生成できません。
Exception
(以下の例) __slots__
追加した
MRO (メソッド解決順序) が変更されました
他の回答でも述べられていますが、ここでは、クラシック MRO と C3 MRO (新しいスタイルのクラスで使用される) の違いの具体的な例を示します。
問題は、多重継承で属性 (メソッドとメンバー変数を含む) が検索される順序です。
クラシッククラス 左から右に深さ優先検索を実行します。最初の試合でやめてください。彼らは持っていない __mro__
属性。
class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass
assert C12().i == 0
assert C21().i == 2
try:
C12.__mro__
except AttributeError:
pass
else:
assert False
新しいスタイルの授業 MRO は、単一の英語の文で合成するのがより複雑です。詳しく解説してあります ここ. 。その特性の 1 つは、基本クラスは、そのすべての派生クラスが検索された後でのみ検索されるということです。彼らが持っているのは、 __mro__
検索順序を示す属性。
class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass
assert C12().i == 2
assert C21().i == 2
assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)
新しいスタイル クラス オブジェクトは、以下から派生しない限り生成できません。 Exception
Python 2.5 あたりでは多くのクラスを発生させることができましたが、Python 2.6 あたりではこれは削除されました。Python 2.7.3 の場合:
# OK, old:
class Old: pass
try:
raise Old()
except Old:
pass
else:
assert False
# TypeError, new not derived from `Exception`.
class New(object): pass
try:
raise New()
except TypeError:
pass
else:
assert False
# OK, derived from `Exception`.
class New(Exception): pass
try:
raise New()
except New:
pass
else:
assert False
# `'str'` is a new style object, so you can't raise it:
try:
raise 'str'
except TypeError:
pass
else:
assert False
古いスタイルのクラスは、属性検索に関してはまだわずかに高速です。これは通常は重要ではありませんが、パフォーマンスが重視される Python 2.x コードでは役立つ場合があります。
In [3]: class A: ...: def __init__(self): ...: self.a = 'hi there' ...: In [4]: class B(object): ...: def __init__(self): ...: self.a = 'hi there' ...: In [6]: aobj = A() In [7]: bobj = B() In [8]: %timeit aobj.a 10000000 loops, best of 3: 78.7 ns per loop In [10]: %timeit bobj.a 10000000 loops, best of 3: 86.9 ns per loop
グイドが書いた 新しいスタイルの授業の裏話, 、Python の新しいスタイルと古いスタイルのクラスに関する非常に素晴らしい記事です。
Python 3 には新しいスタイルのクラスしかありません。「古いスタイルのクラス」を書いたとしても、それは暗黙的に次から派生します。 object
.
新しいスタイルのクラスには、古いスタイルのクラスにはない高度な機能がいくつかあります。 super
そして新しい C3mro, 、いくつかの魔法の方法など。
これは非常に実用的な、正誤の違いです。次のコードの 2 つのバージョンの唯一の違いは、2 番目のバージョンでは person が object から継承されることです。それ以外は 2 つのバージョンは同一ですが、結果は異なります。
1) 古いスタイルのクラス
class Person():
_names_cache = {}
def __init__(self,name):
self.name = name
def __new__(cls,name):
return cls._names_cache.setdefault(name,object.__new__(cls,name))
ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed1 is ahmed2
print ahmed1
print ahmed2
>>> False
<__main__.Person instance at 0xb74acf8c>
<__main__.Person instance at 0xb74ac6cc>
>>>
2) 新しいスタイルの授業
class Person(object):
_names_cache = {}
def __init__(self,name):
self.name = name
def __new__(cls,name):
return cls._names_cache.setdefault(name,object.__new__(cls,name))
ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed2 is ahmed1
print ahmed1
print ahmed2
>>> True
<__main__.Person object at 0xb74ac66c>
<__main__.Person object at 0xb74ac66c>
>>>
新しいスタイルのクラスは以下から継承します object
Python 2.2 以降ではそのように記述する必要があります (つまり、 class Classname(object):
の代わりに class Classname:
)。主な変更点は型とクラスを統合することであり、これによる素晴らしい副作用は、組み込み型から継承できることです。
読む 記述 詳細については。
新しいスタイルのクラスで使用できるもの super(Foo, self)
どこ Foo
クラスであり、 self
インスタンスです。
super(type[, object-or-type])
メソッド呼び出しを type の親クラスまたは兄弟クラスに委任するプロキシ オブジェクトを返します。これは、クラス内でオーバーライドされた継承メソッドにアクセスする場合に便利です。検索順序は、型自体がスキップされることを除いて、getattr() で使用される順序と同じです。
Python 3.x では、単に次のように使用できます。 super()
パラメータのないクラス内。
というか、常に新しいスタイルのクラスを使用する必要があります。 ない限り 2.2 より古いバージョンの Python で動作する必要があるコードがある。