2008-11-29 5 views
15

Je suis en train de faire ce qui suit en python:stockage fonctions python non liées dans un objet de classe

Dans un fichier appelé foo.py:

# simple function that does something: 
def myFunction(a,b,c): 
    print "call to myFunction:",a,b,c 

# class used to store some data: 
class data: 
    fn = None 

# assign function to the class for storage. 
data.fn = myFunction 

Et puis dans un fichier appelé bar.py : import foo

d = foo.data 
d.fn(1,2,3) 

Cependant, je reçois l'erreur suivante:

TypeError: unbound method f() must be called with data instance as first argument (got int instance instead)

Cela est assez juste je suppose - python traite d.myFunction comme une méthode de classe. Cependant, je veux le traiter comme une fonction normale - donc je peux l'appeler sans avoir à ajouter un paramètre 'self' inutilisé à la définition de myFunction.

La question est:

Comment puis-je enregistrer une fonction dans un objet de classe sans la fonction d'être liés à cette classe?

+0

Je pense que vous avez l'intention d'utiliser: d.fn (1,2,3) et pas d.myFunctions (1,2,3) –

+0

oui, je pense que vous vouliez dire d.fn() – hop

+1

La solution est ci-dessous, mais pourquoi voudriez-vous cela? – orip

Répondre

23
data.fn = staticmethod(myFunction) 

devrait faire l'affaire.

+0

C'est la bonne réponse et la bonne syntaxe puisque la fonction est définie ailleurs. – tzot

0

Cela me semble inutile. Pourquoi ne pas simplement appeler myFunction quand vous en avez besoin?

En général, en Python, nous utilisons des modules pour ce type d'espace de noms (contrairement à Java où vous n'avez aucun choix). Et bien sûr, myFunction est déjà lié à l'espace de noms du module lorsque vous le définissez.

It is discussed somewhat in the answers to this question.

+0

Je suppose que vous pouvez attacher une fonction particulière à un objet, puis l'appeler par l'objet sans se préoccuper de savoir quelle fonction il appelle réellement. –

+0

Mal compris ce que le PO faisait, n'a pas remarqué qu'il s'agissait d'une méthode de classe pas une méthode d'instance. –

+0

L'appeler quand c'est nécessaire est génial - mais lors des tests, vous pouvez souhaiter simuler la fonction d'appel - cela devient plus délicat avec les membres qui appellent des fonctions car il est difficile de capturer leur portée. – Glycerine

1

Qu'est-ce que vous pouvez faire est:

d = foo.data() 
d.fn = myFunction 

d.fn(1,2,3) 

Ce qui peut ne pas être exactement ce que vous voulez, mais fonctionne.

0

Merci à André pour la réponse - si simple!

Pour ceux d'entre vous qui se soucient, peut-être que j'aurais dû inclure tout le contexte du problème. Voici quand même:

Dans mon application, les utilisateurs peuvent écrire des plugins en python. Ils doivent définir une fonction avec une liste de paramètres bien définie, mais je n'ai pas voulu leur imposer de conventions de nommage.

Ainsi, tant que les utilisateurs écrivent une fonction avec le nombre correct de paramètres et types, tout ce qu'ils ont à faire est quelque chose comme ça (rappelez-vous, c'est le code du plugin):

# this is my custom code - all plugins are called with a modified sys.path, so this 
# imports some magic python code that defines the functions used below. 
from specialPluginHelperModule import * 

# define the function that does all the work in this plugin: 
def mySpecialFn(paramA, paramB, paramC): 
    # do some work here with the parameters above: 
    pass 

# set the above function: 
setPluginFunction(mySpecialFn) 

L'appel setPluginFunction prend l'objet fonction et le place dans un objet classe caché (avec d'autres choses liées à la configuration du plugin, cet exemple a été quelque peu simplifié). Lorsque l'application principale veut exécuter la fonction, j'utilise le module runpy pour exécuter le code du plugin, puis extraire l'objet de classe mentionné ci-dessus - cela me donne les données de configuration et la fonction plugin pour que je puisse l'exécuter proprement (sans polluer mon espace de noms).

Tout ce processus est répété plusieurs fois pour différents plugins sur la même entrée, et semble fonctionner très bien pour moi.

+0

"tous les plugins sont appelés avec un sys.path modifié" Modifiez-vous temporairement le sys.path dans un bloc try/finally ou existe-t-il un moyen de "masquer" le sys.path global? – haridsv

+4

Veuillez utiliser le lien modifier de votre question pour ajouter des informations supplémentaires. Le bouton Post-réponse ne doit être utilisé que pour les réponses complètes à la question. – cpburnz

Questions connexes