A classe Python herda o objeto

1245

Existe algum motivo para uma declaração de classe herdar object?

Acabei de encontrar um código que faz isso e não consigo encontrar uma boa razão para isso.

class MyClass(object):
    # class code follows...
tjvr
fonte
2
Isso cria uma classe de novo estilo .
Slaks
116
A resposta a esta pergunta (embora simples) é bastante difícil de encontrar. Pesquisando coisas como "classe base de objetos python" ou similar, aparece páginas e páginas de tutoriais sobre programação orientada a objetos. Upvoting porque este é o primeiro elo que me levou aos termos de pesquisa "python vs. novo estilo old objetos"
vastlysuperiorman

Respostas:

765

Existe algum motivo para uma declaração de classe herdar object?

No Python 3, além da compatibilidade entre o Python 2 e 3, não há razão . No Python 2, muitos motivos .


História do Python 2.x:

No Python 2.x (a partir do 2.2), existem dois estilos de classes, dependendo da presença ou ausência de objectuma classe base:

  1. classes de estilo "clássico" : elas não têm objectcomo classe base:

    >>> class ClassicSpam:      # no base class
    ...     pass
    >>> ClassicSpam.__bases__
    ()
    
  2. classes de estilo "novas" : elas têm, direta ou indiretamente (por exemplo, herança de um tipo interno ), objectcomo classe base:

    >>> class NewSpam(object):           # directly inherit from object
    ...    pass
    >>> NewSpam.__bases__
    (<type 'object'>,)
    >>> class IntSpam(int):              # indirectly inherit from object...
    ...    pass
    >>> IntSpam.__bases__
    (<type 'int'>,) 
    >>> IntSpam.__bases__[0].__bases__   # ... because int inherits from object  
    (<type 'object'>,)
    

Sem dúvida, ao escrever uma aula, você sempre desejará aulas de novo estilo. As vantagens de fazer isso são inúmeras, para listar algumas delas:

  • Suporte para descritores . Especificamente, as seguintes construções são possíveis com descritores:

    1. classmethod: Um método que recebe a classe como um argumento implícito em vez da instância.
    2. staticmethod: Um método que não recebe o argumento implícito selfcomo primeiro argumento.
    3. propriedades com property: Crie funções para gerenciar a obtenção, configuração e exclusão de um atributo.
    4. __slots__: Economiza o consumo de memória de uma classe e também resulta em acesso mais rápido aos atributos. Obviamente, impõe limitações .
  • O __new__método estático: permite personalizar como novas instâncias de classe são criadas.

  • Ordem de resolução de método (MRO) : em que ordem as classes base de uma classe serão pesquisadas ao tentar resolver qual método chamar.

  • Relacionado a MRO, superchamadas . Veja também, super()considerado super.

Se você não herdar object, esqueça-os. Uma descrição mais exaustiva dos pontos anteriores, além de outras vantagens de "novas" classes de estilo, pode ser encontrada aqui .

Uma das desvantagens das novas classes de estilo é que a própria classe exige mais memória. A menos que você esteja criando muitos objetos de classe, duvido que isso seja um problema e seja um afundamento negativo em um mar de aspectos positivos.


História do Python 3.x:

No Python 3, as coisas são simplificadas. Existem apenas classes de novo estilo (chamadas de classes), portanto, a única diferença na adição objecté exigir que você digite mais 8 caracteres. Este:

class ClassicSpam:
    pass

é completamente equivalente (além do nome :-) a isso:

class NewSpam(object):
     pass

e para isso:

class Spam():
    pass

Todos têm objectem seus __bases__.

>>> [object in cls.__bases__ for cls in {Spam, NewSpam, ClassicSpam}]
[True, True, True]

Então o que você deveria fazer?

No Python 2: sempre herda objectexplicitamente . Receba as vantagens.

No Python 3: herdar objectse você estiver escrevendo um código que tenta ser independente do Python, ou seja, ele precisa funcionar tanto no Python 2 quanto no Python 3. Caso contrário, não faz realmente nenhuma diferença, já que o Python o insere para você Por trás das cenas.

