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 :

map avec arg constant


Sujet :

Python

  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 map avec arg constant
    Bonjour,

    Comment utiliser map(f,...) lorsqu'un des arguments de f() est constant (i.e ne dépend pas de l'itérable) ?

    Pour l'instant je multiplie une liste avec l'argument constant. A priori peu efficace (un appel à len() et la multiplication de la liste).

    Voici un exemple (voir fonction f5() ), ou j'essaye d'optimiser le problème suivant: créer la liste l_x des o.x depuis une liste l d'objets o ayant un champ x.
    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
     
    def get_x(r):
        return r.x
    import random    
    class obj:
        def __init__(self): self.x= random.random()
        def f(self): return self.x
     
    o= obj()
    l= [o]*1000
     
    def f1():
        l_x=[]
        for k in l: l_x.append(k.x)
    def f2():
        l_x=[k.x for k in l]
    def f3():        
        l_x= map(get_x,l)
    def f4():        
        l_x= map(obj.f,l)
    "Exemple de map avec argument constant"
    def f5():
        l_constantArg= ["x"]*len(l)
        l_x= map(getattr,l,l_constantArg)
     
    def run(fun,repet,name,*args,**kargs):
        """ appel fun(*args,**kwargs) repet. fois. Mesure et affiche le temps """
        R= xrange(repet)
        t= time.clock()
        for m in R:
            res= fun(*args,**kargs)
        dt= time.clock() - t
        print "fun %s has run.%s in %s " %(name,repet,dt)
     
    run(f1,100,'for k in :',l)
    run(f2,100,'[list_comp]',l)   
    run(f3,100,'map global get_x()',l)
    run(f4,100,'map class.get()',l)
    run(f5,100,'map getattr',l)

    Resultats (debug mode san psyko):
    fun for k in : has run.100 in 0.0350195346057
    fun [list_comp] has run.100 in 0.0227143393923
    fun map global get_x() has run.100 in 0.798853485569
    fun map class.get() has run.100 in 0.848990583999
    fun map getattr has run.100 in 0.0160827702962

    NB: Le gain dépend fortement de la longueur de la liste l. Il n'a pas l'air monotone.

    Resultats (avec psyko):
    fun for k in : has run.100 in 0.019553602483
    fun [list_comp] has run.100 in 0.00934755674255
    fun map global get_x() has run.100 in 0.0231512664319
    fun map class.get() has run.100 in 0.0810935468055
    fun map getattr has run.100 in 0.0158168147069


    La question est puis-je faire mieux que f5() ?

    Par exemple comment puis-je appeler la built-in getattr avec un tuple d'argument (je pense à map(gettattr, zip(l,["x"]) ), qui ne marche pas tel quel.

    Mes essais avec zip ou iterttools.starmap() ou .imap() m'ont fortement decu.

    Dit autrement, comment combine-t'on les fonctions built-in intelligemment pour obtenir une classe de fonctions assez large ?


    Merci d'avance

  2. #2
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    bonsoir,

    oui tu peux mieux faire que f5 avec... f2 (c'est aussi f2 la plus rapide sur mon PC).

    après pour répondre à ta question, tu recherches en faite à faire une closure:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def closure(f, arg2):
        def _closure(arg1):
            return f(arg1, arg2)
    getattrx = closure(getattr, 'x')
    print getattrx(o)

  3. #3
    Membre Expert
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Par défaut
    Salut,

    Tu peux le faire avec une fonction lambda

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def f5(*args, **kwargs):
        l_x= map(lambda o: getattr(o, 'x'), l)
    Mais par contre c'est plus lent.

  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 oui mais
    Merci pour vos réponses

    Néanmoins, tout le probleme est, partant d'une fonction built-in, d'obtenir une closure preservant a peu près la vitesse du built-in, pour que map reste bien mieux.

    J'ai essayé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    import functools
    def f6(l):    
        gg= functools.partial(getattr,"x")
        "  OU "
        gg= functools.partial(getattr,name="x")
        return map(gg,l)
    et j'obtiens respectivement
    TypeError: getattr(): attribute name must be string
    TypeError: getattr() takes no keyword arguments



    Une autre piste est de curryfier getattr et d'utiliser deux maps (la curryfiée devant conserver les performances de la built-in)

  5. #5
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    c'est normal, tu cherches à "fermer" le deuxième paramètre. et getattr ne supporte pas les arguments à mot-clé.

    du coup la closure réalisée par partial est incorrect, d'où la closure que je t'ai proposée pour fermer le second argument.

    je ne comprends pas ton soucis, map est plus lent que la compréhension de liste dans ce que tu montres.

  6. #6
    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
    Je me dis qu'en éliminant les couts (création de la liste, multiplication et accès à len), on peut peut être faire mieux.

    De plus est-ce vraiment bien de reposer sur Psyko pour juger (f5 est mieux que f2 sans psyko) ?

  7. #7
    Membre Expert
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Par défaut
    Vu que j'ai un peu répondu un peu a coté, m'étant arrêté à la question :

    Comment utiliser map(f,...) lorsqu'un des arguments de f() est constant (i.e ne dépend pas de l'itérable) ?

    Pour l'instant je multiplie une liste avec l'argument constant. A priori peu efficace (un appel à len() et la multiplication de la liste).
    je propose donc une autre solution, très légèrement plus rapide, mais évite une déclaration de liste.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def f6(*args, **kwargs):
        l_x=map(getattr, l, itertools.repeat('x', len(l)))

  8. #8
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    Citation Envoyé par VV33D Voir le message
    De plus est-ce vraiment bien de reposer sur Psyko pour juger (f5 est mieux que f2 sans psyko) ?
    sur mon PC (Win7-64bits) avec Python 2.6.5 (32bits), f2 est plus rapide même sans psycho (0.008s contre 0.01s avec f5)

    il me semble de toute façon que les map et filter étaient destinés à disparaitre de Python car redondants avec les listes comprehensions et qu'ils sont juste maintenus pour des raisons de compatibilité. Je n'arrive plus à retrouver où j'ai lu ceci.

  9. #9
    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
    Merci à tous pour vos conseils

    La solution avec repeat() est effectivement plus rapide (a peu près 15% de mieux que f5() sur quelques tests). Finalement pour l'accès aux membres d'une liste, vous m'avez convaincu que la compréhension de liste est mieux (même si je me dis qu'on peut encore faire mieux que f6() avec map).

Discussions similaires

  1. Réponses: 2
    Dernier message: 02/02/2008, 19h04
  2. [hibernate] Mapping avec identifiant composé
    Par miky_jo dans le forum Hibernate
    Réponses: 3
    Dernier message: 11/10/2005, 16h48
  3. [KODO]mapping avec JDO
    Par ksavieras dans le forum Persistance des données
    Réponses: 3
    Dernier message: 21/09/2005, 20h41
  4. creer champ avec valeur constante dans resultat de requete
    Par freejeje dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 20/05/2005, 10h52
  5. [Struts][Tiles] Probleme d'action mapping avec un dynaform
    Par bluefox_du_974 dans le forum Struts 1
    Réponses: 3
    Dernier message: 28/03/2005, 22h47

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