1074

Pythonの古いスタイルと新しいスタイルのクラスの違いは何ですか?いつどちらを使うべきですか?

4

8 に答える 8

600

新しいスタイルとクラシックのクラスから:

Python 2.1までは、古いスタイルのクラスがユーザーが利用できる唯一のフレーバーでした。

(古いスタイルの)クラスの概念は、型の概念とは無関係です。xが古いスタイルのクラスのインスタンスである場合、はのクラスをx.__class__ 指定しますxが、type(x)常に<type 'instance'>です。

これは、クラスに関係なく、すべての古いスタイルのインスタンスが、インスタンスと呼ばれる単一の組み込み型で実装されているという事実を反映しています。

クラスとタイプの概念を統一するために、Python2.2で新しいスタイルのクラスが導入されました。新しいスタイルのクラスは、単にユーザー定義の型であり、それ以上でもそれ以下でもありません。

xが新しいスタイルのクラスのインスタンスである場合、type(x)通常はと同じx.__class__です(ただし、これは保証されていません。新しいスタイルのクラスインスタンスは、に対して返される値をオーバーライドできますx.__class__)。

新しいスタイルのクラスを導入する主な動機は、完全なメタモデルを備えた統合オブジェクトモデルを提供することです。

また、ほとんどの組み込み型をサブクラス化する機能や、計算されたプロパティを有効にする「記述子」の導入など、多くの直接的な利点もあります。

互換性の理由から、クラスはデフォルトでまだ古いスタイルです

新しいスタイルのクラスは、別の新しいスタイルのクラス(つまり、タイプ)を親クラスとして指定するか、他の親が必要ない場合は「最上位のタイプ」オブジェクトを指定することによって作成されます。

新しいスタイルのクラスの動作は、どのタイプが返されるかに加えて、いくつかの重要な詳細が古いスタイルのクラスの動作とは異なります。

これらの変更のいくつかは、特別なメソッドが呼び出される方法のように、新しいオブジェクトモデルの基本です。その他は、多重継承の場合のメソッド解決順序など、互換性の問題のために以前は実装できなかった「修正」です。

Python3には新しいスタイルのクラスしかありません

サブクラスを作成するかどうかに関係objectなく、Python3ではクラスは新しいスタイルです。

于 2008-09-10T18:02:43.743 に答える
326

宣言について:

新しいスタイルのクラスは、 objectまたは別の新しいスタイルのクラスから継承します。

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

古いスタイルのクラスはそうではありません。

class OldStyleClass():
    pass

Python 3 注:

Python 3 は古いスタイルのクラスをサポートしていないため、上記のどちらの形式でも新しいスタイルのクラスになります。

于 2009-07-30T01:21:59.097 に答える
237

古いスタイル クラスと新しいスタイル クラスの間の重要な動作の変更

  • 追加
  • 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
于 2013-11-13T09:36:59.783 に答える
41

古いスタイルのクラスは、属性ルックアップに関してはまだわずかに高速です。これは通常は重要ではありませんが、パフォーマンスが重要な 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
于 2010-07-12T11:26:52.043 に答える
38

Guido はThe Inside Story on New-Style Classesを書きました。これは、Python の新しいスタイルと古いスタイルのクラスに関する非常に優れた記事です。

Python 3 には new-style クラスしかありません。「古いスタイルのクラス」を書いても、それは暗黙のうちに から派生していobjectます。

super新しいスタイルのクラスには、新しいC3 mro、いくつかの魔法のメソッドなど、古いスタイルのクラスに欠けているいくつかの高度な機能があります。

于 2013-04-24T13:41:26.200 に答える
25

これは非常に実用的な真/偽の違いです。次のコードの 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>
    >>>
    
于 2013-10-09T13:40:29.397 に答える
10

新しいスタイルのクラスは から継承されており、Python 2.2 以降では (つまりの代わりに) そのobjectように記述する必要があります。コアとなる変更は、型とクラスを統合することです。これの良い副作用は、組み込み型から継承できるようになることです。class Classname(object):class Classname:

詳細については、説明をお読みください。

于 2008-10-28T09:54:30.437 に答える
8

新しいスタイルのクラスでは、クラスはsuper(Foo, self)どこで、インスタンスはどこであるかを使用できます。Fooself

super(type[, object-or-type])

タイプの親クラスまたは兄弟クラスにメソッド呼び出しを委譲するプロキシ オブジェクトを返します。これは、クラスでオーバーライドされた継承メソッドにアクセスする場合に便利です。検索順序は、タイプ自体がスキップされることを除いて、getattr() で使用される順序と同じです。

また、Python 3.x ではsuper()、パラメーターなしでクラス内で単純に使用できます。

于 2013-04-30T08:28:52.780 に答える