2017-01-29 2 views
1

Le parfait, mais impossible, scénario serait:avec des mots-clés à partir des attributs des instances

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

    def foo(self, x = self.x, y = self.y): 
     return x + y 

Il ne fonctionne pas parce que auto n'est pas défini. J'ai fait beaucoup de recherches, j'ai regardé des décorateurs, des descripteurs, des métaclasses, presque tout. La solution peut être la plus évidente et la plus connue de tous, mais je ne l'ai pas trouvée. Je pouvais gérer deux solutions de contournement, comme suit:

def prep(argslist, argsprovided, attributes): 
     argsout = [] 
     for name in argslist: 
      if name in argsprovided: 
       argsout.append(argsprovided[name]) 
      else: 
       argsout.append(getattr(attributes,name)) 

     return argsout 

class example(object): 

    # I can create a default instance or a custom one 
    def __init__(self,x = 1,y = 1,z = 1,w = 1): 

     self.x = x 
     self.y = y 
     self.z = z 
     self.w = w 

    # I can wrap a function to use the self argument  
    def wrapper(self): 
     def foo(x = self.x, y = self.y, z = self.z, w = self.w): 
      return x + y + z + w 
     return foo 

    # I can wrap 'joo' alongside with foo, and make 'wrapper' return a list  
    def joo(self, **kwargs): 
     [x,y,z,w] = prep(['x','y','z','w'],kwargs,self) 
     return x + y + z + 2*w 

    # I can use my custom 'prep' function to to the job 
    def foo(self, **kwargs): 
     [x,y,z,w] = prep(['x','y','z','w'],kwargs,self) 
     return x + y + z + w 



# Creates a default instance and a custom one   
c = example() 
d = example(2,2,2,2) 

# I can use 'foo' with the instance's default values with both wrapping and 'prepping' 
print(c.wrapper()()) 
print(d.wrapper()()) 
print(c.foo()) 
print(d.foo()) 

# I can use 'foo' with a mix of default values and provided values with both wrapping and 'prepping' 
print(c.wrapper()(1,2,3)) 
print(d.wrapper()(1,2,3)) 
print(c.foo(y = 3,z = 4,w = 5)) 
print(d.foo(y = 3,z = 4,w = 5)) 

Le code imprime:

4 
8 
4 
8 
7 
8 
13 
14 

J'ai une grande classe avec beaucoup de fonctions, chacun a besoin le comportement de « foo ». Ma solution de préparation prend trop de temps. Après avoir profilé le code, j'ai pensé qu'il passait 12 secondes à l'intérieur de la préparation seulement. Qu'est-ce qu'une façon intelligente et moins longue de faire cela? Je suis complètement perdu.

Répondre

1

Je ne suis pas sûr que cela aidera, mais que diriez-vous d'utiliser None comme valeur par défaut et utiliser une clause pour déterminer la valeur. Par exemple:

def foo(self, x=None, y=None): 
    real_x = x if x != None else self.x 
    real_y = y if y != None else self.y 
    return real_x + real_y 
+0

C'est en effet plus rapide! C'est une bonne option, mais certaines de mes fonctions prennent plus de 10 arguments, donc ce n'est pas ce practicle. La méthode wrapper est juste un peu plus lente. Le meilleur moyen est de définir k = c.wrapper(), puis d'utiliser k(). – RFiischer

0

J'ai trouvé six façons de faire ce que je voulais. Après le profilage du code, le résultat a été:

afoo  foo  noo1  noo2  wrap1  wrap2 
6.730 28.507 3.98  4.097 10.256 3.468 
6.407 28.659 4.096 3.924 9.783  3.529 
6.277 28.450 3.946 3.889 10.265 3.685 
6.531 30.287 3.964 4.149 10.077 3.674 

Comme vous le verrez en avant, noo1, noo2 et wap2 sont assez similaires sur le code. La méthode conventionnelle afoo n'est pas très efficace. Ma méthode personnalisée foo est terrible et wrap1 a été juste testée par souci d'exhaustivité.

afoo.py
L'inconvénient est que vous avez besoin d'une ligne supplémentaire pour chaque argument de la fonction.

class example(object): 

    # I can create a default class or a custom one 
    def __init__(self,x = 1,y = 1,z = 1,w = 1): 

     self.x = x 
     self.y = y 
     self.z = z 
     self.w = w 

    def afoo(self, x = None, y = None, z = None, w = None): 
     x = x if x != None else self.x 
     y = y if y != None else self.y 
     z = z if z != None else self.z 
     w = w if w != None else self.w 
     return x + y + z + w 


c = example(2,2,2,2) 
for i in range(0, 10000000): 
    c.afoo(1,2,3,4) 

foo.py
Celui-ci est le procédé plus lent.

def prep(argslist, argsprovided, attributes): 
     argsout = [] 
     for name in argslist: 
      if name in argsprovided: 
       argsout.append(argsprovided[name]) 
      else: 
       argsout.append(getattr(attributes,name)) 

     return argsout 

class example(object): 

    # I can create a default class or a custom one 
    def __init__(self,x = 1,y = 1,z = 1,w = 1): 

     self.x = x 
     self.y = y 
     self.z = z 
     self.w = w 

    def foo(self, **kwargs): 
     [x,y,z,w] = prep(['x','y','z','w'],kwargs,self) 
     return x + y + z + w 


c = example(2,2,2,2) 
for i in range(0, 10000000): 
    c.foo(x = 1,y = 2,z = 3,w = 4) 

wrapper1.py
bien moins efficace que wrapper2.py.

class example(object): 

    # I can create a default class or a custom one 
    def __init__(self,x = 1,y = 1,z = 1,w = 1): 

     self.x = x 
     self.y = y 
     self.z = z 
     self.w = w 

    def wrapper(self): 
     def foo(x = self.x, y = self.y, z = self.z, w = self.w): 
      return x + y + z + w 
     return foo 


c = example(2,2,2,2) 
for i in range(0, 10000000): 
    c.wrapper()(1,2,3,4) 

wrapper2.py

class example(object): 

    # I can create a default class or a custom one 
    def __init__(self,x = 1,y = 1,z = 1,w = 1): 

     self.x = x 
     self.y = y 
     self.z = z 
     self.w = w 

    def wrapper(self): 
     def foo(x = self.x, y = self.y, z = self.z, w = self.w): 
      return x + y + z + w 
     return foo 


c = example(2,2,2,2) 
k = c.wrapper() 
for i in range(0, 10000000): 
    k(1,2,3,4) 

noo1.py

class example(object): 

    # I can create a default class or a custom one 
    def __init__(self,U,x = 1,y = 1,z = 1,w = 1): 

     self.x = x 
     self.y = y 
     self.z = z 
     self.w = w 

     def noo(x = self.x, y = self.y, z = self.z, w = self.w): 
      return x + y + z + w 

     self.noo = noo 

c = example(2,2,2,2) 
for i in range(0, 10000000): 
    c.noo(1,2,3,4) 

noo2.py

class example(object): 

    # I can create a default class or a custom one 
    def __init__(self,x = 1,y = 1,z = 1,w = 1): 

     self.x = x 
     self.y = y 
     self.z = z 
     self.w = w 

    def __call__(self): 
     def noo(x = self.x, y = self.y, z = self.z, w = self.w): 
      return x + y + z + w 

     self.noo = noo 


c = example(2,2,2,2) 
c() 
for i in range(0, 10000000): 
    c.noo(1,2,3,4) 

Lors du test de ces codes, je compris la fonction prep dans tous, juste pour être shure ils avaient la même structure de base, et donc la différence de temps seraient des boucles.