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.