Dimitris Fasarakis Hilliard
fonte
"dependendo da presença ou ausência de um tipo embutido como classe base" => na verdade, não se trata de "ausência ou presença de um tipo embutido como classe base", mas se a classe herda - direta ou indiretamente - object. No IIRC, houve um momento em que nem todos os tipos internos ainda eram portados para classes de novo estilo.
bruno desthuilliers 19/03/19
@brunodesthuilliers Minha impressão foi de que todos os tipos internos herdaram object. Eu tenho um Python 2.2.3 por perto e, após uma verificação rápida, não consegui encontrar um infrator, mas reformularei a resposta mais tarde para torná-la mais clara. Estaria interessado se você pudesse encontrar um exemplo, porém, minha curiosidade é despertada.
Dimitris Fasarakis Hilliard
Com toda a honestidade (consulte o "IIRC" no meu comentário anterior), não tenho 101% de certeza sobre esse ponto (se todos os tipos internos já foram convertidos em classes de novo estilo quando foram introduzidas) - talvez seja claro errado, ou isso pode ter afetado apenas alguns dos tipos de lib padrão (mas não embutidos). Mas, no entanto, acho que deveria ser melhor esclarecer que o que faz uma classe de novo estilo está tendo objectem suas bases.
Bruno desthuilliers
7
stackoverflow muito ruim apenas upvote = upvote + 1 para essas respostas, gostaria de fazer upvote + = N
PirateApp
1
staticmethode classmethodfunciona bem mesmo em aulas de estilo antigo. propertysorta funciona para leitura em classes de estilo antigo, mas falha em interceptar gravações (portanto, se você atribuir ao nome, a instância ganha um atributo do nome dado que oculta a propriedade). Observe também que __slots__o aprimoramento na velocidade de acesso aos atributos se refere principalmente a desfazer a perda sofrida pelo acesso a atributos de classe de novo estilo, portanto, não é realmente um ponto de venda de classes de novo estilo (a economia de memória é um ponto de venda).
ShadowRanger
540

Python 3

  • class MyClass(object): = Classe de novo estilo
  • class MyClass:= Classe de novo estilo (herda implicitamente de object)

Python 2

  • class MyClass(object): = Classe de novo estilo
  • class MyClass:= CLASSE DE ESTILO ANTIGO

Explicação :

Ao definir classes base no Python 3.x, você pode remover o objectda definição. No entanto, isso pode abrir a porta para um problema seriamente difícil de rastrear ...

O Python introduziu novas classes de estilo no Python 2.2, e agora as classes antigas são realmente muito antigas. A discussão de classes de estilo antigo está oculta nos documentos 2.x e inexistente nos documentos 3.x.

O problema é, a sintaxe para as classes de estilo antigo em Python 2.x é o mesmo que a sintaxe alternativa para as classes de estilo novo em Python 3.x . O Python 2.x ainda é muito utilizado (por exemplo, GAE, Web2Py), e qualquer código (ou codificador) involuntariamente trazendo definições de classe no estilo 3.x para o código 2.x vai acabar com alguns objetos básicos seriamente desatualizados. E como as aulas de estilo antigo não estão no radar de ninguém, elas provavelmente não saberão o que as atingiu.

Então, basta soletrar o caminho longo e poupar alguns desenvolvedores do 2.x as lágrimas.

Yarin
fonte
13
"Ao definir classes base no Python 3.x, você pode remover o objeto da definição. No entanto, isso pode abrir a porta para um problema seriamente difícil de rastrear ..." A quais problemas você está se referindo?
Aidis
6
@Aidis: Eu acho que eles querem dizer que o código executado tanto no Py2 quanto no Py3 seria bom no Py3, mas seria quebrado no Py2 se depender de recursos de classe de novo estilo. Pessoalmente, se estou escrevendo um código como esse, omito a herança explícita e apenas coloco __metaclass__ = typena parte superior do módulo (após a from __future__ import absolute_import, division, print_functionlinha :-)); é um hack de compatibilidade no Py2 que torna todas as classes subsequentemente definidas no módulo novo estilo por padrão, e no Py3 é completamente ignorado (apenas uma variável global aleatória), por isso é inofensivo.
ShadowRanger
400

