2017-08-27 1 views
0

J'essaie de me prouver que je peux redéfinir la syntaxe du langage Python. Fondamentalement, l'une des facettes de la métaprogrammation. Mais j'ai du mal à écraser le comportement de la classe object intégrée.Python: Puis-je remplacer le __getattr__ dans un objet (intégré)?

J'essaye de changer le comportement où un AttributeError est levé quand un objet n'a aucun attribut spécifique. Au lieu de cela, j'essaye de forcer Python à se comporter comme JavaScript, en retournant None dans le cas. C'est un exercice pour essayer de mieux comprendre les built-ins de Python, pas vraiment un problème pratique.

Une fois que je l'ai modifié, je ne peux plus créer d'objets. Voici ma tentative de modifier le comportement de object:

#!/usr/bin/env python 

class object(type): 
    def __new__(self, *args, **kwargs): 
     print(args) 
     return super(object, self).__new__(object, *args, **kwargs) 
    def __init__(self, *args, **kwargs): 
     self._dict = {} 
     super(object, self).__init__(*args, **kwargs) 
    def __getattribute__(self, key): 
     print('GET -> LONG METHOD') 
     if key.startswith('_'): 
      raise TypeError('Cannot modify built-ins') 
     return self._dict.get(key) 
    def __getattr__(self, key): 
     print('GET -> SHORT METHOD') 
     if key.startswith('_'): 
      raise TypeError('Cannot modify built-ins') 
     return self._dict.get(key) 
    def __setattr__(self, key, value): 
     if key.startswith('_'): 
      raise TypeError('Cannot set directly on built-ins') 
     self._dict[key] = value 

class A(object): 
    pass 

a = A() 

a.yay = 7 
print(a.yay) 
print(a.yup) # should be None 

Je ne sais pas exactement quelle est la méthode __getattribute__ mais quand je visitai object je l'ai trouvé avait cette méthode au lieu de __getattr__, donc je l'ai écrasé à la fois (Au cas où).

Le problème avec le code est que pendant la instatiation de a = A() choses exploser:

Traceback (most recent call last): 
    File "py.py", line 34, in <module> 
    a = A() 
    File "py.py", line 12, in __new__ 
    return super(object, self).__new__(self, *args, **kwargs) 
TypeError: type.__new__() takes exactly 3 arguments (0 given) 

Le message d'erreur me semble erroné de. Je passe définitivement au moins 1 argument à __new__ dans:

return super(object, self).__new__(object, *args, **kwargs) 

Au départ, je ne passait pas cet argument du tout, étant donné que la classe doit être transmis à l'intérieur *args de toute façon. J'ai ajouté l'instruction print à la méthode __new__ et j'ai constaté que rien ne lui était transmis.

Est-il vraiment impossible de changer le comportement des built-ins en Python? Ou je le fais juste mal?

+0

Même si vous réussissez, vous ne modifierez que les nouvelles classes qui héritent de votre «objet» fictif, et vous causerez des problèmes en observant l'original. Essayez de lui donner un nom différent. De plus, rien de tout cela ne change la syntaxe *. – jonrsharpe

Répondre

0

L'erreur particulière que vous rencontrez est due au fait que vous avez déclaré class object(type). Ce n'est pas ainsi que vous déclarez vouloir que votre classe soit un type; toutes les classes sont des types (sauf si vous êtes sur Python 2 et que vous créez une classe classique).

Vous avez déclaré que vous voulez que votre classe soit une sous-classe de type, donc toutes les instances de votre classe seront des types. return super(object, self).__new__(...) appelle type.__new__, ce qui ne prend pas ce que vous lui passez. Mis à part le problème ci-dessus, vous avez également beaucoup plus de problèmes, certains superficiels, certains fondamentaux. Le plus fondamental est que la définition de votre propre classe nommée object ne fera rien au type intégré object. Bien qu'il soit techniquement possible de visser avec le object intégré en utilisant ctypes, il est possible de violer toutes sortes d'invariants de langue avec ctypes. Cela est loin d'être sûr.