112 votes

__getattr__ sur un module

Comment peut mettre en œuvre l’équivalent d’un `` sur une classe, un module ?

Exemple de

Lors de l’appel d’une fonction qui n’existe pas dans un module manière statique défini attributs, je souhaite créer une instance d’une classe dans ce module, et appeler la méthode portant le même nom comme ayant échoué dans la recherche d’attribut sur le module.

Ce qui donne :

108voto

Ethan Furman Points 12683

Il y a deux principaux problèmes que vous rencontrez ici:

  1. __xxx__ méthodes sont seulement leva les yeux sur la classe
  2. TypeError: can't set attributes of built-in/extension type 'module'

(1) signifie que toute solution devra également suivre le module a été examiné, sinon chaque module serait alors l'exemple de substitution de comportement; et (2) signifie que (1) n'est même pas possible... du moins pas directement.

Heureusement, sys.des modules n'est pas pointilleux sur ce qui se passe il y a donc un wrapper de travail, mais uniquement pour le module d'accès (c'est à dire import somemodule; somemodule.salutation('world'); le même module d'accès vous devez tirer sur les méthodes de la classe de substitution et les ajouter à l' globals() eiher avec une méthode personnalisée sur la classe (j'aime utiliser .export()) ou avec une fonction générique (comme ceux déjà inclus dans la liste des réponses). Une chose à garder à l'esprit: si le wrapper est la création d'une nouvelle instance à chaque fois, et le globals solution n'est pas, vous vous retrouvez avec une subtile différence de comportement. Oh, et vous ne devez pas utiliser les deux en même temps-c'est l'un ou l'autre.


Mise à jour

De Guido van Rossum:

Il est en fait un hack qui est parfois utilisée et recommandée: le module peut définir une classe avec la fonctionnalité désirée, puis à à la fin, remplacer lui-même dans sys.modules avec une instance de cette classe (ou avec la classe, si vous insistez, mais c'est généralement moins utiles). E. g.:

# module foo.py

import sys

class Foo:
    def funct1(self, <args>): <code>
    def funct2(self, <args>): <code>

sys.modules[__name__] = Foo()

Cela fonctionne parce que l'importation de machines est activement à l'activation de ce hack, et comme la dernière étape tire le réel module de sys.modules, après le chargement. (Ce n'est pas un hasard. Le hack a été proposé il y a longtemps et nous avons décidé de nous aimais assez pour le soutenir dans la importer des machines.)

Donc, l'établi de façon à accomplir ce que vous voulez, c'est de créer une classe unique dans votre module, et que le dernier acte de la module de remplacer sys.modules[__name__] avec une instance de votre classe -- et maintenant vous pouvez jouer avec __getattr__/__setattr__/__getattribute__ en tant que de besoin.

46voto

Håvard S Points 11152

Il s’agit d’un hack, mais vous pouvez encapsuler le module avec une classe :

19voto

S.Lott Points 207588

Nous ne le faisons habituellement comme ça.

Ce que nous faisons est la suivante.

Pourquoi ? Afin que l’instance globale implicite n’est visible.

Pour obtenir des exemples, regardez la `` module, ce qui crée une instance globale implicite pour simplifier un peu les cas d’utilisation où vous voulez un « simple » générateur de nombres aléatoires.

13voto

Matt Anderson Points 7461

Semblable à ce que @Håvard proposé, dans un cas où je nécessaire pour mettre un peu de magie sur un module (comme __getattr__- )), je voudrais définir une nouvelle classe qui hérite de l' types.ModuleType et de mettre en sys.modules (probablement remplacer le module où ma coutume ModuleType a été défini).

Voir les principales __init__.py le fichier de Werkzeug pour une assez bonne mise en œuvre de cette.

7voto

grieve Points 6303

Il s’agit d’hackers, mais...

Cela fonctionne en effectuant une itération sur tous les objets dans l’espace de noms global. Si l’élément est une classe, il parcourt les attributs de la classe. Si l’attribut est rachetable il l’ajoute à l’espace de noms global en fonction.

Il ignore tous les attributs qui contiennent « __ ».

Je n’utiliserais cela dans le code de production, mais il devrait vous aider à démarrer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X