クラスを定義すると、Pythonは自動的にいくつかのメソッドを提供しますが、そのほとんどはオブジェクトクラスまたは型クラスから継承されます。これらのメソッドをオーバーライドして、特定の操作を実装できます。
20.1印刷時にオブジェクトを読みやすくする
print()を使用してオブジェクトを印刷する__str__()
と、関数のコンテンツが表示されます。インスタンスを直接実行すると、印刷されたオブジェクトに__repr__()
関数のコンテンツが表示されます。したがって、実装__str__()
と__repr__()
これら2つの方法により、オブジェクトの印刷は人間の読み取りとより一致するようになります。例えば
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self): # print()时调用
return 'Student object (name=%s, age=%d)' % (self.name, self.age)
__repr__ = __str__
print(Student("Jim", 20)) # 打印__str__函数的内容,Student object (name=Jim, age=20)
20.2クラスオブジェクトに反復をサポートさせる
すべてのコンテナタイプが反復ループの...in...をサポートしていることがわかっています。forステートメントは実際には2つのことを行います。最初にイテレータを取得します。つまり、__iter__()
関数が呼び出されます。2つ目は、ループのプロセスであり、ループ__next__()
内で関数を呼び出します。実際、カスタムクラスは、これら2つのメソッドが実装されている限り、クラスのオブジェクトをforループで繰り返すこともできます。
たとえば、クラスで実装されたフィボナッチ数列:
class Fib:
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 返回一个迭代对象,实例本身就是迭代对象,故返回自己
def __next__(self): # for循环时就是调用这个方法获取下一个值
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 10000: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
for i in Fib():
if i > 20:
break
print(i)
20.3オブジェクトを呼び出し可能にする
私たちが通常定義する関数、組み込み関数、クラスはすべて呼び出し可能なオブジェクトです。直感的には、それらの後に1対の括弧を追加できますが、1対の括弧()をオブジェクトに適用できる場合は、このオブジェクトです。これは呼び出し可能オブジェクトと呼ぶことができ、関数callable()を使用して、オブジェクトが呼び出し可能オブジェクトであるかどうかを判断できます。
callable(0) # 函数返回 False
def add(a, b):
return a + b
callable(add) # 函数返回 True
__call__
メソッドがクラスに実装されている場合、インスタンスオブジェクトも呼び出し可能なオブジェクトになります。つまり、インスタンスの後に括弧を付けることができ、呼び出しの結果は__call__
メソッドのコンテンツになります。例を参照してください。
class Student:
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
s = Student('Michael')
s() # 实例变成了Callable的了,输出My name is Michael
これの実用は何ですか?__getattr__
とを使用し__call__
て動的呼び出しを実現する例を見てみましょう。動的にURL文字列を生成します。
class Chain:
def __init__(self, path=''):
self._path = path
def __getattr__(self, path):
"""调用不存在的属性时,会执行这个方法,方法效果是将path用/拼接起来,返回一个实例"""
return Chain('%s/%s' % (self._path, path))
def __call__(self, path):
"""当实例被调用时,会执行这个方法,方法效果是实例里面的参数也用/拼接起来,返回一个实例"""
return Chain('%s/%s' % (self._path, path))
def __str__(self):
return self._path
__repr__ = __str__
if __name__ == '__main__':
print(Chain().status.user.timeline.list) # 每一个"."就是一次调用__getattr__方法
print(Chain().users('michael').repos) # Chain().users根据__getattr__的作用会返回一个实例,加上()后回到用__call__方法
20.4インスタンスオブジェクトを手動で作成する
__new__
このメソッドは、インスタンスオブジェクトの作成を担当します。このメソッドは、オブジェクトの作成時にPythonインタープリターによって自動的に呼び出されます。これはクラスメソッドです。__new__
メソッドがインスタンスを返した後、Pythonインタープリターは引き続き__init__
メソッドを自動的に呼び出してインスタンスを初期化します。__new__
メソッドが値を返さない場合、またはインスタンスを返さない場合、Pythonインタープリターはメソッドを自動的に呼び出しません__init__
。__new__
このメソッドは、主にクラス(int、str、tupleなど)を継承する場合に使用され、プログラマーにこれらのクラスのインスタンス化プロセスをカスタマイズする機会を提供します。カスタムメタクラスメタクラスの実現もあります。
__new__
典型的なアプリケーションは、シングルトンパターンを作成することです。
シングルトンモードの原理は、クラス属性にシングルトン決定ビットフラグを追加し、このフラグを使用してクラスがインスタンス化されているかどうかを判断することです。クラスがインスタンス化されている場合は、インスタンス化されたオブジェクトが返されます。
class Singleton:
# 重写父类的__new__方法,__new__是个类方法,第一个参数是cls,必须有返回值
def __new__(cls, *args, **kwargs): # 自定义类实例化对象的过程
# __new__生成的对象放入cls的_instance属性中, 如果cls不存在_instance
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls, *args, **kwargs) # 调用父类__new__创建实例
# 如果cls存在_instance,直接返回,不要生成新的对象
return cls._instance
class MyClass(Singleton):
pass
s1 = MyClass()
s2 = MyClass()
s3 = MyClass("s3")
s4 = MyClass("s4")
print(id(s1), id(s2), id(s3), id(s4))
シングルトンから継承するクラス__new__
は、オーバーライドされない限りシングルトンになります。
20.52つのオブジェクト比較ロジックのカスタマイズ
このメソッドは、2つのオブジェクトが等しいかどうかが判別されたときにトリガーされます__eq__
。このメソッドでは、2つのオブジェクトが等しいためのルールを定義できます。2つのオブジェクトのサイズを比較するためのルールを定義するメソッドも__lt__
あります。__gt__
例えば:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other): # 定义内置方法,自定义两个对象相等的逻辑
return self.__dict__ == other.__dict__ # 两对象空间的属性值都相等,两个对象被认为相等。
def __lt__(self, other):
return self.age < other.age
if __name__ == '__main__':
s1 = Student("李四", 20)
s2 = Student("李四", 20)
print(s2 == s1) # True
print(s2 is s1) # False
s3 = Student("王五", 19)
print(s1 > s3) # True