Python の高度な ----- オブジェクト指向 7.0 (__new__ メソッドと __init__ メソッドについて詳しく説明します)

目次

序文:

__init__ メソッド

__new__ メソッド (重要!)

1. __new__メソッドの呼び出し処理

2. __new__ メソッドをオーバーライドします。

3. __new__ メソッドは異なる値を返します

3. シングルトンモード


序文:

        __new__() メソッドは前号で紹介しましたが、実はこのメソッドにはまだまだ語るべき内容がたくさんあり、このメソッドを習得すると、オブジェクトのスペース割り当てを柔軟に制御できるようになります(前号のリンク)上級Python-----Facing Object 6.0 (バインディングメソッド[クラスメソッド、静的メソッド]と組み込みメソッド)_Python Ouni Sauce's Blog - CSDN Blog )、次回は見ていきましょう!

__init__ メソッド

このメソッドは誰もがよく知っているはずです。はい、これは初期化メソッドであり、構築メソッドとも呼ばれます。新しいオブジェクトを作成するときは、このオブジェクトのプロパティまたはメソッドを初期化する必要があります。このメソッドは、自動的に実行されます。オブジェクトが作成されたとき。以下に例を示します。

class Person(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age  #定义实例化对象的属性
        print('person message')
dick=Person('Dick',18)
#输出结果:person message
print(dick.name,dick.age)
#输出结果:Dick 18

この例から、__init__ メソッドが自動的に呼び出され、人物メッセージが自動的に出力されることが簡単にわかりますが、その前に、__init__ メソッドよりも先に呼び出される別のメソッドがあります。これは、オブジェクト __new__ に領域を割り当てることです。方法

__new__ メソッド (重要!)

1. __new__メソッドの呼び出し処理

        Python のすべてのクラスの親クラスはオブジェクト クラスであり、オブジェクト クラスはスーパー クラスとも呼ばれます。インスタンス オブジェクトを作成するときは、まずオブジェクトのメモリ領域を割り当てます。その後、そのオブジェクトにデータを入れることができます。このとき、__new__ メソッドを使用してこの空間を作成し、このオブジェクト空間を __init__ メソッドに返して初期化します。つまり、__new__ メソッドはこの空間を返し、それを自己インスタンス パラメータに渡します。 __init__ メソッドなので、__new__ メソッドは __init__ メソッドと同じように自動的に呼び出されます。

__new__ このメソッドは、組み込みの静的クラス メソッドです。Python インタプリタは、このメソッドによって返されたオブジェクト参照を取得した後、この参照を最初のパラメータとして init メソッドに渡します。そのため、新しいメソッドは init メソッドよりも先に実行されます。   

 一般的な理解:

上の文は少しわかりにくいかもしれませんが、ここでたとえてみましょう: 私たちが日常生活で使用する木製家具は、木材を加工して得られます。__new__ メソッドも、木材を入手する責任のある木こりです。そして、これらを与えてください。木材を __init__ メソッド、つまり大工に渡し、これらの木材を使って私たちが使用するあらゆる種類の家具を作ることができます。

        ここで、クラスを定義するたびに __new__ メソッドを定義せずに __init__ メソッドだけを定義するのですが、メモリ空間はどのようにして確保されるのですか? と疑問に思う人もいるかもしれません。

        答え: すべてのクラスはオブジェクト クラスを継承することに注意してください。そのため、クラスにコンテンツを書き込むとき、実際にはオブジェクト クラスを書き換えます。 def __init__(self に移動すると、__init__ メソッドと __new__ メソッドの両方がオブジェクト クラスのメソッドに属します) ): 、実際にはオブジェクト内の __init__ メソッドを書き換えますが、 def __new__(cls): には行きません。つまり、 __new__ メソッドを書き換えません。その後、定義したクラスがこれを保持して呼び出します。メソッドを呼び出し、インスタンス化されたオブジェクトの空間を __init__ メソッドに返します。

例:

class A(object):
    def __init__(self,name):
        self.name=name
class B(object):
    object.__new__(object) #当我们没有重写__new__方法,默认继承并且调用object类__new__方法
    def __init__(self,name):
        self.name=name
