2009-07-26 6 views
11

Je ne suis pas sûr de ce que je veux dire ici, alors s'il vous plaît ours avec moi ..Passer des expressions aux fonctions en python?

En sqlalchemy, il semble que je suis censé passer une expression? à filter() dans certains cas. Lorsque je tente de mettre en œuvre quelque chose de moi-même comme ça, je me retrouve avec:

>>> def someFunc(value): 
... print(value) 

>>> someFunc(5 == 5) 
True 

Comment obtenez-i les valeurs transmises à == à l'intérieur de la fonction?

Edit: Je suis en train de réaliser quelque chose comme ça

>>> def magic(left, op, right): 
... print(left+" "+op+" "+right) 

>>> magic(5 == 5) 
5 == 5 

Edit: Qu'en est-il si l'un des paramaters était un objet?

+0

Suivi question sur les ORM: http://stackoverflow.com/questions/1185537 –

Répondre

21

Vous pouvez réaliser votre exemple si vous faites "op" fonction:

 
    >>> def magic(left, op, right): 
    ...  return op(left, right) 
    ... 
    >>> magic(5, (lambda a, b: a == b), 5) 
    True 
    >>> magic(5, (lambda a, b: a == b), 4) 
    False 

Ceci est plus Pythonic que le passage d'un Chaîne. C'est comme ça que fonctionnent les fonctions sort().

Les exemples SQLAlchemy avec filter() sont déroutants. Je ne connais pas les internes de SQLAlchemy, mais je devine dans un exemple comme query.filter (User.name == 'ed') ce qui se passe est que User.name est un type spécifique à SQLAlchemy, avec un impair Implémentation de la fonction __eq() qui génère SQL pour la fonction filter() au lieu de faire une comparaison. C'est à dire: ils ont créé des classes spéciales qui vous permettent de taper des expressions Python qui émettent du code SQL. C'est une technique inhabituelle, que j'éviterais à moins de construire quelque chose qui relie deux langues comme un ORM.

+0

Notez qu'il n'est pas nécessaire de mettre entre parenthèses lambda. –

+3

Vrai, mais en le mettant entre parenthèses, il est plus facile de lire dans ce cas en raison des paramètres internes du lambda. –

+0

Si vous aimez - c'est juste superflu parens pour moi. –

1

Vous ne pouvez pas. L'expression 5 == 5 est évaluée et seulement alors le résultat est passé à someFunc. La fonction obtient simplement True (l'objet True, pour être précis), quelle que soit l'expression.

Modifier: Concernant votre édition, this question est un peu plus proche.

Edit 2: Vous pouvez tout simplement passer l'expression comme une chaîne et utiliser eval, comme ceci:

>>> def someFunc(expression_string): 
... print(expression_string, "evaluates to", eval(expression_string)) 

>>> someFunc("5 == 5") 
5 == 5 evaluates to True 

Je ne sais pas si cela vous aide. Gardez à l'esprit que eval est un outil puissant, il est donc dangereux de passer une entrée arbitraire (et peut-être même générée par l'utilisateur).

0

Vous devez envelopper le tout dans une chaîne littérale. Vous essayez d'imprimer cela comme une chaîne je suppose, correct?

0

Réponse courte: Vous ne pouvez pas. Le résultat de l'évaluation de l'expression est transmis à la fonction plutôt qu'à l'expression elle-même.

1

Il semble que vous pouvez revenir tuples de eq:

class Foo: 
    def __init__(self, value): 
      self.value = value 

    def __eq__(self, other): 
      return (self.value, other.value) 


f1 = Foo(5) 
f2 = Foo(10) 
print(f1 == f2) 
+2

Vous pouvez renvoyer tout ce que vous voulez de '__eq__', mais retourner quelque chose qui ne peut pas être contraint à un booléen pour comparer l'égalité - le but de' __eq__' - est une très mauvaise idée. –

+0

C'est probablement une mauvaise pratique, mais c'est une question théorique de toute façon. Plus d'un "Comment est-ce possible?" type chose. –

+0

SQLalchemy fait vraiment quelque chose comme ça? C'est une bibliothèque que je ne toucherai pas avec un poteau en acier de 20 pieds. C'est un hack grossier et dégoûtant. (Ne vous attaquant pas - vous expliquez simplement comment ils ont pu le faire.) –

5

Une variante encore plus pythonique de la solution de Nelson consiste à utiliser les fonctions d'opérateur du module operator dans la bibliothèque standard; il n'y a pas besoin de créer vos propres lambdas.

>>> from operator import eq 
>>> def magic(left, op, right): 
... return op(left, right) 
... 
>>> magic(5, eq, 5) 
True 
1

Vous devez implémenter __eq__(). Par exemple ::

class A(object): 
    def __eq__(self, other): 
     return (self, '==', other) 

Ensuite, pour la fonction, que vous voulez obtenir l'expression, comme ::

def my_func(expr): 
    # deal with the expression 
    print(expr) 

>>> a = A() 
>>> my_func(a == 1) 
(<__main__.A object at 0x1015eb978>, '==', 1) 
Questions connexes