Sim, este é um objeto de 'novo estilo'. Foi um recurso introduzido no python2.2.

Os novos objetos de estilo têm um modelo de objeto diferente dos objetos clássicos e algumas coisas não funcionarão corretamente com objetos de estilo antigo, por exemplo super(), @propertye descritores. Consulte este artigo para obter uma boa descrição do que é uma nova classe de estilo.

Link SO para obter uma descrição das diferenças: Qual é a diferença entre o estilo antigo e as novas classes de estilo no Python?

Jerub
fonte
110
+1 Isto. Observe que as classes de estilo antigo desapareceram no Python 3, então você só precisa herdar do objectPython 2. #
9
Esta não é uma resposta real. apenas menciona outros artigos. Penso que a resposta de Yarin deve ser aceita como resposta a esta pergunta.
Alwbtc 01/01
2
@alwbtc: Esta resposta também tem algo novo. Por exemplo, a menção de "super ()" me levou a outra importante [aqui] ( stackoverflow.com/questions/576169/… ).
ViFI
34

História do Learn Python da maneira mais difícil :

A versão original de Python de uma classe foi quebrada de várias maneiras sérias. No momento em que essa falha foi reconhecida, já era tarde demais e eles precisavam apoiá-la. Para resolver o problema, eles precisavam de um estilo de "nova classe" para que as "classes antigas" continuassem funcionando, mas você pode usar a nova versão mais correta.

Eles decidiram que usariam a palavra "objeto", em minúsculas, para ser a "classe" da qual você herda para criar uma classe. É confuso, mas uma classe é herdada da classe chamada "objeto" para criar uma classe, mas não é realmente um objeto, é uma classe, mas não esqueça de herdar do objeto.

Também para que você saiba qual é a diferença entre as classes de novo estilo e as de estilo antigo, é que as classes de novo estilo sempre herdam da objectclasse ou de outra classe que herdou de object:

class NewStyle(object):
    pass

Outro exemplo é:

class AnotherExampleOfNewStyle(NewStyle):
    pass

Enquanto uma classe base de estilo antigo se parece com isso:

class OldStyle():
    pass

E uma classe infantil à moda antiga é assim:

class OldStyleSubclass(OldStyle):
    pass

Você pode ver que uma classe base Old Style não herda de nenhuma outra classe; no entanto, é claro que as classes Old Style podem herdar uma da outra. Herdar do objeto garante que determinadas funcionalidades estejam disponíveis em todas as classes do Python. Novas classes de estilo foram introduzidas no Python 2.2

disp_name
fonte
8
Chamar a classe raiz objectnão é tão confuso e, na verdade, é bastante padrão. O Smalltalk possui uma classe raiz denominada Objecte uma metaclasse raiz denominada Class. Por quê? Porque, assim como Dogé uma classe para cães, Objecté uma classe para objetos e Classé uma classe para classes. Java, C #, ObjC, Ruby e a maioria das outras linguagens OO baseadas em classe que as pessoas usam hoje que têm uma classe raiz usam alguma variação Objectcomo o nome, não apenas Python.
Abarnert
30

Sim, é histórico . Sem ele, ele cria uma classe de estilo antigo.

Se você usa type()em um objeto de estilo antigo, apenas obtém "instância". Em um objeto de novo estilo, você obtém sua classe.

knitti
fonte
Além disso, se você usa type()uma classe de estilo antigo, obtém "classobj" em vez de "type".
Joel Sjögren
7

A sintaxe da instrução de criação de classe:

class <ClassName>(superclass):
    #code follows

Na ausência de outras superclasses das quais você deseja herdar especificamente, superclassdeve sempre ser object, que é a raiz de todas as classes no Python.

objecté tecnicamente a raiz das classes de "novo estilo" no Python. Mas as novas classes de estilo hoje são tão boas quanto o único estilo de classe.

Mas, se você não usar explicitamente a palavra objectao criar classes, como os outros mencionaram, o Python 3.x herda implicitamente da objectsuperclasse. Mas acho que explícito é sempre melhor que implícito (inferno)

Referência

kmario23
fonte