2012-07-22 35 views
14

tôi là một chút tò mò nếu tôi có thể làm nhiều việc hơn trong một chức năng sau khi trở về một kết quả. Về cơ bản tôi đang làm một trang web bằng cách sử dụng khung kim tự tháp (mà chỉ đơn giản là mã hóa trong python) sau khi tôi xử lý các yếu tố đầu tôi trở biến để làm cho trang nhưng đôi khi tôi muốn làm việc nhiều hơn sau khi tôi làm cho trang.Có cách nào để thực hiện nhiều công việc hơn sau tuyên bố trả lại không?

Ví dụ, bạn đến trang web của tôi và cập nhật hồ sơ của bạn và tất cả các bạn quan tâm là thành công vì vậy tôi sản lượng của nó một thông báo nói 'thành công!' nhưng sau đó làm tôi muốn đưa cập nhật của bạn và cập nhật các bản ghi hoạt động của tôi về những gì bạn làm, cập nhật dòng hoạt động bạn bè, vv .. Ngay bây giờ tôi đang làm tất cả những gì trước khi tôi trở về trạng thái kết quả mà bạn quan tâm nhưng tôi m tò mò nếu tôi có thể làm điều đó sau khi người dùng nhận phản hồi của họ nhanh hơn.

Tôi đã thực hiện đa xử lý trước và xấu nhất trường hợp tôi có thể chỉ cần ngã ba một thread để làm công việc này, nhưng nếu có một cách để làm việc sau khi một tuyên bố trở lại sau đó sẽ được đơn giản.

dụ:

def profile_update(inputs): 
    #take updates and update the database 
    return "it worked" 
    #do maintainence processing now.. 
+1

Tôi không quen với luồng của python, nhưng hầu hết trong các mô hình luồng, bắt đầu một chuỗi chỉ đơn giản là gọi một hàm. Sự phức tạp xuất phát từ việc đảm bảo công việc được thực hiện trong luồng được đồng bộ hóa phù hợp với những thứ đang diễn ra không đồng bộ với chuỗi. Dường như với tôi rằng sự phức tạp sẽ tồn tại ở mức độ tương tự với bất cứ điều gì bạn có thể muốn xảy ra trong bước xử lý '#do maintainence processing now..' sau khi trả về. Nếu không cần đồng bộ hóa ở đó, thì không cần đồng bộ trong một chuỗi. Nhưng, trò chuyện cũng đúng. –

Trả lời

9

Không, không may, một khi bạn nhấn tuyên bố return, bạn trở về từ chức năng/phương pháp (có hoặc không có giá trị trả về).

Từ docs for return:

trở lại rời khỏi cuộc gọi chức năng hiện tại với danh sách biểu thức (hoặc Không) là giá trị trả về.

Bạn có thể muốn xem xét chức năng máy phát điện và báo cáo kết quả yield, đây là một cách để trả về một giá trị từ một chức năng và tiếp tục xử lý và chuẩn bị giá trị khác để được trả lại khi hàm được gọi lần sau .

+0

thú vị, không nghĩ về lợi nhuận .. Tôi nghĩ rằng nó đã được sử dụng để trả về một giá trị cho chức năng gọi nó không phải là một phản ứng. Về cơ bản tôi trả về một câu trả lời http dưới dạng một từ điển. Tôi không thể thay đổi cách HTTPS chấp nhận trả lại nhưng tôi sẽ thực hiện một số việc đào bới và xem liệu tôi có thể thay thế lệnh của mình bằng năng suất hay không. Ý tưởng thú vị, cảm ơn. – Lostsoul

+0

Tôi không nghĩ rằng sản lượng sẽ giúp ích ở đây. Một hàm sử dụng lợi nhuận tạo ra một dãy các giá trị khi chúng được yêu cầu bởi phép lặp qua kết quả của cuộc gọi. Người gọi sẽ phải được sửa đổi để mong đợi một chuỗi từ hàm, để xử lý mục đầu tiên dưới dạng phản hồi và sau đó yêu cầu nhiều giá trị hơn để cho phép mã sau khi sản lượng đầu tiên chạy. – Ben

