2009-08-10 40 views
9

Dưới đây là một số mã từ Richard Jones' Blog:Chức năng tìm Defined trong một với: Lô

with gui.vertical: 
    text = gui.label('hello!') 
    items = gui.selection(['one', 'two', 'three']) 
    with gui.button('click me!'): 
     def on_click(): 
      text.value = items.value 
      text.foreground = red 

Câu hỏi của tôi là: làm thế nào heck anh ấy làm điều này? Trình quản lý ngữ cảnh có thể truy cập vào phạm vi bên trong khối bằng cách nào? Dưới đây là một mẫu cơ bản cho cố gắng để con số này ra:

Trả lời

11

Dưới đây là một cách:

from __future__ import with_statement 
import inspect 

class button(object): 
    def __enter__(self): 
    # keep track of all that's already defined BEFORE the `with` 
    f = inspect.currentframe(1) 
    self.mustignore = dict(f.f_locals) 

    def __exit__(self, exc_type, exc_value, traceback): 
    f = inspect.currentframe(1) 
    # see what's been bound anew in the body of the `with` 
    interesting = dict() 
    for n in f.f_locals: 
     newf = f.f_locals[n] 
     if n not in self.mustignore: 
     interesting[n] = newf 
     continue 
     anf = self.mustignore[n] 
     if id(newf) != id(anf): 
     interesting[n] = newf 
    if interesting: 
     print 'interesting new things: %s' % ', '.join(sorted(interesting)) 
     for n, v in interesting.items(): 
     if isinstance(v, type(lambda:None)): 
      print 'function %r' % n 
      print v() 
    else: 
     print 'nothing interesting' 

def main(): 
    for i in (1, 2): 
    def ignorebefore(): 
     pass 
    with button(): 
     def testing(i=i): 
     return i 
    def ignoreafter(): 
     pass 

main() 

Sửa: kéo dài nhiều mã một chút, bổ sung một số giải thích ...:

Bắt người dân địa phương của người gọi theo số __exit__ thật dễ dàng - phức tạp hơn là tránh những người dân địa phương đã được xác định trước khi khối with, đó là lý do tôi thêm vào chính hai các hàm cục bộ mà with sẽ bỏ qua. Tôi không hài lòng 100% với giải pháp này, có vẻ hơi phức tạp, nhưng tôi không thể kiểm tra bình đẳng đúng với == hoặc is, vì vậy tôi đã sử dụng phương pháp này khá phức tạp.

Tôi cũng đã thêm vòng lặp (để đảm bảo chắc chắn hơn def s trước/trong/sau đang được xử lý đúng) và kiểm tra loại và chức năng gọi để đảm bảo hóa thân đúng là testing là được xác định (mọi thứ dường như hoạt động tốt) - tất nhiên mã được viết chỉ hoạt động nếu def bên trong with là dành cho một hàm có thể gọi mà không có đối số, không khó để có được chữ ký với inspect để chống lại điều đó (nhưng vì tôi đang thực hiện cuộc gọi chỉ với mục đích kiểm tra rằng các đối tượng hàm đúng được xác định, tôi không bận tâm về lần tinh lọc cuối cùng này ;-).

+0

Đáng yêu, cảm ơn bạn rất nhiều. – llimllib

+1

Bạn được chào đón! là một vấn đề thú vị để giải quyết, do đó, tx cho đặt ra nó ;-). –

+1

Tôi đã đăng một mục blog về việc sử dụng mã mà bạn đã cung cấp cho tôi, trong trường hợp bạn quan tâm: http://billmill.org/multi_line_lambdas.html – llimllib

1

Để trả lời câu hỏi của bạn, có, đó là khung nhìn.

Nhưng cú pháp tôi sẽ tạo ra để làm điều tương tự là

with gui.vertical: 
    text = gui.label('hello!') 
    items = gui.selection(['one', 'two', 'three']) 
    @gui.button('click me!') 
    class button: 
     def on_click(): 
      text.value = items.value 
      text.foreground = red 

Ở đây tôi sẽ thực hiện gui.button như một trang trí trả về nút dụ đưa ra một số thông số và sự kiện (mặc dù nó xuất hiện với tôi bây giờ mà button = gui.button('click me!', mybutton_onclick là cũng được.)

Tôi cũng sẽ để lại gui.vertical vì nó có thể được triển khai mà không có sự quan tâm. Tôi không chắc về triển khai của nó, nhưng nó có thể liên quan đến việc thiết lập gui.direction = gui.VERTICAL sao cho gui.label() và những người khác sử dụng nó để tính toán tọa độ của chúng.

Bây giờ khi tôi nhìn vào điều này, tôi nghĩ rằng tôi muốn thử cú pháp:

with gui.vertical: 
     text = gui.label('hello!') 
     items = gui.selection(['one', 'two', 'three']) 

     @gui.button('click me!') 
     def button(): 
      text.value = items.value 
      foreground = red 

(ý tưởng được rằng tương tự như cách nhãn được làm bằng văn bản, một nút được làm bằng văn bản và chức năng)

+0

nhưng sau đó tại sao lại sử dụng "với gui.vertical"? Nó sẽ cần phải làm cùng một chồng nội tâm để có được quyền truy cập vào văn bản, các mục và nút bên trong nó.Tôi chắc chắn bạn làm điều gì đó như: lớp MyLayout (gui.Vertical): văn bản = gui.label ('hello!') #etc phải không? Dù sao thì, tôi nhận thức rõ rằng đây là hành vi lạm dụng nghiêm trọng không chuẩn của khối. Tôi chỉ muốn biết anh ấy đã làm thế nào. Tôi hy vọng bạn ít nhất thấy rằng đó là một sự lạm dụng mát mẻ với khối :) – llimllib

+0

Tôi đọc 'với gui.vertical' là" tạo không có phần tử, nhưng đảm bảo tất cả các yếu tố được tạo trong ngữ cảnh này tính toán tọa độ theo chiều dọc từ hiện tại điểm". Không có nội tâm. –

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