user=A('dick')
user2=B("hao")
print(user.__sizeof__(),user2.__sizeof__()) #查看占内存
#输出结果:32 32

上記の例から、クラス A とクラス B の効果がまったく同じであることがわかりますが、クラス B の __new__ メソッド呼び出しを書き出しただけなので、実際には、__new__ メソッドが自動的にオブジェクト クラスを継承して呼び出します。 、心配する必要はありません。

: __new__ メソッドは __init__ メソッドよりも先に呼び出されます。

 例を見てみましょう:

class User(object):
    def __init__(self,name):
        self.name=name
        print(f'我的名字是{self.name}')
    def __new__(cls, *args, **kwargs): #对__new__方法重写
        print('这个是__new__方法')
        return object.__new__(cls) #返回这个类对象的空间
jb=User('Dick')
#输出结果:
# 这个是__new__方法
# 我的名字是Dick

出力結果を見ると、__new__メソッドの内容が先に出力され、次に__init__メソッドの内容が出力されるため、__new__メソッドが先に実行されることがわかります。

2. __new__ メソッドをオーバーライドします。

        親クラスの __new__ メソッドが気に入らない場合があるので、メソッドを書き換えることになりますが、このメソッドを書き換えるときはどのような点に注意すればよいでしょうか。

__new__ メソッドを書き換える場合、オブジェクト空間インデックスの戻り値が必要になりますが、この戻り値は通常、親クラスの __new__ メソッドを使用します。 

 予防:

1. 返されるオブジェクトへの参照 (つまり、オブジェクトのスペース) が必要です。

2. 返されたオブジェクトのクラスに注意してください

例 1: オブジェクトへの参照が返されない場合はどうなりますか?

class A(object):
    def __new__(cls, *args, **kwargs):
        print('重写new方法')
    #这里我没有写返回值会怎么样呢?
    def __init__(self,name):
        print('初始化方法')
        self.name=name
user=A('dick')
print(user)
#输出结果:重写new方法
#         None

ここでは戻り値がありませんが、インスタンスオブジェクトを作成する際に、割り当てられた領域がどこにあるのかわからないため、オブジェクトの初期化ができないため、__init__メソッドが実行できず、インスタンスオブジェクトが取得されません。スペース、つまりスペースは作成されますが、スペースが見つからず、データを保存できません。

例 2:

class B(object):
    def __init__(self,name):
        self.name=name
        print('初始化方法')
    def __new__(cls, *args, **kwargs):
        print('这是new方法')
        return object.__new__(cls)
user=B('Dick')
print(user.name)
#输出结果:
# 这是new方法
# 初始化方法
# Dick

ここの __new__ メソッドはオブジェクト インデックスの戻り値を持ち、現在のクラスのインスタンス化されたオブジェクトを __init__ メソッドの self パラメーターに渡して初期化し、このオブジェクトがスペースを取得できるようにします。

3. __new__ メソッドは異なる値を返します

私たちは以前にクラス メソッドについて学習しており、クラス メソッドにはクラス自体を表すことを意味するパラメーター --cls があり、__new__ メソッドにも cls パラメーターがあることは誰もが知っていますが、このパラメーターは必ずしもそのクラスを表すわけではありません。独自のクラス つまり、他の親クラスも渡すことができます。したがって、このパラメーターに異なる値が入力されると、さまざまな状況が発生します。以下では、例としてコードを使用して、それらを 1 つずつ説明します。

例 1:

class A(object):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        print('这个是A类重写的方法')
        res=object.__new__(cls)
        return res
class B(A):
    def __init__(self,sound):
        self.sound=sound
user=B('汪汪')
print(user.sound)
#输出结果:
# 这个是A的类
# 汪汪

ここで、A はオブジェクト クラスの __new__ メソッドを書き換え、B は A を継承しますが、B は A の __new__ メソッドを書き換えないため、B は A の __new__ メソッドを直接使用して現在のクラス (cls ) に渡し、インスタンス化されたメソッドを返します。現在のクラスの空間 (cls)

例 2:

