2016-03-14 1 views
2

J'ai deux fonctions:Python: Passage fonction avec des arguments à une fonction

  1. fonction bibliothèque

    que je ne peux pas changer dire lib_func(func, param1)
    dire lib_func prend une fonction func et un autre paramètre param1 comme arguments.

  2. fonction définie par l'utilisateur user_func.

Par exemple:

x = 0 
y = 0 
def user_func(): 
    global x 
    global y 
    return sqrt(x*y) 

Maintenant, le problème est que je veux passer x à user_func comme argument non comme GLOBALS en passant user_func à lib_func.

+0

Vous ne pouvez pas modifier user_func() aussi, non? –

+0

oui vous pouvez modifier user_func –

+0

Si vous pouvez modifier user_func, quel est le problème? Arrêtez simplement d'utiliser des variables globales! –

Répondre

1

Une fonction est simplement un objet que l'on peut appeler ainsi définir une classe avec une méthode __call__ équivaut en principe à définir une fonction. Au moins dans le contexte que vous donnez.

Alors:

def user_func(x, y, z): 
    return anything_with(x, y, z) 

équivaut à:

class user_class(object): 
    @staticmethod # staticmethod so that it can be called on the class 
    def __call__(x, y, z): 
     return anything_with(x, y, z) 

tel qu'il se présente est tout simplement faux-fuyants. Mais la magie se produit lorsque vous créez une instance avec des attributs prédéfinis et vous ne spécifions les arguments variables en tant que paramètres pour la call:

class user_class(object): 
    def __init__(self, x): 
     self.x = x 

    def __call__(self, y, z): # No x as parameter! 
     return do_anything_with(self.x, y, z) # use the predefined x here 

mais vous devez modifier la façon dont vous appelez lib_func alors:

x = 0 
user_class_instance = user_class(0) 
result = lib_func(user_class_instance, param1) 

il répétera appeler l'instance avec différents y et z mais x sera maintenue constante


La plupart de ces paramètres variables fonctions permettent cependant lib_func passer (par exemple qui sera donné au user_func), par exemple scipy.optimize.curve_fit:

curve_fit(user_func, x, y, [initial_guess_param1, param2, ...]) 

il user_func sera appelé par curve_fit interne (vous n'avez pas faire quoi que ce soit) comme:

user_func(x, initial_guess_param1, param2, ...) 
# Then curve-fit modifies initial_guess_param1, param2, ... and calls it again 
user_func(x, initial_guess_param1, param2, ...) 
# and again modifies these and calls again 
user_func(x, initial_guess_param1, param2, ...) 
# ... until it finds a solution 

il x et y sont définis et pas changé lors de l'appel, mais curve_fitinitial_guess_param1 sera changé tout en trouvant le curve_fit optimal.

1

Vous pouvez envelopper votre user_func() avec une autre fonction

def parameterized_func(local_x): 
    global x 
    x = local_x 
    return user_func() 

Et puis passer la nouvelle fonction parameterized_func() à votre lib_func(). Ce n'est pas très agréable, et changera évidemment la variable globale x. Je suggère de regarder dans et voir si vous ne pouvez pas changer la fonction user_func() à la place.

+0

Mais nous ne pouvions toujours pas nous débarrasser des globals. –

+0

Vous ne pouvez pas vraiment vous débarrasser de l'utilisation de globals sauf si vous avez la permission/possibilité de changer 'user_func()'. –

1

Si je comprends bien la tâche, vous aurez besoin de deux choses:

  1. Créer une nouvelle fonction pour envelopper user_func avec x, y params

  2. utilisation functools.partial pour obtenir une fonction plus avec passé params

Voici un exemple.

Module user_module.pyuser_func défini:

x = 0 
y = 0 
def user_func(): 
    global x 
    global y 
    print('user_func', x, y) 

Module main.py où vous avez besoin d'emploi fait:

def lib_func(func, param1): 
    print('lib_func', param1) 
    func() 


# Create user_func with params: 
import user_module 

def new_user_func(x, y): 
    user_module.x = x 
    user_module.y = y 
    user_module.user_func() 


# Use functools.partial to create user_func with ready params: 
from functools import partial 

f = partial(new_user_func, 1, 2) 
lib_func(f, 'param1') 

f = partial(new_user_func, 3, 4) 
lib_func(f, 'param1') 

sortie pour cet exemple:

lib_func param1 
user_func 1 2 

lib_func param1 
user_func 3 4 
+0

lib_func va appeler user_func à plusieurs reprises avec de nouveaux arguments. –

+0

@iota, il suffit de créer un nouveau func avec partial pour chaque ensemble d'arguments. J'ai mis à jour la réponse pour le montrer. –

-2

essayer d'envelopper le user_func et ré tourner une nouvelle fonction pour lib_func:

def wrapuserfunc(x): 
    user_func.x = x 
    return user_func 

def user_func(): 
    if hasattr(user_func, 'x'): 
     print user_func.x 

lib_func(wrapuserfunc(1), param1) # user_func.x = 1 
# get x in user_func 
print user_func.x # x = 1 

wrapuserfunc(x) fonctionne très bien. La fonction est un objet en Python.