Python-Kernnotizen für die Testentwicklung (20): Integrierte Klassen für fortgeschrittene Methoden

Wenn wir eine Klasse definieren, stellt uns Python automatisch einige Methoden zur Verfügung, von denen die meisten von der Objektklasse oder Typklasse geerbt werden. Wir können diese Methoden überschreiben, um bestimmte Operationen zu implementieren.

20.1 Objekte beim Drucken leichter lesbar machen

Das Drucken des Objekts mit print() __str__()stellt den Inhalt der Funktion dar. Wenn die Instanz direkt ausgeführt wird, zeigt das gedruckte Objekt __repr__()den Inhalt der Funktion an. Daher kann der Objektdruck durch die Implementierung __str__()und __repr__()diese beiden Verfahren dem menschlichen Lesen besser entsprechen. zum Beispiel

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 Klassenobjekte dazu bringen, die Iteration zu unterstützen

Wir wissen, dass alle Containertypen for ... in ... for iterative Schleifen unterstützen. Die for-Anweisung macht eigentlich zwei Dinge. Als erstes muss man einen Iterator bekommen, d.h. die __iter__()Funktion wird aufgerufen. Die zweite Sache ist der Prozess des Schleifens, das Aufrufen von __next__()Funktionen in einer Schleife. Tatsächlich kann das Objekt einer benutzerdefinierten Klasse, solange diese beiden Methoden implementiert sind, auch von der for-Schleife durchlaufen werden.

Zum Beispiel die Fibonacci-Folge, implementiert mit einer Klasse:

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 Objekte aufrufbar machen

Die Funktionen, eingebauten Funktionen und Klassen, die wir normalerweise definieren, stellen alle aufrufbare Objekte dar. Das intuitive Gefühl ist, dass wir ein Paar Klammern nach ihnen hinzufügen können, aber wenn wir ein Paar Klammern () auf ein Objekt anwenden können, dann dieses Objekt Es kann als aufrufbares Objekt bezeichnet werden, und die Funktion callable() kann verwendet werden, um zu beurteilen, ob das Objekt ein aufrufbares Objekt ist.

callable(0)      # 函数返回 False
def add(a, b):
    return a + b
callable(add)    # 函数返回 True

Wird die __call__Methode , dann wird auch das Instanzobjekt zu einem Callable Object. Das heißt, der Instanz können Klammern folgen, und das Ergebnis des Aufrufs ist __call__der Inhalt der Methode. Siehe ein Beispiel:

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

Was ist der praktische Nutzen davon? Sehen wir uns ein Beispiel an, in dem __getattr__und verwendet __call__wird, um einen dynamischen Aufruf zu erzielen und eine URL-Zeichenfolge dynamisch zu generieren.

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 Erstellen Sie manuell ein Instanzobjekt

__new__Die Methode ist für die Erstellung eines Instanzobjekts verantwortlich. Die Methode wird automatisch vom Python-Interpreter aufgerufen, wenn das Objekt erstellt wird. Es ist eine Klassenmethode. __new__Nachdem die Methode eine Instanz zurückgibt, ruft der Python-Interpreter weiterhin automatisch die __init__Methode auf, um die Instanz zu initialisieren. Wenn __new__die Methode keinen Wert oder keine Instanz zurückgibt, ruft der Python-Interpreter die __init__Methode nicht automatisch auf. __new__Die Methode dient hauptsächlich dem Vererben einer Klasse (z. B. int, str, tuple), um Programmierern die Möglichkeit zu geben, den Instanziierungsprozess dieser Klassen anzupassen. Es gibt auch die Realisierung von benutzerdefinierten Metaklassen-Metaklassen.

__new__Eine typische Anwendung ist die Erstellung eines Singleton-Musters.

Das Prinzip des Singleton-Modus besteht darin, dem Klassenattribut ein Singleton-Bestimmungsbit-Flag hinzuzufügen und dieses Flag zu verwenden, um zu bestimmen, ob die Klasse instanziiert wurde.Wenn die Klasse instanziiert wurde, wird das instanziierte Objekt zurückgegeben.

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))

Klassen, die von Singleton erben __new__, sind Singletons, sofern sie nicht überschrieben werden.

20.5 Anpassen der Vergleichslogik für zwei Objekte

Die Methode wird ausgelöst, wenn festgestellt wird, ob zwei Objekte gleich sind __eq__. In dieser Methode können Sie Regeln für die Gleichheit zweier Objekte definieren. Es gibt auch __lt__und __gt__-Methoden, die die Regeln für den Vergleich der Größe zweier Objekte definieren. Z.B:

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

Supongo que te gusta

Origin blog.csdn.net/liuchunming033/article/details/107934981
Recomendado
Clasificación