2010-09-06 13 views
1
>>> class S(object): 
...  def __init__(self): 
...    self.x = 1 
...  def x(self): 
...    return self.x 
... 
>>> s = S() 
>>> s.x 
1 
>>> s.x() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not callable 

Pourquoi, dans cet exemple, est s.x une méthode, mais aussi un entier? Il me semble que self.x = 1 devrait remplacer la déclaration def x(self): de l'attribut x lors de l'instanciation. Pourquoi est-ce que je peux obtenir et appeler, résultant en un entier et une méthode, respectivement, le même attribut? Ma conjecture est que le modèle de recherche de variable dans les classes de nouveau style est typé par le canard, afin de renvoyer le résultat le plus pertinent à l'appelant. J'aimerais entendre toute l'histoire.python - comportement étrange question

Répondre

2

Il semble que vous ayez une mauvaise compréhension de l'erreur que vous voyez. Lorsque votre objet s est instancié, son constructeur remplace la méthode x par un entier, donc dans l'objet s, x est un entier, pas une fonction. Si vous essayez de l'appeler comme une méthode, une exception est levée.

Python est typé canard dans le sens où les appels de méthode sont résolus lors de l'exécution - le compilateur n'a pas de problème avec s.x() parce x aurait été créé comme une méthode dynamique. Cependant, lorsque l'interpréteur appelle effectivement x comme méthode, il remarque x est un nombre entier et ne peut pas être appelé, d'où le TypeError.

+0

Ah, merci. Je ne sais pas pourquoi j'essaie d'être philosophique tard dans la nuit. Ça ne marche jamais très bien. J'étais dans l'état d'esprit de @decorator et j'ai seulement vu le 'return self.x' comme ce qui était finalement appelé. Et, je ne sais même pas ce qui m'a fait penser à essayer ceci, pas pour aggraver les choses :) – orokusaki

1

Je ne suis pas sûr de ce que vous pensez, mais il n'y a rien de si compliqué. Lorsque vous affectez self.x = 1, la méthode x n'est plus accessible. À partir de ce moment, s.x est seulement un nombre entier - essaie de l'appeler comme une méthode entraîne une exception, comme vous l'avez vu.

0

Il semble que la propriété x est définie en tant que méthode dans la définition de classe. Cependant, instancier réellement un objet écrase ce nom avec un entier - d'où le comportement observé. Ce n'est jamais réellement deux à la fois. Donc, c'est fondamentalement un code défectueux.

3

Python n'utilise pas d'espaces séparés pour les objets appelables et non appelables: un nom est un nom. s.x, par les règles Python, doit se référer à exactement le même objet, si vous allez l'appeler ou non. Une autre façon de le mettre: en supposant que _aux est un nom pas autrement utilisé,

_aux = self.x 
_aux() 

et

self.x() 

doit avoir une sémantique absolument identique en Python, le fait que dans le premier cas, la valeur intermédiaire self.x est lié à un nom et appelé plus tard nonobstant. Avoir des espaces de nommage uniques, "unifiés" pour les appelables et les non-appelables a un grand nombre d'avantages - il rend les règles de recherche de nom (pour chacun des noms nus et qualifiés) énormément plus simples, par exemple, en les découplant totalement à partir du but auquel le nom en cours de recherche va être mis (soit immédiatement après le résultat de la recherche, ou plus tard encore), et aussi du type (appelable ou non) de n'importe quel objet se présente être d'abord référencé selon les règles de recherche.

Surtout vu le nombre de différents types appelables Python a (fonctions, classes, instances de classes qui définissent __call__, types spéciaux tels que staticmethod et classmethod, ...!-), toute autre règle ne pouvait que conduire au chaos total. (Notez aussi, par exemple, que même C++, un langage qui n'a pas peur de la complexité mais également permet aux instances de classes d'être appelées [[si la classe surcharge operator()]], utilise une règle d'espace de nom unifiée similaire - encore une fois, faire la distinction entre les appelables et les non-appelables serait un cauchemar totalement injustifié, si les règles étaient différentes à cet égard! -).

+0

@Alex - comme toujours, bonne réponse. Je pense que @Eli a répondu à ma meilleure question, car elle n'était pas basée sur la théorie pratique, mais plutôt sur un manque d'attention de ma part. – orokusaki

+0

@Alex: totalement sans rapport mais je dois demander de toute façon. Quel est le '! -)'? J'ai entendu le '! 'Peut être utilisé comme un clin d'oeil mais j'ai l'habitude de voir' ;-) 'comme un clin d'oeil. '-)' signifie la langue-dans-joue, et peut-être vous le combinez avec le point d'exclamation pour l'accentuation. Je vous ai vu l'utiliser plusieurs fois, et je me suis toujours demandé ce que c'était. Désolé de l'avoir mis ici, mais je suis curieux: P – avacariu

+0

@vlad, c'est une variante-clin d'oeil, comme, par exemple. '? -)' - Je suppose que ';-)' est aussi bien, mais peut-être que j'ai plus de "clin d'oeil", alors je préfère les signes de ponctuation plus "étendus" dans mes émoticônes. –

0

C'est ce que votre code est en train de faire:

  1. Créer une classe nommée S avec 2 méthodes, __init__ et x
  2. Créer une instance de S et nommez-le s
    1. Appel S.__init__ avec s comme paramètre
      1. Set s.x avec la valeur 1
  3. Imprimer s.x
  4. Imprimer le résultat de l'appel s.x

Maintenant, si vous regardez 2.1.1, vous verrez que vous avez overrided la méthode x avec un nombre entier, ce qui signifie que vous ne pouvez pas appeler à nouveau avec s (mais il reste dans la classe S)

Si vous avez fait cela, et pourtant, besoin d'appeler la fonction x, essayez:

>>> class S(object): 
...  def __init__(self): 
...   self.x = 1 
...  def x(self): 
...   return self.x 
... 
>>> s = S() 
>>> s.x 
1 
>>> S.x(s) 
1 
>>> 

Je l'ai juste fait pour vous comprendre pourquoi vous perdez x comme méthode, faire de la bonne façon et éviter d'avoir des variables instances avec le même nom que les méthodes de classe

+0

merci. Je comprends. J'ai juste mal lu l'exception quand il imprimé (fatigué et retardé de camper), et a sauté à une conclusion. – orokusaki