2009-07-26 11 views
11

Nie jestem do końca pewien, co mam na myśli, więc proszę o zachowanie mnie ..Przekazywanie wyrażeń do funkcji w Pythonie?

W sqlalchemy, wygląda na to, że mam przekazać wyrażenie? do filter() w niektórych przypadkach. Kiedy próbuję zaimplementować coś jak to ja, ja skończyć z:

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

>>> someFunc(5 == 5) 
True 

Jak uzyskać wartości przekazywane do == od wewnątrz funkcji?

Edycja: Próbuję osiągnąć coś takiego

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

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

Edit: A co, jeśli jeden z paramaters było przedmiotem?

+0

Kontynuacja pytanie o ORMs: http://stackoverflow.com/questions/1185537 –

Odpowiedz

21

można osiągnąć swój przykład, jeśli uczynić „op” funkcja:

 
    >>> 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 

To więcej pythonowy niż przepuszczenie Strunowy. Tak działają funkcje takie jak sort().

Te przykłady SQLAlchemy z filtrem() są zagadkowe. Nie znam elementów wewnętrznych dotyczących SQLAlchemy, ale domyślam się, że w przykładzie takim jak query.filter (User.name == 'ed'), co się dzieje, jest to, że User.name jest typem specyficznym dla SQLAlchemy, z nieparzystym implementacja funkcji __eq(), która generuje SQL dla funkcji filter() zamiast wykonywania porównania. Tzn. Stworzyli specjalne klasy, które pozwalają na wpisywanie wyrażeń języka Python, które emitują kod SQL. To niezwykła technika, której uniknęłabym, gdyby nie zbudować czegoś, co łączy dwa języki, takie jak ORM.

+0

Należy pamiętać, że nie ma potrzeby nadawania nawiasie lambda. –

+3

To prawda, ale umieszczenie tego w nawiasie ułatwia czytanie w tym przypadku ze względu na wewnętrzne parametry lambda. –

+0

Jeśli chcesz - to dla mnie zbyteczne parens. –

1

Nie możesz. Wyrażenie 5 == 5 jest obliczane i tylko wtedy wynik jest przekazywany do someFunc. Funkcja właśnie dostaje True (obiekt True), bez względu na to, jakie było wyrażenie.

Edycja: jeśli chodzi o edycję, this question jest blisko.

Edit 2: Można po prostu przekazać wyrażenie jako ciąg i użyć eval, podobnie jak to:

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

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

Nie wiem, czy to pomaga. Należy pamiętać, że eval to potężne narzędzie, więc niebezpiecznie jest przekazywać do niego dowolne dane wejściowe (a nawet generowane przez użytkowników).

0

Musisz zawinąć całość jako ciąg literowy. Próbujesz wydrukować to jako ciąg, który zakładam, prawda?

0

Krótka odpowiedź: Nie możesz. Wynik oceny wyrażenia jest przekazywany do funkcji, a nie samego wyrażenia.

1

Wydaje można powrócić krotki z 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

Możesz zwrócić wszystko, co chcesz, z '__eq__', ale zwracając coś, czego nie można zmusić do boolu, aby porównać równość - cel' __eq__' - jest naprawdę złym pomysłem. –

+0

To chyba zła praktyka, ale i tak jest to pytanie teoretyczne. Więcej o "Jak to możliwe?" wpisz rzecz. –

+0

SQLalchemy naprawdę robi coś takiego? To jedna biblioteka, której nie dotknę stalowy słup o długości 20 stóp. To wstrętny, odrażający hack. (Nie atakujesz cię - wyjaśniasz tylko, jak mogli to zrobić.) –

5

Jeszcze bardziej pytonowym wariantem rozwiązania Nelsona jest użycie funkcji operatora z modułu operator w standardowej bibliotece; nie ma potrzeby tworzenia własnych lambd.

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

Musisz wdrożyć __eq__(). Na przykład ::

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

Następnie dla funkcji, które chcesz uzyskać ekspresję, jak ::

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

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