Este artigo destaca os métodos especiais de Python que todos os programadores Python devem conhecer

>
>
>
>
>
>>
Os métodos mágicos ajudam-nos a enriquecer as nossas aplicações. Eles indiretamente adicionam magia ao nosso código Python. Este é um tópico de nível avançado para desenvolvedores Python e eu o recomendo para todos que estão/ou pretendem usar a linguagem de programação Python.
Os métodos mágicos nos dão mais controle sobre como nossa aplicação se comporta.
Este artigo tem como objetivo explicar o que são métodos mágicos e como eles podem ser usados para construir aplicações Python. Ele irá fornecer uma visão geral dos métodos mágicos mais amplamente utilizados para uma série de tipos de dados.
O propósito de delinear os métodos mágicos chave é para que possamos entender se queremos sobrepor esses métodos em nossas classes personalizadas para enriquecer as aplicações.
Métodos mágicos tornam a linguagem de programação Python extremamente poderosa
O que são os métodos mágicos Python?
Os métodos mágicos Python também são conhecidos como métodos especiais ou métodos dunder. Eles são rodeados por sublinhados duplos, por exemplo __init__().
Um objeto pode ter vários métodos mágicos.
Remmbrar tudo em Python é um objeto incluindo uma variável/função/classe, etc. Os objetos são a abstração de python para dados.
Os métodos mágicos são usados para construir e rubricar novos objetos, eles nos ajudam a recuperar um objeto como um dicionário, eles são usados para apagar um objeto entre outras operações. Eles são usados quando o operador + é invocado, ou mesmo quando queremos representar um objeto como uma string.
Embora todos os métodos em Python sejam públicos, a convenção de codificação é cercar todos os métodos privados através de duplo sublinhado __<método>__()
Isto implica que os métodos mágicos são destinados a ser métodos privados. Isso também significa que o chamador de um objeto não deve invocar o método diretamente, pois o método se destina a ser invocado pela classe interna que tem o método mágico.
Podemos sobrepor os métodos mágicos para fornecer nossa própria funcionalidade personalizada.
Explicarei os conceitos de métodos mágicos criando uma classe personalizada e depois darei uma visão geral dos métodos mágicos mais importantes em um inteiro, string, lista e um dicionário.
A medida que avançamos no artigo, ele começará a construir uma imagem muito mais clara do porquê da existência dos métodos mágicos e de como usá-los.
Se você quiser entender a linguagem de programação Python desde o iniciante até um nível avançado, então eu recomendo fortemente o artigo abaixo:
I iniciará o tópico de métodos mágicos criando uma classe personalizada e então eu explicarei como os métodos mágicos são usados.
The Usecase To Understand Magic Methods
No trecho abaixo, eu criei uma classe chamada Human e então instanciei uma instância da classe Human.
Este trecho de código será usado para nos ajudar a entender métodos mágicos.
Nota, o id do objeto humano é do tipo inteiro, o atributo nome é do tipo string, os endereços das propriedades são do tipo lista e os mapas de propriedades são do tipo dicionário.
Eu agrupei os métodos mágicos em várias seções de tipos de dados para facilitar a leitura. No entanto, os mesmos métodos mágicos são encontrados em diferentes tipos de dados.
Os métodos mágicos podem ser sobrepostos para enriquecer a funcionalidade e criar uma lógica personalizada que melhor se adapte às necessidades do negócio.
Class:
Deixe entender os métodos mágicos que estão associados ao objeto humano. Se eu executar o método dir(humano), ele irá listar todas as funções e nomes de atributos do objeto humano.
Existem no total 29 métodos/atributos que estão associados ao objeto humano. Entre eles, 26 são os métodos mágicos.
É um número bastante grande de métodos especiais. Estes métodos são herdados do tipo base da classe Humana. Portanto, eles são os métodos predefinidos que podemos usar/override para enriquecer as classes.
A próxima parte da seção irá explicar os métodos mágicos chave.
__delattr__
Este método é chamado quando tentamos excluir um atributo de uma classe.
Podemos sobrepor a funcionalidade implementando o método na classe Humano:
def __delattr__(self, item):
print('Deleting attribute ' + item)
return object.__delattr__(self, item)
Agora, sempre que tentarmos excluir um atributo, ele exibirá a mensagem: Deleting attribute
Há também o método __setattr__() para atribuir um valor a um atributo e __getattr__() para obter um valor do atributo.
Uma usecase de__delattr__() pode ser para evitar que determinados atributos de um objeto sejam excluídos ou quando queremos executar ações específicas quando um determinado atributo é excluído.
__dict__
Este método retorna um dicionário que representa o objeto. As chaves do dicionário são os atributos do objeto e os valores são os valores dos atributos.
Como uma instância:
human = Human(2, 'Malik').__dict__
print(human)
O código acima retorna:
{‘id’: 2, ‘name’: ‘Malik’, ‘addresses’: , ‘mapas’: {}}
__dir__
Podemos substituir o método dir() substituindo o método __dir__() na classe. Como instância, podemos remover os métodos internos do resultado que é retornado pelo método dir():
__eq__
Este método é chamado quando tentamos executar a operação ==. Vamos considerar que dois objetos humanos são iguais quando seu atributo id é igual mesmo que seu nome seja diferente.
Pode substituir o método __eq__() para alcançar esta funcionalidade:
def __eq__(self, other):
return self.id == other.id
Este agora retornará True:
first = Human(1, 'Farhad')
second = Human(1, 'Malik')
print(first == second)
__format__
Quando tentamos fazer string.format(), o método __formato__() é invocado internamente.
__ge__
Como instância, vamos assumir que existem dois objetos humanos:
first = Human(1, 'Farhad')
second = Human(2, 'Malik')
Consideremos também que nosso projeto tem uma regra que um objeto humano com um Id maior é considerado maior do que o outro objeto humano. Portanto, podemos sobrepor o método __gt__() e implementar a lógica personalizada:
def __ge__(self, other):
return self.id >= other.id
Isso agora retornará Falso porque o id do segundo objeto humano é maior que o primeiro objeto humano:
print(first >= second)
Returns False
Existe também um método __lt__() que é executado quando o operador ≤ é executado.
__hash__
Hashing é usado para converter um objeto em um número inteiro. Hashing é executado quando tentamos definir um item em um dicionário/set.
Um bom algoritmo de hashing resulta em um número menor de colisões de hashing. Nós podemos fornecer nosso próprio algoritmo de hash substituindo o método __hash__().
Consideremos que o id do objeto Humano é suposto ser único em nossa aplicação. O algoritmo __hash__() pode ser sobreposto para retornar o self.id como o inteiro do hash:
def __hash__(self):
return self.id
Podemos criar dois objetos e salvá-los em uma coleção definida. Quando consultamos o comprimento do conjunto, esperamos dois elementos no conjunto porque ambos os objetos têm um id.
first = Human(1, 'Farhad')
second = Human(2, 'Malik')
my_set = set()
print(len(my_set))
#returns 2
Se agora definirmos o id como sendo 1 para ambos os objetos e repetirmos o exercício então veremos apenas 1 elemento no conjunto porque ambos os objetos têm a mesma chave de hash que seu atributo id é o mesmo, mesmo que seu atributo nome seja diferente.
first = Human(1, 'Farhad')
second = Human(1, 'Malik')
my_set = set()
print(len(my_set))
#returns 1
__init__
O método __init__() é executado quando queremos instanciar uma nova instância de uma classe chamando seu construtor.
Como uma instância, quando tentamos executar:
human = Human(1, 'farhad')
Então o método __init__() foi executado.
Nós podemos sobrescrever a funcionalidade e passar nossos próprios argumentos e comportamento personalizados nele também.
Como uma instância, o método __init__() da classe Humano é:
def __init__(self, id, name, addresses=, maps={}):
self.id = id
self.name = name
self.addresses = addresses
self.maps = maps
__init_subclass__
Este é um dos usecases da metaclasse. Quando uma classe é subclassada e seu objeto é criado, então o método __init_subclass__() é chamado.
Essencialmente, o método informa ao pai que ele foi subclassado. Este gancho pode então rubricar todas as subclasses de uma determinada classe. Portanto, o método é usado para registrar subclasses e atribuir valores padrão aos atributos nas subclasses. Assim, ele nos permite personalizar a inicialização de subclasses.
Explicarei como as metaclasses funcionam no meu próximo artigo.
__novo__
Quando queremos instanciar/criar uma nova instância de uma classe então o método __novo__(cls) é executado.
Como uma instância, vamos considerar que queremos imprimir ‘Human criando…’ sempre que o construtor Human() for chamado.
Podemos sobrepor a funcionalidade do método __new__(cls) como mostrado abaixo:
def __new__(cls, *args, **kwargs):
print('Human creating...')
return object.__new__(cls)
Como resultado, Human creating… é impresso quando tentamos criar uma instância:
human = Human(1, 'Farhad', , {'London':2, 'UK':3})
__sizeof__
Este método é chamado quando executamos sys.getizeof(). Ele retorna o tamanho do objeto na memória, em bytes.
__str__
Imprime: id=1. name=Farhad.
A função __str__() deve tentar retornar uma representação amigável do objeto.
__weakref__
Este objeto __weakref__ retorna a lista de referências fracas para o objeto alvo. Essencialmente, ele ajuda a coleta de lixo a informar as referências fracas que o referente foi coletado. Portanto, ele impede que os objetos acessem os indicadores subjacentes.
Integer
Isto nos leva à próxima seção do artigo. Podemos ver que a propriedade id do objeto humano é do tipo int. Se então executarmos dir() na propriedade id e filtrarmos os métodos que estão rodeados de duplo sublinhado, veremos que existem no total 62 métodos mágicos.
print(len(list(filter(lambda x: x.startswith('__') and x.endswith('__'), dir(human1.id)))))
I irá explicar os métodos chave aqui:
__add__
Este método é chamado quando tentamos adicionar dois números.
Como uma instância:
human.id + 2 é o mesmo que human.id.__add__(2)
__
Este método é executado quando tentamos usar o operador & e.g.:
return self & another_value
__bool__
Este método é executado quando tentamos executar a verificação booleana em um objeto e.g.:
self != 123
__floordiv__
Este método é executado quando tentamos executar o //operador.
__getnewargs__
Ocasionalmente, nós picamos objetos em Python. Pickling cria uma representação em byte-stream de um objeto na memória que pode ser salvo no disco se necessário.
O método __getnewargs__() informa o processo de pickling sobre como ele precisa carregar de volta o objeto em pickles para recriar o objeto alvo. Em particular, como o objeto precisa ser criado, passando nos argumentos para o novo método(). Portanto, o nome ‘get new args’.
__index__
Consequentemente, um objeto pode ser convertido em um inteiro executando o método __index__(). Podemos também sobrepor o método e fornecer nossa própria funcionalidade de como o índice precisa ser gerado.
__invert__
Este método é executado quando usamos o operador ~.
Como uma instância:
first = Human(1, 'Farhad')
print(~first.id)
É o mesmo que executar:
first = Human(1, 'Farhad')
print(first.id.__invert__())
__lshift__
Este método nos dá um deslocamento à esquerda de um valor, por exemplo, self << valor. Podemos sobrecarregar o operador << substituindo o método __lshift__().
Nota: __rshift__() é executado quando executamos o operador >>> operador.
__mod__
Este método é chamado quando usamos o operador %.
__neg__
Este método é executado quando usamos o operador negativo – por exemplo.
first.id — second.id
__subclasshook__
Este método pode ser substituído para personalizar o método issubclass(). Essencialmente, ele retorna True se uma classe for uma subclasse e False se não for. O método também retorna NotImplemented que permite que o algoritmo existente seja usado.
O método pode personalizar o resultado do método issubclass().
String
Isto nos leva à próxima seção do artigo.
Vemos que a propriedade do nome do objeto humano é do tipo string. Se depois executarmos dir(human.name) na propriedade e filtrarmos os métodos que estão rodeados de duplo sublinhado, vamos notar que existem no total 33 métodos mágicos.
print(len(list(filter(lambda x: x.startswith('__') and x.endswith('__'), dir(human1.name)))))
Explicarei os 4 métodos chave aqui, pois o resto do artigo já destacou a maioria dos métodos mágicos.
__contém__
Este método é executado quando tentamos verificar se um determinado caractere existe.
__len__
Este método retorna o comprimento da string. Ele é executado quando executamos o método len().
Se queremos contar apenas caracteres específicos para calcular o comprimento da string então o método __()__ pode ser sobrescrito para fornecer essa funcionalidade.
__repr__
Este método é executado quando queremos criar uma representação amigável ao desenvolvedor de um objeto.
Nota, a __repr__ é executada quando imprimimos(objeto) se não tivermos uma implementação __str__() em nossa classe.
def __repr__(self):
return f'id={self.id} ({type(self.id)}). name={self.name} ({type(self.name)})'print(Human(1, 'Farhad'))
Esta irá imprimir:
id=1 (<classe ‘int’>). name=Farhad (<classe ‘str’>)
O método __repr__() deve ser destinado a produzir a representação oficial de um objeto.
__iadd__
Occasionalmente, nós usamos um operador de adição junto com a atribuição e.g.
self.id += 1
Este é equivalente a self.id = self.id + 1
O método iadd() é executado quando executamos a adição com a atribuição.
Outras vezes, o método __ipow__() é executado quando **= é executado.
O método mágico __iand__() é para executar um bitwise AND com atribuição e __ior__() é chamado quando tentamos fazer != tal como: i != j
List
Isto nos leva à próxima seção do artigo. A propriedade de endereços do objeto humano é do tipo lista. Se então executarmos dir(human.addresses) na propriedade addresses e filtrarmos os métodos que estão rodeados de sublinhados duplos, vamos encontrar que existem no total 35 métodos mágicos.
print(len(list(filter(lambda x: x.startswith('__') and x.endswith('__'), dir(human1.addresses)))))
Explicarei os métodos chave aqui:
__reduce__
Quando um objeto é picleado, o método __reduce__() é executado para retornar um objeto que ajuda o pickle a entender como construí-lo de volta.
__reduce_ex__
O método __reduce_ex__() é preferido pelo pickle ao invés do método __reduce__().
O método __reduce_ex__() leva um argumento inteiro que é a versão do protocolo. Ele fornece compatibilidade retroativa para decapagem e é usado para construir o fluxo de bytes de picles para o objeto.
__reversed__
O método __reversed__() é executado quando tentamos inverter uma coleção na seqüência inversa.
É executado quando o método reverse(collection) ou collection.reverse() é chamado. Algumas vezes, decidimos alterar a funcionalidade do método reverse().
Alterando o método __reversed__(), podemos alcançar o resultado desejado.
Dicionário
Isto nos leva à quinta seção do artigo.
Dicionário é um dos principais tipos de construção em Python. Se executarmos dir(human.maps) e filtrarmos os métodos que estão rodeados de duplo underscores, vamos encontrar que existem no total 29 métodos mágicos.
print(len(list(filter(lambda x: x.startswith('__') and x.endswith('__'), dir(human1.maps)))))
Entre os 29 métodos mágicos, vou explicar os 4 métodos chave aqui:
__delitem__
Este método é executado quando apagamos um item e.g.
del dictionary
__getitem__
Este método é executado quando tentamos obter um item para uma chave:
item = dictionary
__setitem__
Este método é executado quando tentamos definir um item no dicionário:
dictionary = item
__iter__
Este método retorna um iterador para a coleção. Um iterador nos ajuda a iterar sobre uma coleção.
Podemos sobrepor como o iterador() é executado substituindo o método __iter__().
Pouco, uma nota em __call__()
E se quisermos tornar nosso objeto chamável? Vamos considerar que queríamos tornar o objeto humano em uma função callable human()?
O método__call__() nos permite tratar as classes como funções.
human = Human(1, 'Farhad')
human()
Possibilitamos essa funcionalidade fornecendo a implementação do método mágico __call__() em nossa classe Humana.
Isso irá imprimir:
Você tentou chamar
Argumentos: ()
Argumentos de Palavras-Chave: {}
id=1 (<classe ‘int’>). name=Farhad (<classe ‘str’>)
Call completed
Altrapassando o método __call__(), podemos agora implementar um decorador para retornar um objeto como uma função ou mesmo chamar aquelas bibliotecas que aceitam funções como argumentos, passando nos objetos reais.
Sumário
Este é um tópico de nível avançado para desenvolvedores Python e eu recomendo a todos que estão/ou pretendem usar a linguagem de programação Python.
Este artigo pretende explicar o que são métodos mágicos e como eles podem ser usados para construir aplicações Python. Ele forneceu uma visão geral dos métodos mágicos mais usados em uma classe customizada, inteiros, strings, listas e tipos de dados de dicionário.
>
Embora cada método em Python seja público, a convenção de codificação é cercar todos os métodos privados através de duplo sublinhado __<method>__()
Isto implica que os métodos mágicos têm a intenção de ser métodos privados. Isto também significa que o chamador de um objeto não deve invocar diretamente o método e o método é invocado pela classe interna que tem o método mágico. Os métodos mágicos nos permitem ter mais controle sobre como nossa aplicação se comporta.
Os métodos mágicos podem ser sobrescritos para enriquecer a funcionalidade e criar uma lógica personalizada que melhor se adapte às necessidades do negócio.
O propósito de delinear os métodos mágicos chave é entender se queremos sobrescrever esses métodos em nossas classes personalizadas para enriquecer as aplicações.