Pergunta

Qual é a diferença entre classes de estilo antigo e novo em Python?Quando devo usar um ou outro?

Foi útil?

Solução

De http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes :

Até o Python 2.1, as classes antigas eram o único tipo disponível para o usuário.

O conceito de classe (estilo antigo) não está relacionado ao conceito de tipo:se x é uma instância de uma classe de estilo antigo, então x.__class__designa a classe de x, mas type(x) é sempre <type 'instance'>.

Isso reflete o fato de que todas as instâncias de estilo antigo, independentemente de sua classe, são implementadas com um único tipo interno, chamado instância.

Classes de novo estilo foram introduzidas no Python 2.2 para unificar os conceitos de classe e tipo.Uma classe de novo estilo é simplesmente um tipo definido pelo usuário, nem mais, nem menos.

Se x é uma instância de uma classe de novo estilo, então type(x) é tipicamente o mesmo que x.__class__ (Embora isso não seja garantido-uma instância de classe de novo estilo tem permissão para substituir o valor retornado para x.__class__).

A principal motivação para a introdução de classes de novo estilo é fornecer um modelo de objeto unificado com um metamodelo completo.

Ele também possui vários benefícios imediatos, como a capacidade de subclasse a maioria dos tipos internos ou a introdução de "descritores", que permitem propriedades computadas.

Por motivos de compatibilidade, as classes ainda são antigas por padrão.

As aulas de novo estilo são criadas especificando outra classe de novo estilo (ou seja,um tipo) como uma classe pai ou o objeto "Tipo de nível superior", se nenhum outro pai for necessário.

O comportamento das classes de novo estilo difere do das classes de estilo antigo em vários detalhes importantes, além de que tipo retorna.

Algumas dessas mudanças são fundamentais para o novo modelo de objeto, como os métodos especiais são invocados.Outros são "correções" que não puderam ser implementadas antes para preocupações com compatibilidade, como a ordem de resolução do método em caso de herança múltipla.

Python 3 só tem classes de novo estilo.

Não importa se você subclassifica de object ou não, as aulas são de estilo novo no Python 3.

Outras dicas

Em termos de declaração:

As classes do novo estilo herdam do objeto ou de outra classe do novo estilo.

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

As aulas do estilo antigo, não.

class OldStyleClass():
    pass

Mudanças importantes de comportamento entre classes de estilo antigo e novo

  • super adicionado
  • MRO alterado (explicado abaixo)
  • descritores adicionado
  • novos objetos de classe de estilo não podem ser gerados, a menos que sejam derivados de Exception (exemplo abaixo)
  • __slots__ adicionado

MRO (Ordem de Resolução de Método) alterada

Foi mencionado em outras respostas, mas aqui vai um exemplo concreto da diferença entre o MRO clássico e o MRO C3 (usado nas classes do novo estilo).

A questão é a ordem em que os atributos (que incluem métodos e variáveis ​​de membro) são procurados na herança múltipla.

Aulas clássicas faça uma primeira pesquisa em profundidade da esquerda para a direita.Pare na primeira partida.Eles não têm o __mro__ atributo.

class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 0
assert C21().i == 2

try:
    C12.__mro__
except AttributeError:
    pass
else:
    assert False

Aulas de novo estilo MRO é mais complicado de sintetizar em uma única frase em inglês.É explicado em detalhes aqui.Uma de suas propriedades é que uma classe Base só é pesquisada depois que todas as suas classes Derivadas tiverem sido pesquisadas.Eles têm o __mro__ atributo que mostra a ordem de pesquisa.

class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 2
assert C21().i == 2

assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)

Objetos de classe de novo estilo não podem ser gerados, a menos que sejam derivados de Exception

Por volta do Python 2.5, muitas classes podiam ser criadas; por volta do Python 2.6, isso foi removido.No Python 2.7.3:

# OK, old:
class Old: pass
try:
    raise Old()
except Old:
    pass
else:
    assert False

# TypeError, new not derived from `Exception`.
class New(object): pass
try:
    raise New()
except TypeError:
    pass
else:
    assert False

# OK, derived from `Exception`.
class New(Exception): pass
try:
    raise New()
except New:
    pass
else:
    assert False

# `'str'` is a new style object, so you can't raise it:
try:
    raise 'str'
except TypeError:
    pass
else:
    assert False

As classes de estilo antigo ainda são um pouco mais rápidas para pesquisa de atributos.Isso geralmente não é importante, mas pode ser útil em código Python 2.x sensível ao desempenho:

In [3]: class A:
   ...:     def __init__(self):
   ...:         self.a = 'hi there'
   ...: 

In [4]: class B(object):
   ...:     def __init__(self):
   ...:         self.a = 'hi there'
   ...: 

In [6]: aobj = A()
In [7]: bobj = B()

In [8]: %timeit aobj.a
10000000 loops, best of 3: 78.7 ns per loop

In [10]: %timeit bobj.a
10000000 loops, best of 3: 86.9 ns per loop

Guido escreveu A história interna das aulas do novo estilo, um artigo realmente ótimo sobre classes de estilo novo e antigo em Python.

Python 3 tem apenas classes de novo estilo, mesmo se você escrever uma 'classe de estilo antigo', ela é implicitamente derivada de object.

As classes do novo estilo têm alguns recursos avançados que faltam nas classes do estilo antigo, como super e o novo C3 mro, alguns métodos mágicos, etc.

Aqui está uma diferença muito prática entre Verdadeiro/Falso.A única diferença entre as duas versões do código a seguir é que na segunda versão Person herda do objeto.Fora isso, as duas versões são idênticas, mas com resultados diferentes:

1) aulas à moda antiga

class Person():
    _names_cache = {}
    def __init__(self,name):
        self.name = name
    def __new__(cls,name):
        return cls._names_cache.setdefault(name,object.__new__(cls,name))

ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed1 is ahmed2
print ahmed1
print ahmed2


>>> False
<__main__.Person instance at 0xb74acf8c>
<__main__.Person instance at 0xb74ac6cc>
>>>

2) aulas de novo estilo

class Person(object):
    _names_cache = {}
    def __init__(self,name):
        self.name = name
    def __new__(cls,name):
        return cls._names_cache.setdefault(name,object.__new__(cls,name))

ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed2 is ahmed1
print ahmed1
print ahmed2

>>> True
<__main__.Person object at 0xb74ac66c>
<__main__.Person object at 0xb74ac66c>
>>>

Classes de novo estilo herdam de object e deve ser escrito como tal no Python 2.2 em diante (ou seja, class Classname(object): em vez de class Classname:).A principal mudança é unificar tipos e classes, e o bom efeito colateral disso é que permite herdar tipos integrados.

Ler descrição para mais detalhes.

Novas classes de estilo podem usar super(Foo, self) onde Foo é uma aula e self é a instância.

super(type[, object-or-type])

Retorna um objeto proxy que delega chamadas de método a uma classe pai ou irmã do tipo.Isto é útil para acessar métodos herdados que foram substituídos em uma classe.A ordem de pesquisa é a mesma usada por getattr() exceto que o tipo em si é ignorado.

E no Python 3.x você pode simplesmente usar super() dentro de uma classe sem parâmetros.

Ou melhor, você deve sempre usar classes de novo estilo, a menos que você tem código que precisa funcionar com versões do Python anteriores à 2.2.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top