2013-10-22 15 views
5

Có thể áp dụng mã từ mô-đun đã nhập vào mô-đun nhập vào không? Ví dụ, tôi có gỡ lỗi module, nơi được xác định một số trang trí để gỡ lỗi, ví dụ:Nhạy cảm với Python

def debug_func(f): 
    def wrapper(*func_args, **func_kwargs): 
     print(f(*func_args, **func_kwargs)) 
    return wrapper 

ý tưởng là gì: Nó sẽ có ích nếu tôi có thể chỉ

import Debug 

và tất cả các chức năng từ mô-đun hiện tại sẽ được bọc bằng trang trí. Có thể không?

+1

Bạn cần gọi hàm trong 'Debug' sau khi nhập; 'Debug' có lẽ không thể phản ánh trên mô-đun nhập khẩu trong khi chính nó đang được nhập.IMHO, bạn nên làm 'từ Debug import debug_func' và sau đó sử dụng trang trí' @ debug_func' trên những hàm cần nó. Nó sẽ không quá khó để viết một regexp có thể bình luận hoặc bỏ ghi chú tất cả các trường hợp của '@ debug_func' trong một tập tin. –

+1

Tôi đoán bạn có thể viết một hàm 'decorate_', có chức năng như tham số, xem tất cả các mục' có thể gọi 'trong 'gobals()' và trang trí chúng, hoặc một cái gì đó tương tự. Gọi sau khi nhập. –

Trả lời

3

Trong Debug.py:

import functools 
from types import FunctionType 

def wrap_functions(module_dict): 
    for k, f in module_dict.items(): 
     if not isinstance(f, FunctionType): 
      continue 
     def get_wrapper(f): 
      def wrapper(*func_args, **func_kwargs): 
       print(f(*func_args, **func_kwargs)) 
      return functools.wraps(f)(wrapper) 
     module_dict[k] = get_wrapper(f) 

Tại đáy của module bạn đang có nhu cầu để gỡ lỗi:

import Debug 
Debug.wrap_functions(globals()) 

Cảm ơn (1) cho tất cả các bình luận đã cung cấp gợi ý.

+0

Bạn đã nhận nó ngược. Anh ta muốn 'nhập khẩu Debug' để bọc các chức năng của mô-đun nhập khẩu, không phải chức năng của Debug. –

+1

Thay vì sao chép trình trang trí trong hàm, tại sao bạn không chuyển (các) bộ trang trí để sử dụng làm tham số khác? Ngoài ra, sử dụng tốt hơn 'Debug.wrap_functions (globals())', nếu không 'wrap_function' sẽ tự trang trí. Ngoài ra, +1 –

+1

Tôi đọc câu trả lời ban đầu của bạn, sau đó đi xa để thực hiện một số kiểm tra và quay trở lại để tìm những gì tôi đã lên kế hoạch viết :). –

0

Tôi nghĩ rằng cách pythonic làm việc đó sẽ có gỡ lỗi của bạn gọi các module sửa lỗi, như các công cụ chuẩn (pdb, unittest, ...) với một cuộc gọi như:

$ python -m Debug mymodule.py 

Với bạn Gỡ lỗi nhập/thực hiện mô-đun với bất kỳ trình trang trí nào bạn thích. Làm theo cách khác (nhập Debug) làm rối trật tự mô-đun được đánh giá, vì bạn đang cố gắng có mô-đun Debug tùy thuộc vào mô-đun nhập khẩu, điều này rất khó.

Ngoài đi qua các chức năng của mình một cách rõ ràng (thông qua globals(), một danh sách các chức năng ...) đối với một số Debug.mark_as_debug như Jim Garrison đề nghị, tôi nghĩ rằng nó sẽ có ý nghĩa hơn đối với tổ chức mã của bạn như vậy mà bạn có thể có của bạn Debug gọi của bạn mô-đun thay vì theo cách khác.

+0

Cảm ơn, nhưng tôi đã viết gỡ lỗi làm ví dụ, vấn đề chính - cách tốt nhất để áp dụng mã từ mô-đun đã nhập vào mô-đun sẽ nhập mã đó là gì. – Dmitriy

+0

Tôi nghĩ câu trả lời cho câu hỏi này là: bạn không thể. kindall giải thích nó tốt hơn nhiều so với tôi đã làm, nhưng nguyên tắc rất của mô-đun đi ngược lại nó (mặc dù bạn có thể thêm móc được gọi từ mô-đun nhập khẩu như ông và Jim Garrison cho thấy). Tôi không nghĩ rằng có bất kỳ (thích hợp) cách có một mô-đun biết người gọi của nó và sửa đổi nó mà không có bất kỳ gọi lại – val

+0

Vâng, về mặt kỹ thuật tôi nghĩ rằng bạn có thể làm điều đó với một móc nhập khẩu, nhưng điều đó có vẻ * rất * bẩn. – kindall

3

Làm cách nào để Debug biết mô-đun nào được nhập từ đó? Trả lời: Nó không thể. Làm thế nào để Debug biết chạy nhiều lần nếu nó được nhập vào nhiều hơn một mô-đun? Trả lời: Nó sẽ không; các mô-đun chỉ chạy một lần và sau đó được lưu vào bộ nhớ cache. Vì vậy, những gì bạn muốn làm không thể được thực hiện khá đơn giản như bạn muốn.

Tuy nhiên, bạn có thể thực hiện việc này bằng cách gọi hàm trong mô-đun debug sau khi nhập. Bạn có thể vượt qua __name__ từ mô-đun gọi để cung cấp tên của nó, sau đó có thể lấy tham chiếu đến chính mô-đun và sau đó là các biến cấp cao nhất được xác định trong đó, một số có thể hoạt động. Những trang này sau đó có thể được trang trí.

# debug.py 
import types, sys, functools 

# decorator to be applied to all top-level functions in a module 
def debug(fn): 
    @functools.wraps(fn) 
    def wrapper(*args, **kwargs): 
     print "calling", fn.__name__, "with args", *args, **kwargs 
     result = fn(*args, **kwargs) 
     print "returning from", fn.__name__, "with return value", result 
     return result 

# decorate all top-level functions in named module with a given decorator 
# (by default it is the above decorator but it could be a different one) 
# This makes these functions behave as though they had been written with 
# @debug above them. 
def set_debug(modname, debug=debug): 
    module = sys.modules[modname] 
    for name in dir(module): 
     if not name.startswith("_"): 
      thing = getattr(module, name) 
      if isinstance(thing, types.FunctionType): 
       setattr(module, name, debug(thing)) 

Bây giờ trong module gọi:

# main.py 
import debug 

def main(): 
    print "in main module" 

debug.set_debug(__name__) # install debugging decorator 

main() 

cách tiếp cận đi qua các không gian tên một cách rõ ràng (chứ không phải là tên module) Jim Garrison cũng là tốt và thực sự đơn giản hoá mọi thứ một chút; bạn có thể sử dụng nó để trang trí những thứ khác ngoài mô-đun. Tôi đã phá vỡ của tôi lên để bạn có thể vượt qua trong một trang trí khác nhau nếu bạn muốn.

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