2012-07-28 15 views
5

Tôi có một chức năng nhỏ tuyệt vời mà trông như thế này:Làm thế nào tôi có thể nhận được tên của lớp học của một phương pháp ràng buộc từ ngăn xếp thông dịch viên?

def verbose_print(message, *args, **kwargs): 
    """Prints `message` with a helpful prefix when in verbose mode 

    Args: 
     message (str): The message to print. Can be a format string, e.g. 
      `A %s with some %s in it` 
     *args: Variables for the message format 
     **kwargs: Keyword variables for the message format 
    """ 

    # Only print when in verbose mode 
    if not config.verbose: 
     return 

    # Ready a prefix for the message 
    try: 
     s = inspect.stack() 
     module_name = inspect.getmodule(s[1][0]).__name__ 
     func_name = s[1][3] 
     prefix = '### %s->%s' % (module_name, func_name) 
    except Exception as e: 
     prefix = '### [stack unavailable]' 

    if args: 
     message = message % args 
    elif kwargs: 
     message = message % kwargs 

    print '%s: %s' % (prefix, message) 

Điểm của hàm là tôi có thể gọi nó từ bất cứ nơi nào với một thông điệp, và nếu tập tin cấu hình dự án của tôi được thiết lập sang chế độ verbose, tất cả các tin nhắn sẽ được in với một tiền tố hữu ích để hiển thị nơi nó được gọi. Dưới đây là một ví dụ về một số kết quả:

 
### avesta.webserver->check_login: Checking login for client at 127.0.0.1 
### avesta.webserver->check_login: Found credentials cookie with username: tomas, token: blablabla 
### avesta.webserver->check_login: Login valid, refreshing session 
### avesta.webserver->get_flash_memory: Fetched flash data: None 
### avesta.webserver->get: Fetched data from empty path ('previous_values', 'name'), returning '' 
### avesta.webserver->get: Fetched data from empty path ('previous_values', 'description'), returning '' 
### avesta.webserver->get: Fetched data from empty path ('validation_errors', 'name'), returning '' 

Định dạng là "### module-> chức năng: thông báo".

Hiện tại phần lớn thời gian này là thực sự là hữu ích, nhưng nó không hoàn hảo. Trong ví dụ trên, hàm "get" thực sự là một phương thức ràng buộc của một lớp, nhưng điều đó không hiển thị. Những gì tôi đang cố gắng để đạt được là khi một chức năng là một phương pháp ràng buộc, tôi in với định dạng này thay vì:

"### module-> ClassName.function"

Nhưng vấn đề là:

  1. tôi chỉ nhận được chức năng tên từ chồng, vì vậy tôi thực sự không thể kiểm tra xem đó là một phương pháp ràng buộc
  2. Thậm chí nếu tôi có tài liệu tham khảo chức năng, làm thế nào tôi sẽ suy tên lớp đó là ràng buộc đến?

Cảm ơn mọi câu trả lời có thể giúp tôi hình dung điều này.

Trả lời

5

Tôi nghĩ điều này sẽ dễ dàng, nhưng hóa ra hơi phức tạp một chút. Nếu bạn có tham chiếu đến phương thức bị ràng buộc, bạn có thể lấy tên lớp thông qua boundMethod.im_class.__name__. Tuy nhiên, khi bạn đang lấy chồng, bạn không thể dễ dàng có được một tham chiếu đến phương pháp bị ràng buộc, chỉ để ngăn xếp khung.

Tuy nhiên tất cả đều không bị mất! Mô-đun inspect có thể giúp bạn lấy các đối số chức năng từ khung ngăn xếp bằng chức năng getargvalues. Bạn phải cheat một chút, bằng cách dựa vào quy ước rằng các phương thức luôn có đối số đầu tiên của chúng có tên là "self". Bạn có thể kiểm tra điều đó, sau đó lấy giá trị "tự" từ hàm số locals của hàm và từ đó dễ dàng có được tên lớp. Hãy thử thay thế khối try hiện tại của bạn bằng mã của anh ấy:

s = inspect.stack() 
module_name = inspect.getmodule(s[1][0]).__name__ 
func_name = s[1][3] 
arginfo = inspect.getargvalues(s[1][0]) 
if len(arginfo.args) > 0 and arginfo.args[0] == "self": 
    func_name = "%s.%s" (arginfo.locals["self"].__class__.__name__, func_name) 
prefix = '### %s->%s' % (module_name, func_name) 
+0

Thật tuyệt vời! Có thể làm cho sự nguy hiểm của cheat ít mạnh hơn bằng cách kiểm tra nếu 'tự' là một trường hợp lớp và kiểm tra xem nó trong thực tế có một phương pháp ràng buộc có tên 'func_name'? Nếu vậy, làm thế nào để kiểm tra những thứ đó? – Hubro

+0

Có thể đào sâu hơn và xác minh rằng đối số đầu tiên thực sự có một phương thức ràng buộc có tên 'func_name', nhưng tôi nghi ngờ nó đáng làm phiền. Tôi nghĩ rằng bạn có nhiều khả năng kết thúc với âm tính giả (chức năng được cho là không đúng phương pháp) so với sai tích cực (chức năng thông thường không chính xác thông qua để được phương pháp) bằng cách sử dụng phương pháp này. Đó là bởi vì bạn có thể đặt tên cho đối số đầu tiên của một phương thức, 'self' đơn giản là một quy ước. Hmm, trên thực tế, bây giờ tôi nghĩ về nó, mã của tôi ở trên sẽ không hoạt động cho các chức năng không có đối số. Tôi sẽ chỉnh sửa để sửa lỗi đó. – Blckknght

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