2012-06-22 13 views
11

Mam metodę że mam uszkodzony na mniejsze funkcji zagnieżdżonych rozbić bazę kodu:połączeń Zagnieżdżone funkcji w Pythonie

def foo(x,y): 
    def do_this(x,y): 
     pass 
    def do_that(x,y): 
     pass 
    do_this(x,y) 
    do_that(x,y) 
    return 

Czy istnieje sposób, aby uruchomić jeden z zagnieżdżonych funkcji przez siebie. np:

foo.do_this(x,y) 

EDIT:

Próbuję buforowania konfiguracji na serwerze WWW I zostały zbudowane przy użyciu pyramid_breaker

def getThis(request): 
    def invalidate_data(getData,'long_term',search_term): 
     region_invalidate(getData,'long_term',search_term) 
    @cached_region('long_term') 
    def getData(search_term): 
     return response 
    search_term = request.matchdict['searchterm'] 
    return getData(search_term) 

To jest moje zrozumienie może nie być dokładne:

Powodem, dla którego mam to, jest to, że przestrzeń nazw używana przez dekorator do tworzenia klucza pamięci podręcznej jest generowana z funkcji i argumenty. Nie można zatem po prostu wstawić dekoratora getThis, ponieważ zmienna żądania jest unikalna, a pamięć podręczna jest bezużyteczna. Stworzyłem więc wewnętrzną funkcję, która ma powtarzalne argumenty (search_term).

Aby unieważnić pamięć podręczną (tj. Odświeżyć), funkcja unieważniania wymaga zakresu, aby poznać funkcję "getData", więc musi również zostać zagnieżdżona. Dlatego muszę wywołać funkcję zagnieżdżoną. Wy, wspaniali ludzie, jasno powiedzieliście, że nie jest to możliwe, więc czy ktoś może wyjaśnić, jak mógłbym to zrobić z inną strukturą?

+0

kod 'foo.do_this' spróbuje do_this dostępowych jako FUNCT członkiem jon 'foo', który da ci błąd atrybutu, zamiast tego uczyń foo jako klasą – avasal

+0

" zlikwiduj podstawę kodu ", to dla której przestrzeni nazw modułu są dobre. Jeśli naprawdę chcesz * enkapsulować * funkcje 'do_', wówczas użyj klasy jako @lazyr shows. – msw

+0

Funkcje zagnieżdżone nie są sposobem konstruowania kodu w Pythonie (nie są też klasami). Zobacz [moduły] (http://docs.python.org/tutorial/modules.html). – georg

Odpowiedz

19

Zakładam do_this i do_that to faktycznie zależy od jakiegoś argumentu foo, gdyż w przeciwnym razie można po prostu przenieść je z foo i nazywają je bezpośrednio.

Sugeruję przerobienie całej rzeczy jako lekcji. Coś takiego:

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

    def do_this(self): 
     pass 

    def do_that(self): 
     pass 

    def __call__(self): 
     self.do_this() 
     self.do_that() 

foo = Foo(x, y) 
foo() 
foo.do_this() 
+0

Bardzo pomocna odpowiedź i czuje się jak moja cała struktura może być źle. Może być bardziej pomocny, jeśli wyjaśnię większy obraz, aby zobaczyć, czy możesz pomóc (nie martw się, jeśli jest to zbyt trudne). – user1474424

+2

@ user1474424 Myślę, że powinieneś umieścić to w nowym pytaniu. –

+0

Dokonałem edycji, aby zadać pytanie. Czy lepiej jest utworzyć nowe pytanie, przepraszam, przepraszam, że przepełnienie stosu – user1474424

3

Nie, nie ma. Ponieważ może uzyskać dostęp do zmiennych w zakresie zewnętrznej od wewnątrz zagnieżdżonej funkcji:

def foo(x,y): 
    def do_this(z): 
     print(x,y,z) 
    # ... 

nie ma sposobu, aby wywołać do_this zapewniając jednocześnie wiążący dla x i y.

Jeśli musisz zadzwonić pod numer do_this z innego miejsca, po prostu ustaw go jako funkcję najwyższego poziomu na tym samym poziomie co foo.

2

Nie (oprócz wywiercenie w obiektach zamknięcia, który jest kompletna przesada tutaj). Jeśli potrzebujesz tego, użyj klasy.

class foo(object): 
    def do_this(self, x, y): 
     ... 
    def do_that(self, x, y): 
     ... 
    def do_other_stuff(self, x, y): 
     # or __call__, possibly 

lub po prostu umieścić te funkcje w zakresie zewnętrznym, ponieważ jesteś przejazdem wszystko jako argumenty i tak:

def foo(x, y): 
    do_this(x, y) 
    do_that(x, y) 

def do_this(x, y): 
    ... 

def do_that(x, y): 
    ... 
1

Jest, trzeba dokonać ich jako atrybut obiektu funkcyjnego. Ale zadziała to dopiero po pierwszym wywołaniu foo.

def foo(x,y): 
    def do_this(x,y): 
     pass 
    def do_that(x,y): 
     pass 
    do_this(x,y) 
    do_that(x,y) 
    foo.do_this = do_this 
    foo.do_that = do_that 
    return 

>>> foo.do_this(1, 2) 
AttributeError: 'function' object has no attribute 'do_this' 
>>> foo(1, 2) 
>>> foo.do_this(1, 2) 
>>> 
7

Te poprzednie odpowiedzi, które mówią, że nie możesz tego zrobić, są oczywiście błędne. To jest python, możesz zrobić prawie wszystko, co chcesz, używając magii magicznego kodu.

Możemy pobrać pierwszą stałą z kodu funkcji foo, będzie to funkcja do_this. Następnie możemy użyć tego kodu, aby utworzyć z nim nową funkcję.

zobacz https://docs.python.org/2/library/new.html, aby uzyskać więcej informacji na temat nowych i https://docs.python.org/2/library/inspect.html, aby uzyskać więcej informacji na temat uzyskiwania kodu wewnętrznego.

Uwaga: to nie dlatego, że można to zrobić, że należy to zrobić, przemyślenia sposób masz funkcje skonstruowany jest do zrobienia, ale jeśli chcesz mieć szybki i zabrudzony hack, który prawdopodobnie będzie przerwa w przyszłość, tutaj przejść:

import new 
myfoo = new.function(foo.func_code.co_consts[1],{}) 
myfoo(x,y) # hooray we have a new function that does what I want 

UPDATE: w python3 można użyć modułu typy z foo.__code__:

import types 
myfoo = types.FunctionType(foo.__code__.co_consts[1], {}) 
myfoo() # behaves like it is do_this() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: do_this() missing 2 required positional arguments: 'x' and 'y' 
+0

W Pythonie 3 mogę używać "typów"? –

+0

@VitalyZdanevich Tak, zgodnie z [documentation] (https://docs.python.org/2/library/new.html): 'Przestarzałe od wersji 2.6: Nowy moduł został usunięty w Pythonie 3. Użyj typów zamiast klas modułów. " – Pedro

+0

To powinna być zaakceptowana odpowiedź – noamt

Powiązane problemy