+0

@Ben Nhưng rõ ràng người gọi phải cho biết khi nào công cụ bảo trì sẽ được chạy, bởi vì nếu mọi thời gian tốt, chúng tôi chỉ có thể chạy nó trước khi trở về. Mà trong lợi nhuận có nghĩa là chúng ta cần hai cuộc gọi dù sao đi nữa và đó chỉ là những gì coroutine cần. – Voo

13

Tại sao bạn không sử dụng một contextmanager? Về cơ bản nó thực hiện chính xác những gì bạn muốn.

Dưới đây là ví dụ kinh điển từ các tài liệu Python.

from contextlib import contextmanager 

@contextmanager 
def tag(name): 
    print "<%s>" % name 
    yield 
    print "</%s>" % name 

Vì vậy, đối với chức năng của mình, bạn chỉ muốn làm:

@contextmanager 
def profile_update(inputs): 
    #take updates and update the database 
    yield "it worked" 
    #do maintainence processing now.. 

Và để gọi nó, bạn chỉ muốn làm:

with profile_update(inputs) as result: #pre-yield and yield here 
    # do whatever while in scope 
# as you move out of scope of with statement, post-yield is executed 

EDIT: Tôi chỉ kiểm tra điều ra, và nó chỉ ra rằng, với một tuyên bố lợi nhuận, chức năng vẫn thực hiện đến cùng. Đây là một ví dụ câm minh họa điểm và khi mọi thứ được thực hiện.

def some_generator(lst): 
    for elem in lst: 
     yield elem 
    lst[0] = "I WAS CHANGED POST-YIELD!!!!" 

>>> q = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> gen = some_generator(q) 
>>> for e in gen: 
... print e, q 

0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
3 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
5 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
6 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
7 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
8 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
9 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

