回答:
以下からの新スタイルと古典的なクラス:
Python 2.1までは、古いスタイルのクラスがユーザーが使用できる唯一のフレーバーでした。
(古いスタイルの)クラスの概念は、タイプの概念とは無関係です。もし
x
古いスタイルのクラスのインスタンスである場合x.__class__
、のクラスを指定しますがx
、type(x)
常に<type 'instance'>
です。これは、クラスに関係なく、すべての古いスタイルのインスタンスが、インスタンスと呼ばれる単一の組み込み型で実装されているという事実を反映しています。
Python 2.2では、新しいスタイルのクラスが導入され、classとtypeの概念が統一されました。新しいスタイルのクラスは、単にユーザー定義型であり、それ以上でもそれ以下でもありません。
xが新しいスタイルのクラスのインスタンスである場合、
type(x)
通常はと同じですx.__class__
(ただし、これは保証されません。新しいスタイルのクラスインスタンスは、に返される値をオーバーライドできますx.__class__
)。新しいスタイルのクラスを導入する主な動機は、完全なメタモデルを備えた統合オブジェクトモデルを提供することです。
また、ほとんどの組み込み型をサブクラス化する機能や、計算されたプロパティを有効にする「記述子」の導入など、多くの直接的な利点もあります。
互換性の理由から、クラスはデフォルトでまだ古いスタイルです。
新しいスタイルのクラスは、別の新しいスタイルのクラス(タイプ)を親クラスとして指定するか、他の親が不要な場合は「トップレベルタイプ」オブジェクトを指定することによって作成されます。
新しいスタイルのクラスの動作は、タイプが返すものに加えて、多くの重要な詳細において古いスタイルのクラスの動作とは異なります。
これらの変更の一部は、特別なメソッドが呼び出される方法など、新しいオブジェクトモデルの基本です。その他は、多重継承の場合のメソッド解決順序のように、互換性を考慮してこれまで実装できなかった「修正」です。
Python 3には新しいスタイルのクラスしかありません。
からサブクラス化する
object
かどうかに関係なく、クラスはPython 3の新しいスタイルです。
super()
は、古いスタイルのクラスでは機能しません。言うまでもなく、その記事が言うように、MROのような根本的な修正と特別なメソッドがあります。これは、それを使用する正当な理由以上のものです。
宣言的に:
新しいスタイルのクラスは、objectまたは別の新しいスタイルのクラスから継承します。
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
古いスタイルのクラスにはありません。
class OldStyleClass():
pass
Python 3注:
Python 3は古いスタイルのクラスをサポートしていないため、上記のいずれの形式でも新しいスタイルのクラスになります。
object
ます。
class AnotherOldStyleClass: pass
class A: pass
おりclass A(): pass
、完全に同等です。1つ目は「Aは親クラスを継承しない」ことを意味し、2つ目は「Aは親クラスを継承しない」ことを意味します。これはnot is
andによく似ていますis not
古いスタイルクラスと新しいスタイルクラスの間の重要な動作の変更
Exception
以下の例から派生しない限り、新しいスタイルクラスオブジェクトを発生させることはできません。__slots__
追加された他の回答でも触れましたが、クラシック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コードで役立つ場合があります。
[3]:クラスA: ...:def __init __(self): ...:self.a = 'こんにちは' ...: [4]:クラスB(オブジェクト): ...:def __init __(self): ...:self.a = 'こんにちは' ...: [6]で:aobj = A() [7]で:bobj = B() [8]:%timeit aobj.a 10000000ループ、最高3:ループあたり78.7 ns [10]:%timeit bobj.a 10000000ループ、最高3:ループあたり86.9 ns
%timeit aobj.a
10000000 loops, best of 3: 66.1 ns per loop
%timeit bobj.a
10000000 loops, best of 3: 53.9 ns per loop
Guidoは、The New Story on New-Style Classesを書いています。これは、Pythonの新しいスタイルのクラスと古いスタイルのクラスに関する非常に優れた記事です。
Python 3には新しいスタイルのクラスしかありません。「古いスタイルのクラス」を作成した場合でも、それは暗黙的にから派生しobject
ます。
新しいスタイルのクラスには、古いスタイルのクラスには欠けている高度な機能がいくつかあります。たとえばsuper
、新しいC3 mro、いくつかの魔法のメソッドなどです。
ここに、非常に実用的な、真/偽の違いがあります。次のコードの2つのバージョンの唯一の違いは、2番目のバージョンではPersonがobjectから継承することです。それ以外は、2つのバージョンは同じですが、結果は異なります。
昔ながらのクラス
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>
>>>
新しいスタイルのクラス
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>
>>>
_names_cache
は、渡したすべての名前をキャッシュ(将来の取得のために保存)する辞書ですPerson.__new__
。setdefaultメソッド(任意のディクショナリで定義)は、キーと値の2つの引数を取ります。キーが辞書にある場合、その値を返します。辞書にない場合は、最初に2番目の引数として渡された値に設定し、それを返します。
__new__()
は、それを作成しないという考え方ですが、この場合は常に呼び出され、常に新しいオブジェクトを作成してからスローします。この場合、aよりもif
が推奨され.setdefault()
ます。
__new__
実際には古いスタイルのクラスのものではありません。インスタンスの構築では使用されません(これはdefineのように特別に見えるランダムな名前です__spam__
)。したがって、古いスタイルのクラスを構築すると、が呼び出されるだけで__init__
、新しいスタイルの構築は__new__
、名前を付けてシングルトンインスタンスに結合して構築し、__init__
初期化します。
新しいスタイルのクラスobject
は、Python 2.2以降から継承され、そのように記述する必要があります(つまりのclass Classname(object):
代わりにclass Classname:
)。中心的な変更は型とクラスを統合することであり、これの素晴らしい副作用は、組み込み型から継承できることです。
読むdescrintro詳細については。
type(x)
。組み込み型をサブクラス化していない場合、新しいスタイルのクラスで見ることができる利点はないようです。には余分な型指定があるという欠点があります(object)
。