2009-06-18 4 views
24

Pourquoi ne puis-je effectuer une action comme ce qui suit:Pourquoi "self" dans les objets Python est-il immuable?

class Test(object): 
    def __init__(self): 
     self = 5 

t = Test() 
print t 

j'attendre pour imprimer 5 puisque nous écrasez l'instance avec elle, mais il ne fait rien du tout. Ne jette même pas une erreur. Juste ignore la cession. Je comprends qu'il n'y aurait guère de situations où l'on voudrait faire cela, mais il semble toujours étrange que vous ne pouvez pas.

Mise à jour: Je comprends maintenant pourquoi ça marche, mais j'aimerais tout de même de ne pas savoir s'il y a un moyen de remplacer une instance à partir de l'instance.

+2

"De l'intérieur", pas vraiment: __new__, que j'ai suggéré, appartient à la classe, pas à l'instance. Vous pouvez normalement modifier le __class__ et/ou l'état (via __dict__) de la plupart des objets ("most" parce que certains sont immuables et/ou n'utilisent pas __dict__), mais pas le * IDENTITY * de l'objet - id (obj) sera la même avant et après votre altération. Le vaisseau de Télémaque me vient à l'esprit, mais cet autre sujet semble plus approprié pour une question différente, car il a peu à voir avec le titre de celui-ci. –

+3

-1: Le remplacement d'une instance rompt un concept fondamental: les objets ont une identité unique. Renvoyer une nouvelle instance - c'est-à-dire - une Usine - a du sens. Qu'essayez-vous de faire? –

Répondre

59

Toute simple affectation-tout argument de toute fonction se comporte exactement de la même manière en Python: ce nom se fixe à une valeur différente, et ne fait rien d'autre que ce soit. Donc, loin d'être étrange (simplement = assigner à un argument spécifique dans une fonction spécifique n'a pas visible de l'extérieur.) "

" Aucun cas spécial n'est assez spécial pour enfreindre les règles ". effet quel qu'il soit), ce serait étonnant si ce cas spécifique fonctionnait d'une autre manière, juste à cause des noms de la fonction et de l'argument en question.

Si jamais vous voulez faire une classe qui construit un objet d'un autre type que lui-même, un tel comportement est bien sûr tout à fait possible - mais il est obtenu en remplaçant la méthode spéciale __new__, pas__init__:

class Test(object): 
    def __new__(cls): 
     return 5 

t = Test() 
print t 

Cette émet 5. Le comportement __new__/__init__ en Python est un exemple du modèle de conception "construction en deux étapes": le "constructeur" proprement dit est __new__ (il construit et retourne un objet (normalement non initialisé) (normalement un nouveau du type/classe en question), __init__ est le « initialiseur » qui initialise correctement le nouvel objet

cela permet, par exemple, la construction d'objets qui sont immuables une fois construits: dans ce cas, tout doit se faire dans __new__, avant que l'objet immuable. est construit, puisque, étant donné que l'objet est immuable, __init__ ne peut pas le muter pour l'initialiser

+0

Ah, c'est logique. Savez-vous comment j'accomplirais ce que je voulais, par hasard? –

+1

déjà édité la réponse pour expliquer: avec __new__, le "constructeur propre", pas avec __init__, le "initialiseur". –

1

Dr. Egon Spengler: Ce serait mauvais.
Dr Peter Venkman: Je ne suis pas d'accord sur tout ce qui est bon ou mauvais. Que voulez-vous dire, "mauvais"?
Dr. Egon Spengler: Essayez d'imaginer toute la vie telle que vous la connaissez en vous arrêtant instantanément et chaque molécule de votre corps explose à la vitesse de la lumière.

+2

Ce ne serait pas * que * mauvais. C'est un idiome connu dans Smalltalk, par exemple, et les programmeurs Smalltalk n'ont pas systématiquement toutes les molécules dans leur corps explosent à la vitesse de la lumière ... Je pense * sourire *. – itowlson

+9

oh, je pensais que c'est pourquoi il n'y en avait plus beaucoup. – anthony

+2

Droite. C'est mauvais. D'accord. D'accord. Conseil de sécurité important. Merci, anthony. –

9

Il ne "ignore" pas l'affectation. cession fonctionne très bien, vous avez créé un nom local qui pointe vers les données 5.

Si vous vraiment voulez faire ce que vous faites ...

class Test(object): 
    def __new__(*args): 
     return 5 
+0

Bonne idée! Semble fonctionner aussi: http://codepad.org/8sgInhvO –

+2

En effet. Mais la véritable tâche à accomplir est de remplacer l'instance de l'instance, ce qui n'est pas le cas. –

3

Je viens de faire un test rapide, et vous pouvez assigner à self. Dans votre méthode init(), imprimez la valeur de self. Vous verrez que c'est 5.

Ce qui vous manque ici, c'est que les paramètres sont passés par valeur dans Python. Ainsi, changer la valeur d'une variable dans une fonction ou une méthode ne la changera pas pour le monde extérieur. Tout cela étant dit, je déconseille fortement de ne jamais changer de soi.

+1

Je serais d'accord que changer de soi est une idée terrible. MAIS il serait toujours intéressant de savoir s'il existe un moyen de remplacer une instance dans l'instance. –

1

Parfois, vous voulez faire cela, mais pas avec des types immuables comme int:

>>> class Test(list): 
    ... def __init__(self): 
    ... list.__init__(self, [1,2,3]) # self = [1,2,3] seems right, but isn't 

>> t = Test() 
>> print t 
[1, 2, 3] 
-3
class Test(object): 
    def __init__(self): 
     self = 5 

t = Test() 
print t 

est comme avoir cette PHP (seule autre lang je sais, désolé)

class Test { 
    function __construct() { 
      $this = 5; 
     } 
} 

Je ne vois pas en quoi cela a du sens. remplacer l'instance par une valeur?

+0

Comment cela n'a-t-il pas de sens? Ce serait la même chose que: $ test = new Test(); $ test = 5; Mais de l'intérieur au lieu de l'extérieur. –

Questions connexes