IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Ajout d'arguments à une fonction


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut Ajout d'arguments à une fonction
    Bonjour,

    J'essaye de rajouter dynamiquement un argument à une fonction de manière efficace (j'aurais pu wrapper ma fonction par une autre, ou assigner dans func_globals pour émuler le même comportement, mais c'est plus long)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    def add_arg(f,name,dvalue):
        """ Ajoute l'argument f(...,name=dvalue,*a,**k) à f """
        cod= f.func_code    
        # les variables locales, arguments et **/*arguments
        varnames= cod.co_varnames[:cod.co_argcount] + (name,) + cod.co_varnames[cod.co_argcount:]
        # nombre de vrais arguments (avec defaults, avant *a et *k)
        argcount= cod.co_argcount+1
        # les noms non référencés (len)
        names= tuple( (n for n in cod.co_names if not(n==name))) # on la retire
        # compte les varnames, pas les names
        nlocals= cod.co_nlocals+1
     
        print varnames,argcount,names #,n_locals
     
        y_code = types.CodeType(argcount,
            nlocals,
            cod.co_stacksize,
            cod.co_flags,
            cod.co_code,
            cod.co_consts,
            names,
            varnames,
            cod.co_filename,
            cod.co_name,
            cod.co_firstlineno,
            cod.co_lnotab)    
     
        dynf = types.FunctionType(y_code, f.func_globals)
        dynf.func_defaults= f.func_defaults+ (dvalue,)
     
        return dynf
     
    def DEMOadd():
        def f(arg0,arg1=1,*argtup,**argdict):
            print unnamed
            len([])
            localv1= unnamed+arg0        
            return localv1
        dynf= add_arg(f,'unnamed',1)
        # printfun(dynf)
        print dynf(1,2,3)
    Evidement, ca ne marche pas (l'application crashe sans message de la part de Python). Assigner le y_code à f plutôt qu'à une copie dynf ne marche pas non plus.

    Quand je regarde ce code (faisant en outre la même chose) : http://code.activestate.com/recipes/...-compile-time/, je réalise que c'est plus compliqué et qu'il faut toucher à l'attribut co_code.

    Brièvement, pourquoi est_ce nécessaire ? Ou puis je trouver la doc permettant de comprendre le code sur le lien ci dessus ?

    Merci d'avance

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Ajouter un argument sans modifier le code de la fonction, c'est censé donner quoi ? C'est pour masquer une variable globale utilisée dans la fonction ?

    Le code est déjà compilé en bytecode (cod.co_code). Le bytecode utilise des instructions différentes pour manipuler les variables locales, globales ou dans la "closure", et les arguments sont référencés par position, pas par nom.

    Tu peux expérimenter avec le module dis.
    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> gvar = 42
    >>> def f(x,y):
    	def g(z,t):
    		return y + t + gvar
    	return g
     
    >>> dis.dis(f(3,4))
      3           0 LOAD_DEREF               0 (y)
                  3 LOAD_FAST                1 (t)
                  6 BINARY_ADD          
                  7 LOAD_GLOBAL              0 (gvar)
                 10 BINARY_ADD          
                 11 RETURN_VALUE
    On voit ici trois instructions différentes pour accéder aux variables (LOAD_DEREF, LOAD_FAST et LOAD_GLOBAL) ainsi que leur argument (0,1,0). Pour retrouver le nom de la variable, comme le fait dis.dis, il faut utiliser les autres attributs de func_code (par exemple, co_varnames pour LOAD_FAST).

  3. #3
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 062
    Par défaut
    J'essaye de rajouter dynamiquement un argument à une fonction de manière efficace
    Qu'entends-tu par manière efficace?

    rajouter dynamiquement un argument -> ça j'ai carrément pas compris, faudra être plus explicite, voir donner un exemple d'utilisation concret.

  4. #4
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    faudra être plus explicite
    * Faire plus efficacement (c'est à dire sans globals() lookup) ce que ferait une modification de func_globals, par exemple des codes de tests simples et réutilisables.
    * Optimisation par décorateur: passer dans locals() les globals utilisées par une fonction (regarder le lien que j'ai posté, c'est un bel exemple)
    * Une sorte de python-calcul symbolique dans lequel on peut injecter des valeurs pour des variables muettes (par exemple un décorateur "dérivée symbolique" pour une fonction réelle)

    Merci pour l'explication claire Dividee. L'identifiant "inconnu" est par défaut dans names, ce qui correspond aux globals, et j'essaye de la déplacer dans une autre "table". J'imagine qu'il n'existe pas de moyen simple de recréer le bytecode avec les modifications que j'essaye d'imposer.

    J'ai l'impression que ce module répondra à mes questions et besoins, je vais voir ca
    http://code.google.com/p/byteplay/

    Merci !

Discussions similaires

  1. Réponses: 4
    Dernier message: 19/05/2015, 20h21
  2. Réponses: 13
    Dernier message: 07/05/2006, 11h54
  3. [JAVASCRIPT] passage d'argument à une fonction
    Par LE NEINDRE dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 03/06/2005, 18h17
  4. [class] Ajouter class devant une fonction
    Par Pedro dans le forum Langage
    Réponses: 12
    Dernier message: 07/03/2005, 13h11
  5. Passer une fonction comme argument à une fonction
    Par Cocotier974 dans le forum Général Python
    Réponses: 4
    Dernier message: 29/06/2004, 13h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo