8

クラス コンストラクター ( init )で値を返そうとしました。

class A:
  def __init__(self):
    return 1

しかし、 initは None を返す必要があるという実行時エラーが発生します。この場合、理解する方法は次のとおりです。

a=A()

クラスインスタンスとして「a」が割り当てられている場所はどこですか?

4

4 に答える 4

28

厳密に言えば、A.__new__()インスタンスを作成しているわけではありませんa

定義するときclass A(object):(またはclass A:、Python3 を使用している場合は廃止されclass A:古いスタイルのクラスです)、インスタンスを作成するために呼び出されるのは__new__継承されたものです。object.__new__()a

a = A()実行されると、次のことが起こります。

  1. A()の省略形ですA.__call__
  2. object.__new__(cls, *args, **kwargs)where はcls=A、インスタンスを作成するために内部で実際に行われることaです。新しいオブジェクトにメモリを割り当て、新しいオブジェクト (インスタンス) を返す必要があります。
  3. 新しく作成されたオブジェクトが返された場合にのみ、新しく作成さ__init__(self) オブジェクトが渡されて呼び出され、オブジェクトを「初期化」します。

次のデモを検討してください。

  • オーバーライド__new__してオブジェクトを返さなくなった場合、__init__呼び出されません。

    class A(object):
    
        def __new__(cls, *args, **kwargs):
            print cls, args, kwargs
    
        def __init__(self):
            self.x = 'init!'
            print self.x
    
    
    In : a = A()
    <class '__main__.A'> () {}
    
    # note that "init!" has not appeared here because __new__ didn't return an
    # new instance
    
  • を使用して新しいインスタンスを返すと、 afterも呼び出されるobject.__new__ことがわかります。__new____init__

    class A(object):
    
        def __new__(cls, *args, **kwargs):
            print cls, args, kwargs
            return object.__new__(cls, args, kwargs)
    
        def __init__(self):
            self.x = 'init!'
            print self.x
    
    In : a = A()
    <class '__main__.A'> () {}
    init!
    

違いを表示する別のデモを次に示します。インスタンスaは を呼び出さずに作成できることに注意して__init__()ください。

class A(object):
    def __init__(self):
        self.x = "init!"
        print self.x

In : a = object.__new__(A)

In : a
Out: <__main__.A at 0x103466450>

In : a.__dict__
Out: {}


In : aa = A()
init!

In : aa
Out: <__main__.A at 0x1033ddf50>

In : aa.__dict__
Out: {'x': 'init!'}

さて、好奇心旺盛な人のために(そして私自身の記憶をリフレッシュするために=]):

大まかに言えば、Python で新しいオブジェクトを作成するには、主に 2 つの方法があります。

サブクラス化して新しいオブジェクト ( type / class ) を作成します。

classステートメントは Python に新しい/クラスオブジェクトを作成するように指示します (既存の/クラスをサブクラス化することによりobject):

class Hello(object):
    pass
>>> Hello.__class__
<type 'type'>

実際、すべてのクラス/オブジェクトには type がありtypeます。type ( )の型type(type)はまだ type です。

タイプ/クラスオブジェクトをサブクラス化できます。

インスタンス化して新しいオブジェクト ( instance ) を作成します。

既存のオブジェクトをインスタンス化することによって、新しいオブジェクトを作成することもできます。これは、__call__演算子 (省略形()) を使用して行われます。

>>> h = hello()
>>> type(h)
<class '__main__.Hello'>
>>> type(int('1'))
<type 'int'>

インスタンス オブジェクトをサブクラス化することはできません。

(リスト演算子を使用するなど、他の方法で新しいインスタンスオブジェクトを作成することもできます[1,2,3]。この場合、リスト インスタンスが作成されます)

type(my_obj)またはでオブジェクトのタイプを確認できますmy_object.__class__


インスタンス オブジェクトの作成方法はわかりましたが、 (インスタンス オブジェクトの作成を可能にする)タイプ/クラスオブジェクトを実際に作成するのは何ですか?

実際、これらのオブジェクトはインスタンス化によっても作成されますが、前述のインスタンス化とは少し異なる種類のインスタンス化です。

classステートメントとは 別にtype(cls_name, parent_class_tuple, attr_dict)、新しいクラスを作成するために使用することもできます。例:

type('Hello', (object,), {})

Hello前に示したものと同じクラスを作成します。

とはtype? メタクラスを入力します。

typeclass のクラスであるmetaclassです。つまり、クラスはメタクラスのインスタンスです。のはまだです。__class__typetype

これは、 metaclassclassinstanceの間の関係を示すグラフです。

            instantiate             instantiate
metaclass   --------------> class   ---------------->    instance
            type.__new__()          object.__new__()

type新しいクラスを作成するためにメタクラスが呼び出されると、同様のフローが行われます。

  1. type.__call__()実行されます
  2. type.__new__()メモリを割り当て、新しいクラス (メタクラス インスタンス) を返し、 を呼び出しますtype.__init__()
  3. type.__init__()ステップ 2 から渡された新しく作成されたクラスを初期化します。

サブクラス化することで新しいメタクラスを作成することもできますtype:

class MyMeta(type):
    def __new__(meta, name, bases, dct):
        # do something
        return super(MyMeta, meta).__new__(meta, name, bases, dct)
    def __init__(cls, name, bases, dct):
        # do something
        super(MyMeta, cls).__init__(name, bases, dct)

MyMeta次に、このメタクラスから、次のように新しいクラスを作成できますtype

MyClass = MyMeta('MyClass', (object, ), {'x': 1})

または、__metaclass__クラスを定義するときに使用します。これは、上に示したものとまったく同じ効果があります。

class MyClass(object):
    __metaclass__ = MyMeta
    x = 1
于 2012-10-24T05:30:40.607 に答える
8

それはこのように動作します:

あなたがやる:

a = A()

A.__new__()が呼び出され、クラスのインスタンスを返しますA

同様に:

a = A.__new__(A)

次にPythonが呼び出します

a.__init__()

エラーメッセージが示すように、値を返すべきではありません。

于 2012-10-24T05:15:37.667 に答える
4

ご存知のように、Python ではすべてがオブジェクトであり、クラスも例外ではありません。クラスは、 のようなものを書くことができるAメソッドを持つオブジェクトです。内部的には、最初に静的メソッド (適切なデフォルト実装を持つ) を使用してオブジェクトを作成し、次に適切なコンストラクター引数を使用して新しいオブジェクトを呼び出します。__call__(...)a = A()A.__call____new____init__

于 2012-10-24T05:19:56.030 に答える
2

__init__返す必要がある要件Noneは、意識的な実装の選択です。これにより、クラス型のオブジェクトがクラスのインスタンス型のオブジェクトを一貫して返すという事実に依存できます。C++ などの他の多くの言語でも同じです。

異なる方法で実装すると、無用な混乱が生じます。

于 2012-10-24T05:27:09.053 に答える