Notas principais do Python para desenvolvimento de teste (20): classes integradas de métodos avançados

Quando definimos uma classe, o Python nos fornece automaticamente alguns métodos, a maioria dos quais é herdada da classe de objeto ou classe de tipo. Podemos substituir esses métodos para implementar operações específicas.

20.1 Tornando os objetos mais fáceis de ler quando impressos

Imprimir o objeto com print() exibirá __str__()o conteúdo da função. Ao executar a instância diretamente, o objeto impresso exibirá __repr__()o conteúdo da função. Portanto, através da implementação __str__()e __repr__()desses dois métodos, a impressão do objeto pode estar mais de acordo com a leitura humana. por exemplo

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 Fazendo objetos de classe suportarem iteração

Sabemos que todos os tipos de contêiner suportam ... in ... para loops iterativos. A instrução for realmente faz duas coisas. A primeira coisa é obter um iterador, ou seja, a __iter__()função é chamada. A segunda coisa é o processo de loop, chamando __next__()funções em um loop. Na verdade, uma classe personalizada, desde que esses dois métodos sejam implementados, o objeto da classe também pode ser iterado pelo loop for.

Por exemplo, a sequência de Fibonacci, implementada com uma classe:

class Fib:
    def __init__(self):
        self.a, self.b = 0, 1  # 初始化两个计数器a,bdef __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 Tornando objetos chamáveis

As funções, funções internas e classes que normalmente definimos são todos objetos que podem ser chamados. A sensação intuitiva é que podemos adicionar um par de parênteses depois deles, mas se pudermos aplicar um par de parênteses () a um objeto, esse objeto Ele pode ser chamado de objeto que pode ser chamado, e a função callable() pode ser usada para julgar se o objeto é um objeto que pode ser chamado.

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

Se o __call__método , o objeto de instância também se tornará um objeto que pode ser chamado. Ou seja, a instância pode ser seguida por parênteses e o resultado da chamada é __call__o conteúdo do método. Veja um exemplo:

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

Qual é a utilidade prática disso? Vejamos um exemplo, usando __getattr__e __call__, para obter uma chamada dinâmica, gere dinamicamente uma string de 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 Criar manualmente um objeto de instância

__new__O método é responsável por criar um objeto instância.O método é chamado automaticamente pelo interpretador Python quando o objeto é criado.É um método de classe. __new__Depois que o método retornar uma instância, o interpretador Python continuará a chamar automaticamente o __init__método para inicializar a instância. Se __new__o método não retornar um valor ou não retornar uma instância, o interpretador Python não chamará automaticamente o __init__método. __new__O método é principalmente ao herdar uma classe (como int, str, tuple), para fornecer aos programadores a oportunidade de personalizar o processo de instanciação dessas classes. Há também a realização de metaclasse de metaclasse customizada.

__new__Uma aplicação típica é criar um padrão singleton.

O princípio do modo singleton é adicionar um sinalizador de bit de determinação singleton ao atributo de classe e usar esse sinalizador para determinar se a classe foi instanciada.Se a classe foi instanciada, o objeto instanciado é retornado.

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

As classes que herdam de Singleton __new__serão singletons, a menos que sejam substituídas.

20.5 Personalizando a lógica de comparação de dois objetos

O método é acionado quando é determinado se dois objetos são iguais __eq__. Neste método você pode definir regras para igualdade de dois objetos. Existem também métodos __lt__e __gt__, que definem as regras para comparar o tamanho de dois objetos. Por exemplo:

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

Acho que você gosta

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