Question

Quelle est la différence entre le style ancien et nouveau style de classes en Python?Quand devrais-je utiliser l'un ou l'autre?

Était-ce utile?

La solution

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

Jusqu'à Python 2.1, de style ancien classes ont été le seul de la saveur à la disposition de l'utilisateur.

Le concept de (vieux style) de classe n'est pas liée à la notion de type:si x est une instance d'une classe de style, puis x.__class__ désigne la classe de x, mais type(x) est toujours <type 'instance'>.

Cela reflète le fait que tous les anciens de style instances, indépendamment de leur classe, sont mis en œuvre avec un seul type, appelé exemple.

Nouveau style de classes ont été introduites en Python 2.2 à unifier les concepts de classe et de type.Un nouveau type de classe est simplement un type défini par l'utilisateur, pas plus, pas moins.

Si x est une instance de la classe de style, puis type(x) est généralement le même que x.__class__ (bien que ce n'est pas la garantie d'un new-style instance de classe est autorisée à remplacer la valeur retournée pour x.__class__).

La principale motivation pour l'introduction de la nouvelle-classes de style est de fournir un objet unifié modèle avec un méta-modèle.

Il a également un certain nombre d'avantages immédiats, comme la capacité de sous-classe de la plupart des types intégrés, ou l'introduction de "descripteurs", qui permettent aux propriétés calculées.

Pour des raisons de compatibilité, les classes sont toujours ancien de style par défaut.

Nouveau style de classes sont créées par la spécification d'une autre nouvelle de style de classe (c'est à direun type) comme une classe parent, ou le "haut-niveau" type d'objet si aucun autre parent est nécessaire.

Le comportement de la nouvelle-classes de style diffère de celui de l'ancien style les classes dans un certain nombre de détails importants, en plus de ce type les rendements.

Certains de ces changements sont fondamentaux pour le nouveau modèle objet, comme la voie à des méthodes spéciales sont invoqués.D'autres sont des "corrections" qui ne pouvait pas être mis en œuvre avant pour les problèmes de compatibilité, comme la méthode la résolution de la commande dans le cas de l'héritage multiple.

Python 3 a seulement la nouvelle-classes de style.

Peu importe si vous sous-classe de object ou pas, les classes sont nouveau style en Python 3.

Autres conseils

Déclaration-sage:

Nouveau style de classes héritent de l'objet, ou à partir d'un autre style nouveau de la classe.

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

De style ancien classes ne pas.

class OldStyleClass():
    pass

D'importants changements de comportement entre les anciens et les nouvelles classes de style

  • super ajouté
  • MRO changé (expliqué ci-dessous)
  • les descripteurs de ajouté
  • nouveau style des objets de la classe ne peut être levé que si dérivée de Exception (exemple ci-dessous)
  • __slots__ ajouté

MRO (Méthode de Résolution de l'Ordre) changé

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

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

Classique des classes faire un parcours en profondeur d'abord de recherche de gauche à droite.Arrêt sur le 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

New-classes de style MRO est plus compliqué de synthétiser en une seule phrase anglaise.Il est expliqué en détail ici.L'une de ses propriétés, c'est qu'une classe de Base est uniquement cherché pour une fois que l'ensemble de ses classes Dérivées ont été.Ils ont l' __mro__ attribut qui indique 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)

Nouveau style des objets de la classe ne peut être levé que si dérivée de Exception

Autour de Python 2.5 le nombre de classes qui peuvent être posé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

De style ancien, les classes sont toujours légèrement plus rapide pour l'attribut de recherche.Ce n'est généralement pas important, mais peut être utile dans la performance sensible Python 2.x code:

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 a écrit De l'Intérieur la Nouvelle-Classes de Style, un très bon article sur les nouveautés de style et de style ancien de la classe en Python.

Python 3 n'a qu'un style nouveau de la classe, même si vous écrivez un "vieux de la classe de style", il est implicitement dérivées de object.

Nouveau style de classes ont certaines fonctionnalités avancées manque dans le vieux-classes de style, tels que super et le nouveau C3 mro, certains magique méthodes, etc.

Voici un très pratique, Vrai/Faux différence.La seule différence entre les deux versions du code suivant, c'est que dans la deuxième version de la Personne hérite de l'objet.Autres que que les deux versions sont identiques, mais avec des résultats différents :

1) le vieux-classes de style

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) nouvelle-classes de 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>
>>>

Nouveau style de classes héritent de object et doit être écrite en tant que telle en Python 2.2 la suite (c'est à dire class Classname(object): au lieu de class Classname:).Le changement de base est d'unifier les types et les classes, et le côté sympa à effet de cela est qu'il vous permet d'hériter de type intégré.

Lire descrintro pour plus de détails.

De nouvelles classes de style peut utiliser super(Foo, self)Foo est une classe et self est l'instance.

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

De retour d'un objet proxy qui délégués des appels de méthode à un parent ou un frère classe de type.C'est utile pour l'accès aux hérité des méthodes 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ée.

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

Ou plutôt, vous devriez toujours utiliser la nouvelle-classes de style, à moins que vous disposez d'un code qui a besoin de travailler avec les versions de Python âgés de plus de 2.2.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top