Quelle est la différence entre la classe et les variables d'instance?
Quelle est la différence entre la classe et les variables d'instance en Python?
class Complex:
a = 1
et
class Complex:
def __init__(self):
self.a = 1
À l'aide de l'appel: x = Complex().a
dans les deux cas attribue x à 1.
Un peu plus en profondeur sur la réponse __init__()
et self
sera appréciée.
Vous devez vous connecter pour publier un commentaire.
Lorsque vous écrivez une classe de bloc, vous créez attributs de classe (ou de variables de classe). Tous les noms que vous affectez dans la classe du bloc, y compris les méthodes, vous définissez avec
def
deviennent des attributs de classe.Après une instance de classe est créée, quoi que ce soit avec une référence à l'instance peut créer une instance attributs sur elle. À l'intérieur des méthodes, le "courant" de l'instance est presque toujours lié à un nom de
self
, qui est pourquoi vous êtes la pensée de ces comme "variables". Généralement dans la conception orientée objet, le code associé à une classe qui est censé avoir le contrôle sur les attributs des instances de cette classe, donc presque tous instance d'affectation d'attribut est fait à l'intérieur des méthodes, à l'aide de la référence de l'instance a reçu dans leself
paramètre de la méthode.Attributs de classe sont souvent comparés à des statique variables (ou les méthodes), comme l'a constaté dans des langages comme Java, C# ou C++. Toutefois, si vous voulez viser pour une meilleure compréhension, je voudrais éviter de penser à des attributs de classe comme "la même" que les variables statiques. Alors qu'ils sont souvent utilisés pour les mêmes fins, le concept sous-jacent est tout à fait différent. Plus à ce sujet dans la section "avancé" en dessous de la ligne.
Un exemple!
Après l'exécution de ce bloc, il y a une classe
SomeClass
, avec 3 attributs de classe:__init__
,bar
, etbar_list
.Ensuite, nous allons créer une instance:
Lorsque cela se produit,
SomeClass
's__init__
méthode est exécutée, la réception de la nouvelle instance dans sonself
paramètre. Cette méthode crée deux attributs d'instance:foo
etfoo_list
. Ensuite, cette instance est attribué dans leinstance
variable, il est donc lié à une chose avec ces deux attributs d'instance:foo
etfoo_list
.Mais:
donne:
Comment est-ce arrivé? Quand nous essayons de récupérer un attribut par le biais de la syntaxe à point, et l'attribut n'existe pas, Python va à travers un tas de mesures pour tenter de répondre à votre demande de toute façon. La prochaine chose qu'il va faire est d'essayer de regarder la attributs de classe de la classe de votre instance. Dans ce cas, il a trouvé un attribut
bar
dansSomeClass
, de sorte qu'il ne revienne.Qui est aussi la façon dont les appels de méthode de travail par la voie. Lorsque vous appelez
mylist.append(5)
, par exemple,mylist
ne pas avoir un attribut nomméappend
. Mais le classe demylist
fait, et il est lié à une méthode de l'objet. Cette méthode de l'objet renvoyé par lemylist.append
peu, et puis le(5)
bits appelle la méthode avec l'argument5
.La façon dont cela est utile, c'est que tous instances de
SomeClass
auront accès à la mêmebar
attribut. On pourrait créer un million de cas, mais nous avons seulement besoin de stocker une chaîne de caractères en mémoire, car ils peuvent tous trouver.Mais vous devez être un peu prudent. Jetez un oeil à l'une des opérations suivantes:
Que pensez-vous de cette affiche?
C'est parce que chaque instance possède sa propre copie de
foo_list
, de sorte qu'ils ont été ajoutés séparément. Mais tous instances de partager l'accès à la mêmebar_list
. Alors, quand nous avons faitsc1.bar_list.append(2)
il a touchésc2
, même sisc2
n'existent pas encore! Et de mêmesc2.bar_list.append(20)
affecté labar_list
récupérés par le biais d'sc1
. Ce n'est souvent pas ce que vous voulez.Avancée de l'étude qui suit. 🙂
Vraiment grok Python, venant de la traditionnelle statiquement typé OO-langages comme Java et C#, vous devez apprendre à repenser les classes un peu.
En Java, une classe n'est pas vraiment un chose dans son propre droit. Lorsque vous écrivez une classe que vous avez plus de déclarer un tas de choses que toutes les instances de cette classe ont en commun. Au moment de l'exécution, il n'y a qu'cas (et statique méthodes/variables, mais ceux qui sont vraiment juste des variables globales et des fonctions dans un espace de noms associé à une classe, rien à voir avec OO vraiment). Les Classes sont la façon dont vous écrivez dans votre code source que le cas sera, comme au moment de l'exécution; ils "existent" dans votre code source, non pas dans le programme en cours d'exécution.
En Python, une classe est rien de spécial. C'est un objet tout comme toute autre chose. Ainsi, "les attributs de classe" sont en fait exactement la même chose qu'une "instance attributs"; en réalité, il est juste "attributs". La seule raison de faire une distinction, c'est que nous avons tendance à utilisation objets qui sont des classes différemment à partir d'objets qui ne sont pas des classes. Le sous-jacentes de la machinerie est tout de même. C'est pourquoi je dis qu'il serait une erreur de penser d'attributs de classe en tant que variables statiques à partir d'autres langues.
Mais ce qui le rend vraiment classes Python différent de Java-classes de style, c'est que comme tout autre objet chaque classe est une instance de la classe!
En Python, la plupart des classes sont des instances d'un builtin classe appelée
type
. C'est cette classe qui contrôle le comportement commun de classes, et fait tous les trucs OO la façon dont il le fait. La valeur par défaut OO façon d'avoir des instances de classes qui ont leurs propres attributs, et ont en commun les mêmes méthodes/attributs définis par leur classe, c'est juste un protocole en Python. Vous pouvez modifier la plupart des aspects de celui-ci si vous le souhaitez. Si vous avez jamais entendu parler de l'aide d'un métaclasse, tout ce qui est est la définition d'une classe qui est une instance d'une classe différente de celletype
.Le seul vraiment "spécial" chose à propos de classes (en dehors de toutes les builtin machines pour les faire travailler de la façon dont ils le font par défaut), c'est la classe bloc de syntaxe, pour le rendre plus facile pour vous de créer des instances de
type
. Ce:est à peu près équivalente à la suivante:
Et il se chargera de tout le contenu de
classdict
à devenir des attributs de l'objet qui est créé.Alors il devient presque banal de voir que vous pouvez accéder à un attribut de classe par
Class.attribute
aussi facilement quei = Class(); i.attribute
. Les deuxi
etClass
sont des objets, et les objets ont des attributs. Cela le rend aussi facile à comprendre comment vous pouvez modifier une classe après qu'il a été créé; il suffit de céder ses attributs de la même manière que vous le feriez avec tout autre objet!En fait, des cas ont aucune relation spéciale avec la classe utilisée pour les créer. La façon Python sait ce qui la classe à la recherche pour les attributs qui ne sont pas trouvés dans l'instance est par hidden
__class__
attribut. Que vous pouvez lire pour savoir ce que cette classe est une instance de l', tout comme avec n'importe quel autre attribut:c = some_instance.__class__
. Vous avez maintenant une variablec
lié à une classe, même si elle n'a sans doute pas le même nom que la classe. Vous pouvez l'utiliser pour accéder à des attributs de classe, ou même de l'appeler à créer plusieurs instances de celui-ci (même si vous ne savez pas dans quelle classe il est!).Et vous pouvez même attribuer à
i.__class__
de changement dans quelle classe il est une instance de! Si vous faites cela, rien de particulier ne se produit immédiatement. Ce n'est pas fracassant. Tout ce que cela signifie est que lorsque vous regardez les attributs qui n'existent pas dans l'instance, Python allez voir le nouveau contenu de__class__
. Depuis que comprend la plupart des méthodes, et des méthodes s'attendent généralement à ce que l'instance ils fonctionnent à être dans certains états, il en résulte généralement dans les erreurs, si vous le faites au hasard, et il est très déroutant, mais il peut être fait. Si vous êtes très prudent, la chose que vous stockez dans__class__
n'ont même pas à être un objet de classe; tous les Python va faire, c'est de rechercher des attributs dans certaines circonstances, de sorte que tous vous avez besoin est un objet qui a le bon type d'attributs (certaines mises en garde de côté où Python est pointilleux sur les choses des classes ou des instances d'une classe particulière).C'est probablement assez pour l'instant. Si tout va bien (si vous avez même lu jusqu'ici) je n'ai pas confondu vous trop. Python est soigné lorsque vous apprendre comment il fonctionne. 🙂
sc1,sc2
, si j'ai missc1.bar = "something else"
, puissc2.bar
est encoreI am a class attribute called bar
. Cela ressemble à chaque instance possède son propre variable de classe, ce qui rend la variable de classe n'est pas différente de la variable d'instance? Si j'ai misSomeClass.bar='another thing'
, puissc1.bar = 'something else'
etsc2.bar='another thing'
sc1.bar = ...
écrit à labar
attribut desc1
(création d'un nouvel attribut) pas labar
attributs deSomeClass
. Par la suite, lorsque vous liresc1.bar
il voit une instance de l'attribut et vous donne de la valeur, tandis que la lecturesc2.bar
voit encore quesc2
n'a pas d'attributbar
et retombe à l'attribut de classe. Les exemples avec l'ajout debar_list
montrer la différence. Rappelez-vous que la cession n'a pas d'incidence sur l'objet que vous auriez récupéré à partir de la variable, il crée ou remplace une référence.__get__
sur cet objet, et que__get__
méthode crée la méthode de l'objet que vous voyez.Ce que vous appelez une "instance" de la variable n'est pas une variable d'instance; c'est un variable de classe. Voir la la langue de référence sur les classes.
Dans votre exemple, le
a
semble être une variable d'instance, parce qu'il est immuable. C'est la nature comme un classe variable peut être vu dans le cas lorsque vous affectez une mutable objet:Si vous avez utilisé
self
, alors ce serait une véritable variable d'instance, et donc chaque instance aurait sa proprea
. Un objet__init__
fonction est appelé lorsqu'une nouvelle instance est créée, etself
est une référence à cette instance.Complex.a
(la classe, pas exemple) et a remarqué qu'il était['Hello']
. 😀a
.". Vous pouvez définir plus d'un__init__
fonction dans une classe? Ou d'accomplir toutes les fonctions de la classe comptent comme des instances?__init__
? L'init est le "constructeur" d'une instance, si vous voulez. Si vous avez besoin de faire des choses compliquées, puis il suffit de séparer les tâches en fonctions distinctes et de les appeler à partir de__init__
. Pour votre autre question, comme Ben mentionné, les fonctions d'une classe ne sont pas réellement stocké dans les instances de la classe. Lorsque Python n'a une fonction recherche, rechercher dans le dictionnaire (__dict__
) de la première instance, et, n'ayant pas trouvé la fonction, va à la recherche dans la classe. Si elle est trouvée, la fonction est appelée avec l'instance en tant qu'argument.__init__
se comporte comme une fonction normale, si vous regardez au-delà de ses propriétés particulières. Cela signifie que vous pouvez utiliser des variables temporaires dans la fonction de la portée, tout comme dans toute autre fonction. Ce ne sont pas conservés dans l'objet, sauf si vous explicitement de les affecter à desself
, auquel cas vous êtes tout simplement en les assignant à l'instance elle-même.a
n'est pas une liste, mais seulement un nombre variable, par exemple avec la valeur par défaut de 5, puis lorsque vous créer 2 objets,b,c
et si vous changezb.a = 15
, il n'a pas pour effet dec.a
, qui est toujours 5. Donc, dans ce cas, il semble que la variable de classe est la même que la variable d'instance (le soi.variable)?b.a = 15
crée un nouvelle variable d'instance sur cet objet (ceux-ci sont plus correctement appelé "attributs de données" et "attributs de classe"). Lors de la lecture deb.a
, Python trouve l'instance de l'attribut de données tout d'abord, et le renvoie sans regarder la classe. Pour voir comment le comportement peut varier, notez que si vous au lieu de céder à la de la classe,Complex.a = 55
, à la suite de lectures à partir d'instances de retour de la nouvelle valeur (doncc.a
donnera55
), moins vous avez créé un attribut de données avec le même nom (pourb.a
donne encore15
).