2009-08-05 34 views
5

Với chức năngintrospecting lồng chức năng một chức năng nhất định của (địa phương) trong Python

def f(): 
    x, y = 1, 2 
    def get(): 
     print 'get' 
    def post(): 
     print 'post' 

là có cách nào cho tôi để truy cập get nó địa phương() và sau() chức năng trong một cách mà tôi có thể gọi cho họ ? Tôi đang tìm kiếm một chức năng mà sẽ làm việc như vậy với hàm f() định nghĩa ở trên:

>>> get, post = get_local_functions(f) 
>>> get() 
'get' 

tôi có thể truy cập vào mã đối tượng cho những chức năng địa phương như vậy

import inspect 
for c in f.func_code.co_consts: 
    if inspect.iscode(c): 
     print c.co_name, c 

mà kết quả trong

get <code object get at 0x26e78 ...> 
post <code object post at 0x269f8 ...> 

nhưng tôi không thể tìm ra cách để có được các đối tượng chức năng thực sự có thể gọi. Điều đó thậm chí có thể?

Cảm ơn sự giúp đỡ của bạn,

Will.

+0

Tôi nên lưu ý rằng đối với trường hợp sử dụng thực tế của tôi, tôi cần có khả năng gọi các hàm cục bộ/lồng nhau như sau: get (request, * args, ** kwargs) –

Trả lời

4

Bạn đang khá thân thiết của làm điều đó - chỉ thiếu new mô-đun:

import inspect 
import new 

def f(): 
    x, y = 1, 2 
    def get(): 
     print 'get' 
    def post(): 
     print 'post' 

for c in f.func_code.co_consts: 
    if inspect.iscode(c): 
     f = new.function(c, globals()) 
     print f # Here you have your function :]. 

Nhưng tại sao các heck bận tâm? Việc sử dụng lớp học có dễ hơn không? Instantiation trông giống như một cuộc gọi hàm.

+0

Đó là thủ thuật, miễn là các chức năng lồng nhau không phải là đóng cửa. Cảm ơn! Bạn và Kiến Aasma là đúng, tuy nhiên, tôi chỉ nên sử dụng một lớp học cho việc này. Lý do mà tôi không phải là đây là dự án Django đã có rất nhiều trang trí xem được sử dụng để xác thực tùy chỉnh, v.v. và tôi không muốn điều chỉnh tất cả các trang trí đó để làm việc với các phương thức. Vì vậy, tôi là loại nửa assed mô phỏng một cách tiếp cận dựa trên lớp học để xem RESTful (như http://github.com/jpwatts/django-restviews/tree/master). –

+0

Tôi tin rằng điều này chỉ hoạt động bởi vì bạn có f trong mô-đun hiện tại. – Quant

2

Bạn có thể trở lại chức năng giống như bất kỳ đối tượng khác bằng Python:

def f(): 
    x, y = 1, 2 
    def get(): 
     print 'get' 
    def post(): 
     print 'post' 
    return (get, post) 


get, post = f() 

Hope this helps!

Lưu ý, mặc dù, nếu bạn muốn sử dụng biến 'x' và 'y' của bạn trong get() hoặc post(), bạn nên đặt chúng làm danh sách.

Nếu bạn làm điều gì đó như thế này:

def f(): 
    x = [1] 
    def get(): 
     print 'get', x[0] 
     x[0] -= 1 
    def post(): 
     print 'post', x[0] 
     x[0] += 1 
    return (get, post) 

get1, post1 = f() 
get2, post2 = f() 

get1 và post1 sẽ tham khảo một 'x' danh sách khác với get2 và POST2.

+0

Vâng, đó thực sự là những gì tôi đang thực hiện tại thời điểm này. Tôi đã hy vọng tìm ra cách để tránh trả lại các hàm một cách rõ ràng, nếu có thể. –

+3

Sẽ, để báo giá ** Zen của Python **: * "Rõ ràng là tốt hơn là ngầm." * --và-- * "Các trường hợp đặc biệt không đủ đặc biệt để phá vỡ các quy tắc." * –

+0

Điểm tốt, Evan . Các giải pháp mà tôi đã có ngay bây giờ, mà về cơ bản là giống như này, ngoại trừ việc nó đòi hỏi phải trả lại một dict thay vì một tuple, hoạt động tốt. Tôi đã chỉ hy vọng để tránh sự lặp lại của việc đưa trở lại dict (get = get, post = post, put = đặt, vv) ở dưới cùng của một loạt các quan điểm Django. Cảm ơn lời khuyên, mặc dù. –

2

Bạn có thể sử dụng lệnh exec để chạy các đối tượng mã. Ví dụ, nếu bạn đã định nghĩa là f trên, sau đó

exec(f.func_code.co_consts[3]) 

sẽ cung cấp cho

get 

như đầu ra.

+0

Ah, vậy đó là cách bạn thực hiện một đối tượng mã! Thật không may, đối với trường hợp sử dụng thực tế của tôi, tôi cần có khả năng chuyển đối số vào các hàm cục bộ. Có cách nào để tôi làm điều đó khi gọi exec()? –

1

Đối tượng hàm bên trong không tồn tại trước khi hàm f() được thực hiện. Nếu bạn muốn có được chúng, bạn sẽ phải tự xây dựng chúng. Điều đó chắc chắn là không tầm thường bởi vì chúng có thể là các đóng mà nắm bắt các biến từ phạm vi chức năng và sẽ yêu cầu poking xung quanh trong các đối tượng có lẽ nên được coi là chi tiết thực hiện của thông dịch viên.

Nếu bạn muốn thu thập các chức năng với ít sự lặp lại tôi khuyên bạn nên một trong những phương pháp sau đây:

a) Chỉ cần đặt các chức năng trong một định nghĩa lớp và trả về một tham chiếu đến lớp đó. Một tập hợp các hàm liên quan được truy cập bằng tên có mùi rất lớn như một lớp.

b) Tạo lớp con dict có phương thức đăng ký chức năng và sử dụng phương thức đó làm trang trí.

Mã này sẽ giống như thế này:

class FunctionCollector(dict): 
    def register(self, func): 
     self[func.__name__] = func 

def f(): 
    funcs = FunctionCollector() 
    @funcs.register 
    def get(): 
     return 'get' 
    @funcs.register 
    def put(): 
     return 'put' 
    return funcs 

c) Poke xung quanh trong người dân địa phương() và lọc ra các chức năng với inspect.isfunction. (Thường không phải là một ý tưởng tốt)

+0

Re: "a) Chỉ cần đặt các hàm trong một định nghĩa lớp và trả về một tham chiếu đến lớp đó. Một tập hợp các hàm liên quan được truy cập bằng tên mùi thật khủng khiếp như một lớp.", Bạn chắc chắn đúng. Xem bình luận của tôi về câu trả lời của gavoja dưới đây cho một lời giải thích cho lý do tại sao tôi không sử dụng một lớp trong trường hợp này. Cảm ơn bạn đã giải thích, mặc dù! –

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