Question Quelle est la différence entre le style ancien et les nouvelles classes de style en Python?


Quelle est la différence entre le style ancien et les nouvelles classes de style en Python? Y a-t-il une raison d'utiliser des classes à l'ancienne ces temps-ci?


855
2017-09-10 18:01


origine


Réponses:


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

Jusqu'à Python 2.1, les classes de style ancien étaient les seules saveurs disponibles pour l'utilisateur. Le concept de classe (ancien style) n'a aucun rapport avec le concept de type: si x est une instance d'une classe à l'ancienne, puis x.__class__ désigne la classe de x, mais type(x) est toujours <type 'instance'>. Ceci reflète le fait que toutes les instances de style ancien, indépendamment de leur classe, sont implémentées avec un seul type intégré, appelé instance.

Des classes de style nouveau ont été introduites dans Python 2.2 pour unifier les concepts de classe et de type. Une classe de style nouveau est simplement un type défini par l'utilisateur, pas plus, pas moins. Si x est une instance d'une classe de style nouveau, alors type(x) est généralement le même que x.__class__ (bien que cela ne soit pas garanti - une instance de classe de nouveau style est autorisée à remplacer la valeur renvoyée pour x.__class__).

La principale motivation pour l'introduction de classes de style nouveau est de fournir un modèle d'objet unifié avec un méta-modèle complet. Il présente également un certain nombre d'avantages immédiats, comme la possibilité de sous-classer la plupart des types intégrés, ou l'introduction de "descripteurs", qui permettent d'obtenir des propriétés calculées.

Pour des raisons de compatibilité, les classes sont toujours à l'ancienne par défaut. Les classes de style nouveau sont créées en spécifiant une autre classe de nouveau style (à savoir un type) en tant que classe parente ou l'objet de type "de niveau supérieur" si aucun autre parent n'est nécessaire. Le comportement des classes de style nouveau diffère de celui des classes de style ancien dans un certain nombre de détails importants en plus de ce que renvoie le type. Certains de ces changements sont fondamentaux pour le nouveau modèle d'objet, comme la façon dont les méthodes spéciales sont appelées. D'autres sont des "correctifs" qui n'ont pas pu être implémentés auparavant pour des problèmes de compatibilité, comme l'ordre de résolution de la méthode en cas d'héritage multiple.

Python 3 a seulement des classes de nouveau style. Peu importe si vous sous-classe de object ou non, les classes sont de style nouveau dans Python 3.


487
2017-07-30 01:21



Déclaration-sage:

Les classes de style nouveau héritent de l'objet ou d'une autre classe de nouveau style.

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

Les classes à l'ancienne ne le font pas.

class OldStyleClass():
    pass

282
2017-11-13 09:36



Changements de comportement importants entre les anciennes et les nouvelles classes de style

  • super ajoutée
  • MRO changé (expliqué ci-dessous)
  • descripteurs ajoutée
  • Les nouveaux objets de classe de style ne peuvent pas être augmentés sauf s'ils sont dérivés de Exception (exemple ci-dessous)
  • __slots__ ajoutée

MRO (Ordre de résolution de méthode) modifié

Il a été mentionné dans d'autres réponses, mais voici un exemple concret de la différence entre MRO classique et C3 MRO (utilisé dans les classes de style nouveau).

La question est l'ordre dans lequel les attributs (qui incluent les méthodes et les variables membres) sont recherchés dans l'héritage multiple.

Classes classiquesfaire une première recherche de profondeur de gauche à droite. Arrêtez-vous au premier match. Ils n'ont pas le __mro__ attribut.

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

Cours de style nouveau MRO est plus compliqué à synthétiser dans une seule phrase en anglais. Il est expliqué en détail ici. Une de ses propriétés est qu'une classe de base est seulement recherchée une fois que toutes ses classes dérivées ont été. Ils ont le __mro__ attribut qui montre l'ordre de recherche.

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)

Les nouveaux objets de classe de style ne peuvent pas être augmentés à moins d'être dérivés de Exception

Autour de Python 2.5, de nombreuses classes pouvaient être levées, autour de Python 2.6 cela a été supprimé. Sur 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

195
2017-07-12 11:26



Les classes de style ancien sont encore légèrement plus rapides pour la recherche d'attribut. Ce n'est généralement pas important, mais peut être utile dans le code Python 2.x sensible aux performances:

Dans [3]: classe A:
   ...: def __init __ (auto):
   ...: self.a = 'salut là-bas'
   ...:

Dans [4]: ​​classe B (objet):
   ...: def __init __ (auto):
   ...: self.a = 'salut là-bas'
   ...:

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

Dans [8]:% timeit aobj.a
10000000 boucles, le meilleur de 3: 78,7 ns par boucle

Dans [10]:% timeit bobj.a
10000000 boucles, le meilleur de 3: 86,9 ns par boucle

34
2018-04-24 13:41



Guido a écrit L'histoire intérieure sur les classes de style nouveau, un très bon article sur les classes new-style et old-style en Python.

Python 3 a seulement une nouvelle classe de style, même si vous écrivez une 'ancienne classe', elle est implicitement dérivée de object.

Les classes de style nouveau ont certaines fonctionnalités avancées qui manquent dans les classes à l'ancienne, telles que super et le nouveau C3 mro, quelques méthodes magiques, etc.


30
2017-10-09 13:40



Voici une différence très pratique, vraie / fausse. La seule différence entre les deux versions du code suivant est que dans la deuxième version, Person hérite de l'objet. Autre que cela les deux versions sont identiques, mais avec des résultats différents:

1) classes à l'ancienne

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) les classes de nouveau style

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>
>>>

17
2017-10-28 09:54



Les classes de style nouveau héritent de object et doit être écrit comme tel dans Python 2.2 (c.-à-d. class Classname(object): au lieu de class Classname:). Le changement de base est d'unifier les types et les classes, et le bon effet secondaire de ceci est qu'il vous permet d'hériter des types intégrés.

Lis descrintro pour plus de détails.


7
2018-04-30 08:28



Les nouvelles classes de style peuvent utiliser super(Foo, self) où Foo est une classe et self est l'instance.

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

Renvoie un objet proxy qui délègue des appels de méthode à un parent ou à une classe de type frère. Ceci est utile pour accéder aux méthodes héritées qui ont été remplacées dans une classe. L'ordre de recherche est le même que celui utilisé par getattr () sauf que le type lui-même est ignoré.

Et en Python 3.x, vous pouvez simplement utiliser super() à l'intérieur d'une classe sans paramètres.


4
2017-09-10 21:23



Ou plutôt, vous devriez toujours utiliser des classes de style nouveau, sauf si vous avez du code qui doit fonctionner avec des versions de Python antérieures à 2.2.


3