print q 
['I WAS CHANGED POST YIELD!!!', 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Một contextmanager có lợi thế là không đòi hỏi hai next cuộc gọi để có được lặp dừng (và cú pháp sạch hơn), nhưng nếu bạn muốn trả về nhiều giá trị hoặc một cái gì đó, bạn cũng có thể làm theo cách này, nhưng bạn có thể thấy rằng các tuyên bố sau năng suất không thực sự được gọi đến khi máy phát điện tăng StopIteration trên next cuộc gọi (cho vòng lặp kết thúc khi nó được StopIteration)


Nếu vì một lý do nào, bạn cần một mức độ cao hơn kiểm soát hơn @contextmanager phiếu mua hàng, bạn có thể o xác định một lớp học với __enter____exit__ phương pháp:

class MyContextClass(object): 
    # ... 

    def __enter__(self): 
     # do some preprocessing 
     return some_object 

    def __exit__(self, exc_type, exc_value, traceback): 
     # do some post processing 
     # possibly do some processing of exceptions raised within the block 
     if exc_type == MyCustomErrorType: 
      return True #don't propagate the error 
+0

@JoelCornett, chỉnh sửa tốt ở đó. đó là một điểm tốt mà '@ contextmanager' chỉ là cú pháp đường cho một lớp phức tạp hơn. –

+0

Tôi nghĩ 'q' phải là' [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 'không' [0, 1, 2, 3, 4] 'trong ví dụ của bạn –

+0

@ AlexandrPriymak vâng, tôi đã thay đổi nó khi chạy trên máy tính của mình, tôi sẽ sửa nó. –

6

Bạn vẫn có thể làm một số công việc sau khi trở về nếu bạn trở về từ một thử khối, các cuối cùng-block sẽ vẫn được thực thi, ví dụ:

def fun(): 
    try: 
     return 
    finally: 
     print "Yay! I still got executed, even though my function has already returned!" 

Trích dẫn the docs:

Khi trở lại chuyển điều khiển ra khỏi một câu lệnh try với cuối cùngMệnh đề, mệnh đề cuối cùng được thực thi trước khi thực sự rời khỏi hàm .

+5

Nhưng cuối cùng vẫn sẽ chạy * trước * người gọi nhận được giá trị trả về. Điều này không giúp bạn cho phép người gọi nhận được phản hồi và thông báo cho người dùng, nhưng * sau đó * chạy nhiều mã hơn. – Ben

+2

Tùy thuộc vào trường hợp sử dụng, điều đó có thể tốt. Nó có thể là một kỹ thuật điều khiển luồng thuận tiện để bọc các nội dung của hàm của bạn, và có một loạt các câu lệnh trả về khác nhau, tất cả đều thả luồng trực tiếp đến khối cuối cùng để thực hiện bảo trì. – andyortlieb

3

Không, lợi tức trả lại giá trị cho người gọi và dừng lại.

Nếu người gọi (s) cũng đang trong tầm kiểm soát của bạn (không nằm trong khuôn khổ kim tự tháp), bạn có thể thay đổi profile_updates để trông giống như sau:

def profile_update(inputs): 
    #take updates and update the database 
    def post_processing_task(): 
     #do maintainence processing now.. 
    return ("it worked", post_processing_task) 

Và sau đó mã người gọi để mong đợi một cặp của (response, task), thay vì chỉ là một phản hồi. Nó có thể làm điều gì đó ngay lập tức với phần response (truyền đạt nó cho người dùng), sau đó gọi task() để xử lý hậu xử lý.

Điều này cho phép profile_update xác định mã nào cần được thực thi sau đó (và giữ các chi tiết đó ẩn và đóng gói từ cấp cao hơn), nhưng cho phép cấp cao hơn xác định luồng giao tiếp phản hồi cho người dùng và sau đó thực hiện sau xử lý trong nền.

+0

+1 Ý tưởng tuyệt vời, tôi sẽ làm một số thử nghiệm nhưng rất thú vị cách suy nghĩ về vấn đề này! – Lostsoul

+0

Huh. Tôi không biết Python có thể làm được điều này. Cám ơn sự tử tế của anh! –

-1

Có thể gian lận với cấu trúc try-except-finally. Ví dụ:

def function(): 
    try: 
    #do some stuff here 
    return x 
    except Exception: 
    #do something when an error occures 
    finally: 
    #do here whatever you wanna do after return 

Lưu ý rằng tuyên bố finally sẽ được thực hiện ngay cả khi ngoại lệ bị bắt.

3
import threading 

def profile_update(inputs): 

    # call function to take updates and update the database 
    update_function(inputs) 

    # call the maintainence_function here 
    t = threading.Thread(target=maintainence_function, args=[input1, input2]) 
    # setDaemon=False to stop the thread after complete 
    t.setDaemon(False) 
    # starting the thread 
    t.start() 

    # return response/anything-else you want to return 
    return "it worked" 



def update_function(inputs): 
    # updating the database process here 

def maintainence_function(input1, input2): 
    #do maintainence processing now.. 

Ở đây chúng tôi sử dụng chức năng luồng của python.

Đầu tiên chúng tôi gọi hàm cập nhật (bạn cũng có thể sử dụng hàm này trong chuỗi nếu cần và nếu phản hồi không phụ thuộc vào hàm này và nếu bạn cần trả lời ngay).

Sau đó, chúng tôi đã tạo một chuỗi sẽ hoàn thành chức năng maintainence_function và dừng sau khi hoàn thành. Nhưng phản ứng sẽ không bị trì hoãn cho đến khi chức năng đó kết thúc.

tức là: trả về "nó hoạt động" sẽ được trả lại và sau đó cũng là chủ đề duy trì hoạt động của hàm maintainence_function nếu ts một quá trình bit.

Các vấn đề liên quan