No Python, o que são metaclasses e para que as usamos?
fonte
No Python, o que são metaclasses e para que as usamos?
Uma metaclasse é a classe de uma classe. Uma classe define como uma instância da classe (ou seja, um objeto) se comporta, enquanto uma metaclasse define como uma classe se comporta. Uma classe é uma instância de uma metaclasse.
Enquanto no Python você pode usar chamadas arbitrárias para metaclasses (como mostra Jerub ), a melhor abordagem é torná-la uma classe real. type
é a metaclasse usual em Python. type
é em si uma classe e é do seu próprio tipo. Você não poderá recriar algo como type
puramente no Python, mas o Python trapaceia um pouco. Para criar sua própria metaclasse no Python, você realmente quer apenas subclassificar type
.
Uma metaclasse é mais comumente usada como uma fábrica de classes. Quando você cria um objeto chamando a classe, o Python cria uma nova classe (quando executa a instrução 'class') chamando a metaclasse. Combinadas com o normal __init__
e os __new__
métodos, as metaclasses permitem que você faça "coisas extras" ao criar uma classe, como registrar a nova classe com algum registro ou substituir a classe por algo completamente diferente.
Quando a class
instrução é executada, o Python primeiro executa o corpo da class
instrução como um bloco de código normal. O espaço para nome resultante (um dict) mantém os atributos da classe a ser. A metaclasse é determinada observando as classes básicas da classe a ser (as metaclasses são herdadas), o __metaclass__
atributo da classe a ser (se houver) ou a __metaclass__
variável global. A metaclasse é então chamada com o nome, bases e atributos da classe para instancia-la.
No entanto, as metaclasses realmente definem o tipo de uma classe, não apenas uma fábrica, para que você possa fazer muito mais com elas. Você pode, por exemplo, definir métodos normais na metaclasse. Esses métodos de metaclasse são como métodos de classe, pois podem ser chamados na classe sem uma instância, mas também não são como métodos de classe, pois não podem ser chamados em uma instância da classe. type.__subclasses__()
é um exemplo de método na type
metaclasse. Você também pode definir os métodos 'mágicos' normais, como __add__
, __iter__
e __getattr__
, para implementar ou alterar como a classe se comporta.
Aqui está um exemplo agregado dos bits e partes:
def make_hook(f):
"""Decorator to turn 'foo' method into '__foo__'"""
f.is_hook = 1
return f
class MyType(type):
def __new__(mcls, name, bases, attrs):
if name.startswith('None'):
return None
# Go over attributes and see if they should be renamed.
newattrs = {}
for attrname, attrvalue in attrs.iteritems():
if getattr(attrvalue, 'is_hook', 0):
newattrs['__%s__' % attrname] = attrvalue
else:
newattrs[attrname] = attrvalue
return super(MyType, mcls).__new__(mcls, name, bases, newattrs)
def __init__(self, name, bases, attrs):
super(MyType, self).__init__(name, bases, attrs)
# classregistry.register(self, self.interfaces)
print "Would register class %s now." % self
def __add__(self, other):
class AutoClass(self, other):
pass
return AutoClass
# Alternatively, to autogenerate the classname as well as the class:
# return type(self.__name__ + other.__name__, (self, other), {})
def unregister(self):
# classregistry.unregister(self)
print "Would unregister class %s now." % self
class MyObject:
__metaclass__ = MyType
class NoneSample(MyObject):
pass
# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)
class Example(MyObject):
def __init__(self, value):
self.value = value
@make_hook
def add(self, other):
return self.__class__(self.value + other.value)
# Will unregister the class
Example.unregister()
inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()
print inst + inst
class Sibling(MyObject):
pass
ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__
class A(type):pass<NEWLINE>class B(type,metaclass=A):pass<NEWLINE>b.__class__ = b
__metaclass__
não é suportado no Python 3. No uso do Python 3class MyObject(metaclass=MyType)
, consulte python.org/dev/peps/pep-3115 e a resposta abaixo.Classes como objetos
Antes de entender as metaclasses, você precisa dominar as classes em Python. E o Python tem uma idéia muito peculiar do que são as classes, emprestadas da linguagem Smalltalk.
Na maioria dos idiomas, as classes são apenas partes de código que descrevem como produzir um objeto. Isso também é verdade no Python:
Mas as aulas são mais do que isso em Python. Classes também são objetos.
Sim, objetos.
Assim que você usa a palavra-chave
class
, o Python a executa e cria um OBJECT. A instruçãocria na memória um objeto com o nome "ObjectCreator".
Esse objeto (a classe) é capaz de criar objetos (as instâncias), e é por isso que é uma classe .
Mas ainda assim, é um objeto e, portanto:
por exemplo:
Criando Classes Dinamicamente
Como as classes são objetos, você pode criá-las rapidamente, como qualquer objeto.
Primeiro, você pode criar uma classe em uma função usando
class
:Mas não é tão dinâmico, pois você ainda precisa escrever a classe toda.
Como as classes são objetos, elas devem ser geradas por algo.
Quando você usa a
class
palavra - chave, o Python cria esse objeto automaticamente. Mas, como na maioria das coisas em Python, ele oferece uma maneira de fazer isso manualmente.Lembra da função
type
? A boa e antiga função que permite que você saiba que tipo de objeto é:Bem,
type
tem uma habilidade completamente diferente, também pode criar classes em tempo real.type
pode pegar a descrição de uma classe como parâmetros e retornar uma classe.(Eu sei, é bobagem que a mesma função possa ter dois usos completamente diferentes, de acordo com os parâmetros que você passa para ela. É um problema devido à compatibilidade com versões anteriores no Python)
type
funciona desta maneira:Onde:
name
: nome da classebases
: tupla da classe pai (por herança, pode estar vazia)attrs
: dicionário contendo nomes e valores de atributospor exemplo:
pode ser criado manualmente desta maneira:
Você notará que usamos "MyShinyClass" como o nome da classe e como a variável para manter a referência da classe. Eles podem ser diferentes, mas não há razão para complicar as coisas.
type
aceita um dicionário para definir os atributos da classe. Assim:Pode ser traduzido para:
E usado como uma classe normal:
E, é claro, você pode herdar dele, portanto:
seria:
Eventualmente, você desejará adicionar métodos à sua classe. Apenas defina uma função com a assinatura apropriada e atribua-a como um atributo.
E você pode adicionar ainda mais métodos depois de criar dinamicamente a classe, assim como adicionar métodos a um objeto de classe criado normalmente.
Você vê para onde estamos indo: no Python, as classes são objetos e você pode criar uma classe dinamicamente.
Isso é o que o Python faz quando você usa a palavra-chave
class
e o faz usando uma metaclasse.O que são metaclasses (finalmente)
Metaclasses são as 'coisas' que criam classes.
Você define classes para criar objetos, certo?
Mas aprendemos que as classes Python são objetos.
Bem, são as metaclasses que criam esses objetos. São as classes das classes, você pode imaginá-las desta maneira:
Você viu que isso
type
permite que você faça algo assim:É porque a função
type
é de fato uma metaclasse.type
é a metaclasse que o Python usa para criar todas as classes nos bastidores.Agora você se pergunta por que diabos está escrito em letras minúsculas, e não
Type
?Bem, acho que é uma questão de consistência com
str
a classe que cria objetos de strings eint
a classe que cria objetos de número inteiro.type
é apenas a classe que cria objetos de classe.Você vê isso verificando o
__class__
atributoTudo, e eu quero dizer tudo, é um objeto em Python. Isso inclui ints, strings, funções e classes. Todos eles são objetos. E todos eles foram criados a partir de uma classe:
Agora, qual é o
__class__
de qualquer um__class__
?Portanto, uma metaclasse é exatamente o que cria objetos de classe.
Você pode chamá-lo de 'fábrica de classe', se desejar.
type
é a metaclasse interna que o Python usa, mas é claro, você pode criar sua própria metaclasse.O
__metaclass__
atributoNo Python 2, você pode adicionar um
__metaclass__
atributo ao escrever uma classe (consulte a próxima seção para obter a sintaxe do Python 3):Se você fizer isso, o Python usará a metaclasse para criar a classe
Foo
.Cuidado, é complicado.
Você escreve
class Foo(object)
primeiro, mas o objeto de classeFoo
ainda não foi criado na memória.O Python procurará
__metaclass__
na definição de classe. Se o encontrar, ele será usado para criar a classe de objetoFoo
. Caso contrário, será usadotype
para criar a classe.Leia isso várias vezes.
Quando você faz:
Python faz o seguinte:
Existe um
__metaclass__
atributo emFoo
?Se sim, criar na memória de um objeto de classe (eu disse um objeto de classe, fique comigo aqui), com o nome
Foo
usando o que está em__metaclass__
.Se o Python não conseguir encontrar
__metaclass__
, ele procurará um__metaclass__
no nível MODULE e tentará fazer o mesmo (mas apenas para classes que não herdam nada, basicamente classes antigas).Então, se não conseguir encontrar nenhuma
__metaclass__
, usará aBar
metaclasse do próprio (o primeiro pai) (que pode ser o padrãotype
) para criar o objeto de classe.Tenha cuidado aqui, pois o
__metaclass__
atributo não será herdado, a metaclasse do pai (Bar.__class__
) será. SeBar
usado um__metaclass__
atributo criadoBar
comtype()
(e nãotype.__new__()
), as subclasses não herdarão esse comportamento.Agora, a grande questão é: o que você pode colocar
__metaclass__
?A resposta é: algo que pode criar uma classe.
E o que pode criar uma classe?
type
, ou qualquer coisa que a subclasse ou use.Metaclasses em Python 3
A sintaxe para definir a metaclasse foi alterada no Python 3:
ou seja, o
__metaclass__
atributo não é mais usado, em favor de um argumento de palavra-chave na lista de classes base.O comportamento das metaclasses, no entanto, permanece basicamente o mesmo .
Uma coisa adicionada às metaclasses no python 3 é que você também pode passar atributos como argumentos de palavra-chave para uma metaclasse, assim:
Leia a seção abaixo para saber como o python lida com isso.
Metaclasses personalizadas
O principal objetivo de uma metaclasse é alterar a classe automaticamente, quando é criada.
Você costuma fazer isso para APIs, onde deseja criar classes que correspondam ao contexto atual.
Imagine um exemplo estúpido, em que você decide que todas as classes no seu módulo devem ter seus atributos escritos em maiúsculas. Existem várias maneiras de fazer isso, mas uma maneira é definir
__metaclass__
no nível do módulo.Dessa forma, todas as classes deste módulo serão criadas usando essa metaclasse, e só precisamos dizer à metaclasse para transformar todos os atributos em maiúsculas.
Felizmente,
__metaclass__
pode realmente ser exigível, não precisa ser uma classe formal (eu sei, algo com 'classe' no nome não precisa ser uma classe, vai entender ... mas é útil).Então, começaremos com um exemplo simples, usando uma função
Vamos checar:
Agora, vamos fazer exatamente o mesmo, mas usando uma classe real para uma metaclasse:
Vamos reescrever o acima, mas com nomes de variáveis mais curtos e mais realistas agora que sabemos o que eles significam:
Você pode ter notado o argumento extra
cls
. Não há nada de especial nisso:__new__
sempre recebe a classe em que está definida, como primeiro parâmetro. Assim como você temself
para métodos comuns que recebem a instância como primeiro parâmetro ou a classe que define os métodos de classe.Mas isso não é adequado OOP. Estamos ligando
type
diretamente e não estamos substituindo ou ligando para os pais__new__
. Vamos fazer isso:Podemos torná-lo ainda mais limpo usando
super
, o que facilitará a herança (porque sim, você pode ter metaclasses, herdando de metaclasses, herdando do tipo):Ah, e no python 3, se você fizer essa chamada com argumentos de palavra-chave, assim:
Isso se traduz na metaclasse para usá-lo:
É isso aí. Não há realmente mais nada sobre metaclasses.
A razão por trás da complexidade do código que usa metaclasses não é por causa de metaclasses, é porque você costuma usar metaclasses para fazer coisas distorcidas que dependem de introspecção, manipulação de herança, vars como
__dict__
etc.De fato, as metaclasses são especialmente úteis para fazer magia negra e, portanto, coisas complicadas. Mas, por si só, são simples:
Por que você usaria classes de metaclasses em vez de funções?
Como você
__metaclass__
pode aceitar qualquer chamada, por que você usaria uma classe, uma vez que é obviamente mais complicada?Existem vários motivos para fazer isso:
UpperAttrMetaclass(type)
, você sabe o que vai seguir__new__
,__init__
e__call__
. O que permitirá que você faça coisas diferentes. Mesmo que geralmente você possa fazer tudo isso__new__
, algumas pessoas ficam mais confortáveis usando__init__
.Por que você usaria metaclasses?
Agora a grande questão. Por que você usaria algum recurso obscuro e propenso a erros?
Bem, geralmente você não:
Guru do Python Tim Peters
O principal caso de uso de uma metaclasse é a criação de uma API. Um exemplo típico disso é o Django ORM. Ele permite que você defina algo como isto:
Mas se você fizer isso:
Não retornará um
IntegerField
objeto. Ele retornará umint
e pode levá-lo diretamente do banco de dados.Isso é possível porque
models.Model
define__metaclass__
e usa alguma mágica que transformará o quePerson
você acabou de definir com instruções simples em um gancho complexo para um campo de banco de dados.O Django faz com que algo complexo pareça simples, expondo uma API simples e usando metaclasses, recriando código dessa API para fazer o trabalho real nos bastidores.
A última palavra
Primeiro, você sabe que classes são objetos que podem criar instâncias.
Bem, de fato, as classes são instâncias. De metaclasses.
Tudo é um objeto em Python, e todos são instâncias de classes ou instâncias de metaclasses.
Exceto por
type
.type
é realmente sua própria metaclasse. Isso não é algo que você pode reproduzir em Python puro, e isso é feito trapaceando um pouco no nível de implementação.Em segundo lugar, as metaclasses são complicadas. Você pode não querer usá-los para alterações de classe muito simples. Você pode alterar as classes usando duas técnicas diferentes:
Em 99% das vezes você precisa de alteração de classe, é melhor usá-las.
Mas 98% das vezes, você não precisa de alteração de classe.
fonte
models.Model
ele não usa,__metaclass__
mas fazclass Model(metaclass=ModelBase):
referência a umaModelBase
classe que faz a mágica da metaclasse acima mencionada. Ótimo post! Aqui está a fonte de Django: github.com/django/django/blob/master/django/db/models/...__metaclass__
atributo não seja herdado, a metaclasse do pai (Bar.__class__
) será. SeBar
usado um__metaclass__
atributo criadoBar
comtype()
(e nãotype.__new__()
), as subclasses não herdarão esse comportamento. >> - Você / alguém poderia explicar um pouco mais essa passagem?Now you wonder why the heck is it written in lowercase, and not Type?
- bem, porque ele é implementado em C - é a mesma razão defaultdict é minúsculas enquanto OrderedDict (em python 2) é CamelCase normaisObserve que esta resposta é para o Python 2.x, como foi escrito em 2008, as metaclasses são ligeiramente diferentes no 3.x.
Metaclasses são o molho secreto que faz a 'classe' funcionar. A metaclasse padrão para um novo objeto de estilo é chamada de 'tipo'.
Metaclasses levam 3 args. ' name ', ' bases ' e ' dict '
Aqui é onde o segredo começa. Procure de onde o nome, as bases e o ditado vêm neste exemplo de definição de classe.
Vamos definir uma metaclasse que demonstrará como ' class: ' a chama.
E agora, um exemplo que realmente significa alguma coisa, isso tornará automaticamente as variáveis na lista "atributos" configuradas na classe e definidas como Nenhuma.
Observe que o comportamento mágico que
Initialised
obtém com a metaclasseinit_attributes
não é passado para uma subclasse deInitialised
.Aqui está um exemplo ainda mais concreto, mostrando como você pode subclasse 'type' para criar uma metaclasse que executa uma ação quando a classe é criada. Isso é bastante complicado:
fonte
Outros explicaram como as metaclasses funcionam e como elas se encaixam no sistema de tipos Python. Aqui está um exemplo do que eles podem ser usados. Em uma estrutura de teste que escrevi, eu queria acompanhar a ordem em que as classes foram definidas, para poder instancia-las posteriormente nessa ordem. Achei mais fácil fazer isso usando uma metaclasse.
Tudo o que é uma subclasse
MyType
recebe um atributo de classe_order
que registra a ordem em que as classes foram definidas.fonte
__init__(self)
diztype(self)._order = MyBase.counter; MyBase.counter += 1
?Um uso para metaclasses é adicionar novas propriedades e métodos a uma instância automaticamente.
Por exemplo, se você olhar para os modelos do Django , sua definição parecerá um pouco confusa. Parece que você está apenas definindo propriedades de classe:
No entanto, no tempo de execução, os objetos Person são preenchidos com todos os tipos de métodos úteis. Veja a fonte para uma metaclasseria incrível.
fonte
Eu acho que a introdução do ONLamp à programação em metaclasse está bem escrita e fornece uma boa introdução ao tópico, apesar de já ter vários anos de idade.
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (arquivado em https://web.archive.org/web/20080206005253/http://www.onlamp. com / pub / a / python / 2003/04/17 / metaclasses.html )
Em resumo: Uma classe é um plano para a criação de uma instância, uma metaclasse é um plano para a criação de uma classe. Pode-se ver facilmente que, em Python, as classes também precisam ser objetos de primeira classe para permitir esse comportamento.
Eu nunca escrevi um, mas acho que um dos usos mais agradáveis das metaclasses pode ser visto na estrutura do Django . As classes de modelo usam uma abordagem de metaclasse para permitir um estilo declarativo de escrever novos modelos ou classes de formulário. Enquanto a metaclasse está criando a classe, todos os membros têm a possibilidade de personalizar a própria classe.
O que resta a dizer é: Se você não sabe o que são metaclasses, a probabilidade de não precisar delas é de 99%.
fonte
TLDR: Uma metaclasse instancia e define o comportamento de uma classe, assim como uma classe instancia e define o comportamento de uma instância.
Pseudo-código:
O acima deve parecer familiar. Bem, de onde
Class
vem? É uma instância de uma metaclasse (também pseudocódigo):Em código real, podemos passar a metaclasse padrão
type
, tudo o que precisamos para instanciar uma classe e obtemos uma classe:Colocando de maneira diferente
Uma classe é para uma instância como uma metaclasse é para uma classe.
Quando instanciamos um objeto, obtemos uma instância:
Da mesma forma, quando definimos uma classe explicitamente com a metaclasse padrão
type
, a instanciamos:Em outras palavras, uma classe é uma instância de uma metaclasse:
Em outras palavras, uma metaclasse é uma classe de classe.
Quando você escreve uma definição de classe e o Python a executa, ele usa uma metaclasse para instanciar o objeto de classe (que, por sua vez, será usado para instanciar instâncias dessa classe).
Assim como podemos usar as definições de classe para alterar o comportamento das instâncias de objetos personalizados, podemos usar uma definição de classe de metaclasse para alterar a maneira como um objeto de classe se comporta.
Para que eles podem ser usados? Dos documentos :
No entanto, geralmente é recomendável que os usuários evitem usar metaclasses, a menos que seja absolutamente necessário.
Você usa uma metaclasse toda vez que cria uma classe:
Quando você escreve uma definição de classe, por exemplo, assim,
Você instancia um objeto de classe.
É o mesmo que chamar funcionalmente
type
com os argumentos apropriados e atribuir o resultado a uma variável com esse nome:Observe que algumas coisas são adicionadas automaticamente
__dict__
ao espaço para nome:A metaclasse do objeto que criamos, em ambos os casos, é
type
.(Uma observação lateral sobre o conteúdo da classe
__dict__
:__module__
existe porque as classes precisam saber onde estão definidas__dict__
e__weakref__
existem porque não definimos__slots__
- se definirmos__slots__
, economizaremos um pouco de espaço nas instâncias, como podemos proibir__dict__
e__weakref__
excluí-los. Por exemplo:... mas eu discordo.)
Podemos estender
type
como qualquer outra definição de classe:Aqui está o padrão
__repr__
das classes:Uma das coisas mais valiosas que podemos fazer por padrão ao escrever um objeto Python é fornecê-lo
__repr__
. Quando ligamoshelp(repr)
, aprendemos que há um bom teste para um__repr__
que também exige um teste de igualdade -obj == eval(repr(obj))
. A implementação simples a seguir de__repr__
e__eq__
para instâncias de classe da nossa classe type fornece uma demonstração que pode melhorar o padrão__repr__
das classes:Então agora, quando criamos um objeto com essa metaclasse, o
__repr__
eco na linha de comando fornece uma visão muito menos feia do que o padrão:Com um bom
__repr__
definido para a instância da classe, temos uma capacidade mais forte de depurar nosso código. No entanto, é muitoeval(repr(Class))
improvável verificar com (uma vez que as funções seriam bastante difíceis de avaliar a partir de seus padrões__repr__
).Um uso esperado:
__prepare__
um espaço para nomeSe, por exemplo, queremos saber em que ordem os métodos de uma classe são criados, poderíamos fornecer um ditado ordenado como o espaço para nome da classe. Nós faríamos isso com o
__prepare__
qual retorna o dict de namespace para a classe, se for implementado no Python 3 :E uso:
E agora temos um registro da ordem em que esses métodos (e outros atributos de classe) foram criados:
Observe que este exemplo foi adaptado da documentação - a nova enumeração na biblioteca padrão faz isso.
Então, o que fizemos foi instanciar uma metaclasse criando uma classe. Também podemos tratar a metaclasse como trataríamos com qualquer outra classe. Ele tem uma ordem de resolução de método:
E tem aproximadamente o correto
repr
(que não podemos mais avaliar, a menos que possamos encontrar uma maneira de representar nossas funções.):fonte
Atualização do Python 3
Existem (neste momento) dois métodos principais em uma metaclasse:
__prepare__
e__new__
__prepare__
permite fornecer um mapeamento personalizado (como umOrderedDict
) para ser usado como espaço para nome enquanto a classe está sendo criada. Você deve retornar uma instância do espaço para nome que escolher. Se você não implementar__prepare__
um normaldict
é usado.__new__
é responsável pela criação / modificação real da classe final.Uma metaclasse simples, sem nada a ver, gostaria:
Um exemplo simples:
Digamos que você queira que um código de validação simples seja executado em seus atributos - como sempre deve ser um
int
ou umstr
. Sem uma metaclasse, sua classe seria algo como:Como você pode ver, você deve repetir o nome do atributo duas vezes. Isso possibilita erros de digitação, além de bugs irritantes.
Uma metaclasse simples pode solucionar esse problema:
É assim que a metaclasse seria (sem usar,
__prepare__
pois não é necessária):Uma amostra de:
produz:
Nota : Este exemplo é bastante simples, também poderia ter sido realizado com um decorador de classe, mas presumivelmente uma metaclasse real estaria fazendo muito mais.
A classe 'ValidateType' para referência:
fonte
__set_name__(cls, name)
no descritor (ValidateType
) para definir o nome no descritor (self.name
e também neste casoself.attr
). Isso foi adicionado para não ter que se aprofundar nas metaclasses para esse caso de uso comum específico (consulte PEP 487).Função do
__call__()
método de uma metaclasse ao criar uma instância de classeSe você tiver feito programação em Python por mais de alguns meses, acabará encontrando um código parecido com este:
O último é possível quando você implementa o
__call__()
método mágico na classe.O
__call__()
método é chamado quando uma instância de uma classe é usada como uma chamada. Mas, como vimos nas respostas anteriores, uma classe em si é uma instância de uma metaclasse; portanto, quando usamos a classe como uma chamada (por exemplo, quando criamos uma instância dela), na verdade, estamos chamando o__call__()
método da metaclasse . Neste ponto, a maioria dos programadores de Python está um pouco confusa, porque eles disseram que, ao criar uma instância como essa,instance = SomeClass()
você está chamando seu__init__()
método. Alguns que cavou um pouco mais profundo saber que antes__init__()
não__new__()
. Bem, hoje outra camada de verdade está sendo revelada, antes que__new__()
haja a metaclasse__call__()
.Vamos estudar a cadeia de chamada de método especificamente da perspectiva de criar uma instância de uma classe.
Essa é uma metaclasse que registra exatamente o momento antes de uma instância ser criada e no momento em que está prestes a devolvê-la.
Esta é uma classe que usa essa metaclasse
E agora vamos criar uma instância de
Class_1
Observe que o código acima não faz nada além de registrar as tarefas. Cada método delega o trabalho real à implementação de seu pai, mantendo assim o comportamento padrão. Como
type
éMeta_1
a classe pai (type
sendo a metaclasse pai padrão) e considerando a sequência de pedidos da saída acima, agora temos uma pista sobre qual seria a pseudo implementação detype.__call__()
:Podemos ver que o
__call__()
método da metaclasse é o primeiro chamado. Em seguida, delega a criação da instância para o__new__()
método da classe e a inicialização para a instância__init__()
. É também o que retorna a instância.Do exposto acima, decorre que a metaclasse
__call__()
também tem a oportunidade de decidir se uma chamadaClass_1.__new__()
ouClass_1.__init__()
será eventualmente feita. Ao longo de sua execução, ele poderia realmente retornar um objeto que não foi tocado por nenhum desses métodos. Tomemos, por exemplo, esta abordagem para o padrão singleton:Vamos observar o que acontece ao tentar criar repetidamente um objeto do tipo
Class_2
fonte
Uma metaclasse é uma classe que informa como (algumas) outras classes devem ser criadas.
Este é um caso em que vi a metaclasse como uma solução para o meu problema: eu tinha um problema muito complicado, que provavelmente poderia ter sido resolvido de maneira diferente, mas optei por resolvê-lo usando uma metaclasse. Devido à complexidade, é um dos poucos módulos que escrevi em que os comentários no módulo superam a quantidade de código que foi escrito. Aqui está...
fonte
A versão tl; dr
A
type(obj)
função fornece o tipo de um objeto.O
type()
de uma classe é sua metaclasse .Para usar uma metaclasse:
type
é a sua própria metaclasse. A classe de uma classe é uma metaclasse - o corpo de uma classe são os argumentos passados para a metaclasse que é usada para construir a classe.Aqui você pode ler sobre como usar metaclasses para personalizar a construção de classes.
fonte
type
é realmente umametaclass
- uma classe que cria outras classes. A maioriametaclass
são as subclasses detype
. Ometaclass
recebe anew
classe como seu primeiro argumento e fornece acesso ao objeto de classe com os detalhes mencionados abaixo:Note:
Observe que a classe não foi instanciada em nenhum momento; o simples ato de criar a classe acionou a execução do
metaclass
.fonte
As classes Python são elas mesmas objetos - como no exemplo - de sua meta-classe.
A metaclasse padrão, que é aplicada quando você determina as classes como:
As meta classes são usadas para aplicar alguma regra a um conjunto inteiro de classes. Por exemplo, suponha que você esteja criando um ORM para acessar um banco de dados e deseje que os registros de cada tabela sejam de uma classe mapeada para essa tabela (com base em campos, regras de negócios etc.), um possível uso de metaclasse é, por exemplo, a lógica do conjunto de conexões, que é compartilhada por todas as classes de registro de todas as tabelas. Outro uso é a lógica para dar suporte a chaves estrangeiras, o que envolve várias classes de registros.
Quando você define a metaclasse, o tipo de subclasse e pode substituir os seguintes métodos mágicos para inserir sua lógica.
de qualquer forma, esses dois são os ganchos mais usados. a metaclasse é poderosa, e acima não há uma lista próxima e exaustiva de usos para a metaclasse.
fonte
A função type () pode retornar o tipo de um objeto ou criar um novo tipo,
por exemplo, podemos criar uma classe Hi com a função type () e não precisamos usar dessa maneira com a classe Hi (object):
Além de usar type () para criar classes dinamicamente, você pode controlar o comportamento de criação da classe e usar a metaclasse.
De acordo com o modelo de objeto Python, a classe é o objeto, portanto, a classe deve ser uma instância de outra determinada classe. Por padrão, uma classe Python é uma instância da classe type. Ou seja, type é metaclasse da maioria das classes internas e metaclasse das classes definidas pelo usuário.
O Magic entrará em vigor quando passamos argumentos de palavra-chave na metaclasse, indica que o intérprete Python cria a CustomList por meio do ListMetaclass. new (), neste ponto, podemos modificar a definição de classe, por exemplo, e adicionar um novo método e, em seguida, retornar a definição revisada.
fonte
Além das respostas publicadas, posso dizer que a
metaclass
define o comportamento de uma classe. Portanto, você pode definir explicitamente sua metaclasse. Sempre que o Python obtém uma palavraclass
- chave , ele começa a procurar o arquivometaclass
. Se não for encontrado - o tipo de metaclasse padrão é usado para criar o objeto da classe. Usando o__metaclass__
atributo, você pode definirmetaclass
sua classe:Produzirá a saída assim:
E, é claro, você pode criar o seu próprio
metaclass
para definir o comportamento de qualquer classe criada usando sua classe.Para fazer isso, sua
metaclass
classe de tipo padrão deve ser herdada, pois esta é a principalmetaclass
:A saída será:
fonte
Na programação orientada a objetos, uma metaclasse é uma classe cujas instâncias são classes. Assim como uma classe comum define o comportamento de certos objetos, uma metaclasse define o comportamento de determinada classe e suas instâncias. O termo metaclasse simplesmente significa algo usado para criar classes. Em outras palavras, é a classe de uma classe. A metaclasse é usada para criar a classe, assim como o objeto é uma instância de uma classe, uma classe é uma instância de uma metaclasse. Em python, as classes também são consideradas objetos.
fonte
Aqui está outro exemplo do que pode ser usado:
metaclass
para alterar a função de sua instância (a classe).O
metaclass
é poderoso, há muitas coisas (como a magia dos macacos) que você pode fazer com isso, mas tome cuidado, pois isso só pode ser conhecido por você.fonte
Uma classe, em Python, é um objeto e, como qualquer outro objeto, é uma instância de "alguma coisa". Esse "algo" é o que é chamado de metaclasse. Essa metaclasse é um tipo especial de classe que cria objetos de outras classes. Portanto, a metaclasse é responsável por criar novas classes. Isso permite que o programador personalize a maneira como as classes são geradas.
Para criar uma metaclasse, a substituição dos métodos new () e init () geralmente é feita. new () pode ser substituído para alterar a maneira como os objetos são criados, enquanto init () pode ser substituído para alterar a maneira de inicializar o objeto. A metaclasse pode ser criada de várias maneiras. Uma das maneiras é usar a função type (). A função type (), quando chamada com 3 parâmetros, cria uma metaclasse. Os parâmetros são: -
Outra maneira de criar uma metaclasse compreende a palavra-chave 'metaclasse'. Defina a metaclasse como uma classe simples. Nos parâmetros da classe herdada, passe metaclass = metaclass_name
O metaclasse pode ser usado especificamente nas seguintes situações: -
fonte
Observe que no python 3.6 um novo método dunder
__init_subclass__(cls, **kwargs)
foi introduzido para substituir muitos casos de uso comuns de metaclasses. É chamado quando uma subclasse da classe de definição é criada. Veja documentos python .fonte
Metaclasse é um tipo de classe que define como a classe se comportará ou podemos dizer que Uma classe é ela própria uma instância de uma metaclasse.
fonte