2012-01-21 15 views
12

Tôi có một mô-đun có chứa nhiều hàm (hơn 25). Tôi muốn thêm một chức năng trang trí chung cho mỗi chức năng này. Cách thông thường để làm là thêm dòng @decorator vào trên mỗi hàm, nhưng tôi đã tự hỏi liệu có cách nào tốt hơn để làm điều đó không? Có lẽ tôi có thể tuyên bố một trang trí toàn cầu ở đầu mô-đun hoặc cái gì khác?Xác định trình trang trí cho một mô-đun hoàn chỉnh

Lưu ý rằng vì tôi đang sử dụng mã của người khác, tôi muốn giảm thiểu số lượng dòng thay đổi, vì vậy việc sửa đổi mô-đun không phải là lý tưởng đối với tôi.

Cảm ơn.

Trả lời

12

Nếu trang trí của bạn được gọi my_decorator

### Decorate all the above functions 
import types 
for k,v in globals().items(): 
    if isinstance(v, types.FunctionType): 
     globals()[k] = my_decorator(v) 

Bạn cũng có thể áp dụng điều này để các module sau khi nhập nó

import othermodule 
import types 
for k,v in vars(othermodule).items(): 
    if isinstance(v, types.FunctionType): 
     vars(othermodule)[k] = my_decorator(v) 
+0

Điều này là hoàn toàn an toàn - và tôi thực sự sử dụng những thứ như thế này trong một dự án thực sự. – jsbueno

+0

Cảm ơn bạn đã trả lời! Điều này làm việc cho tôi, nhưng có một vấn đề nhỏ mà nó cũng bổ sung thêm các chức năng mà tôi đã nhập (như "từ bản sao nhập sâu") ... có cách tôi có thể bỏ qua các chức năng này và chỉ thêm các chức năng mà tôi bản thân tôi được xác định ở cấp cao nhất trong mô-đun? ... cảm ơn! – Rajat

+0

thay thế "vars (othermodule) [k] = my_decorator (v)" với "setattr (othermodule, k, my_decorator (v))" để tránh có thể "'dictproxy' đối tượng không hỗ trợ phân công mục" – user2426679

7

Tôi nghĩ rằng áp dụng một trang trí en-masse như vậy mà nó không rõ ràng nơi bạn sẽ tìm kiếm để tìm hiểu về chức năng (theo định nghĩa của nó) thường là một ý tưởng tồi. Rõ ràng là tốt hơn so với tiềm ẩn, và tất cả những điều đó.

Nếu bạn muốn áp dụng trang trí vào các chức năng một số mô-đun bên thứ ba, mà không sửa đổi mã của bên thứ ba, ở đây là làm thế nào tôi sẽ làm điều đó:

# my_wrapper_module.py 

import some_module 
import functools 

def some_decorator(func): 
    @functools.wraps(func): 
    def wrapper(*args, **kwargs): 
     ... 
    return wrapper 

FUNCTION_NAMES = [ 
    'some_func_1', 
    'some_func_2', 
    'some_func_3', 
    ... 
] 

for name in FUNCTION_NAMES: 
    globals()[name] = some_decorator(getattr(some_module, name)) 

Và sau đó sử dụng các chức năng khác bằng cách làm from my_wrapper_module import some_func_2 vv

Đối với tôi, điều này có những ưu điểm sau:

  1. Không cần phải sửa đổi các tập tin nguồn của bên thứ ba
  2. Rõ ràng từ trang gọi mà tôi nên xem my_wrapper_module để xem những gì tôi đang gọi và tôi không sử dụng các phiên bản chưa được đặt trước của các chức năng
  3. Rõ ràng là từ my_wrapper_module chức năng nào đang được xuất , ban đầu chúng xuất phát từ some_module và tất cả chúng đều có cùng trang trí được áp dụng
  4. Bất kỳ mã nào nhập some_module trực tiếp không bị âm thầm và không thể giải thích được; điều này có thể đặc biệt quan trọng nếu mã của bên thứ ba là nhiều hơn một mô-đun

Nhưng nếu những gì bạn đang cố gắng làm là hack một thư viện của bên thứ ba để các cuộc gọi nội được bị ảnh hưởng, thì đây là không phải những gì bạn muốn.

+0

Giống như ý tưởng tạo 'wrapper_module'.Nhân tiện, tôi đã xóa câu trả lời của mình (vì @ gnibbler's hoàn chỉnh hơn và có cheking chính xác cho kiểu hàm). – reclosedev

+0

Cảm ơn câu trả lời. Tôi đã làm như sau – Rajat

+0

@reclosedev Chúc mừng, tôi đã xóa tham chiếu đến câu trả lời của bạn ngay bây giờ. – Ben

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