class A(object):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        print('这个是A类重写的方法')
        res=object.__new__(cls)
        return res
class B(A):
    def __init__(self,sound):
        self.sound=sound
    def __new__(cls, *args, **kwargs):
        print('这个是B类重写的方法')
        res=cls.__new__(cls)  #这里是返回自身的实例对象空间引索
        return res
user=B('汪汪')
print(user.sound)
#结果:报错,进入死循环

 注: __new__ メソッドを書き換える場合、独自のクラス オブジェクトのスペース インデックスを返すことはできません。返さないと、無限ループに入ります。

例 3: 

class A(object):
    jk='beauty'
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        res=object.__new__(cls)
        return res
    def fun(self):
        print('大家好!')
class B(A):
    def __init__(self,sound):
        self.sound=sound
    def __new__(cls, *args, **kwargs):
        res=super().__new__(A)  #返回的是类对象A的空间引索
        return res
user=B('汪汪') #实际上这里创建是类A的实例化对象
print(user.jk)  #输出结果:beauty
user.fun()  #输出结果:大家好!
print(user.sound) #报错'A' object has no attribute 'sound'
print(user.name)   #报错'A' object has no attribute 'name'

 この例では、クラス A によって割り当てられたスペース インデックスを返すことになりますが、クラス B の型とは異なるため、クラス B の __init__ 初期化に入ることができず、スペースだけがあり初期化が行われない状況が発生します。オブジェクト user をインスタンス化すると、user はクラス B のインスタンス化されたオブジェクトではなく、クラス A のインスタンス化されたオブジェクトになります。(ここでインスタンス化されたオブジェクトのユーザーは、クラス A の __init__ 初期化とクラス B の __init__ 初期化を実行しません)

3. シングルトンモード

        シングルトン モードは、コンピュータにとって非常に一般的なオブジェクト スペース割り当てモードです。たとえば、コンピュータで設定ウィンドウを開いたとき、再度設定ウィンドウを開いたときに、コンピュータはウィンドウが存在するかどうかを検出し、存在する場合は、ウィンドウが再びポップアップします。つまり、このウィンドウをフォークした後にのみ新しいウィンドウが生成されます。これにより、複数のウィンドウのポップアップ ウィンドウが回避され、無効なメモリ占有も回避できます (ウィンドウが表示されるたびに)。メモリが必要です)、これはシングルトン モードと呼ばれます。

 Python では、インスタンス オブジェクトを作成するたびにメモリ アドレスを占有する必要があり、プロジェクトで作業しているときに、役に立たないインスタンス オブジェクトが常にこのアドレスを占有し、プログラムの実行が遅くなります。Python の __new__ メソッドを通じてシングルトン モードを実装するにはどうすればよいですか? 下を見てみましょう。

シングルトンの利点: メモリの節約

 コードは以下のように表示されます:

class Student(object):
    _instance=None  #定义一个类属性,是可以在类中进行调用的
    def __init__(self, name,age):
        self.name=name
        self.age=age
    def __new__(cls, *args, **kwargs):
        if cls._instance is None: #如果这个内存为空的话就进行空间分配
            print('进行空间分配')
            cls._instance=super().__new__(cls)
        return cls._instance
Jack=Student('Jack',18)
John=Student('John',19)
Dick=Student('Dick',18)
print(Jack is Dick is John) #输出:True
print(Jack.name,Jack.age)   #输出:Dick 18
print(John.name,John.age)   #输出:Dick 18
print(Dick.name,Dick.age)   #输出:Dick 18

上記はシングルトン モードです。これらのインスタンス化されたオブジェクトはすべて同じメモリ アドレスを占有するため、メモリ アドレスは同じですが、インスタンス化されたオブジェクトが作成されるたびに、インスタンス化されたオブジェクトがオブジェクトを上書きし、最終的にそのスペースは最後のものに属します。インスタンス化されたオブジェクトなので、出力されます Dick 18

 

 さて、上記が今回の内容のすべてですが、オブジェクトにスペースとメモリを割り当てる方法を学びましたか?

毎日壁紙を共有します:

おすすめ

転載: blog.csdn.net/m0_73633088/article/details/129347622