2012-06-04 36 views
14

Tôi chỉ thấy các ví dụ để thiết lập phương thức __repr__ trong định nghĩa lớp. Có thể thay đổi __repr__ cho các chức năng hoặc trong định nghĩa của chúng hoặc sau khi xác định chúng?Có thể thay đổi chức năng repr trong python không?

Tôi đã cố gắng nhưng không thành công ...

>>> def f(): 
    pass 
>>> f 
<function f at 0x1026730c8> 
>>> f.__repr__ = lambda: '<New repr>' 
>>> f 
<function __main__.f> 

Trả lời

14

Có, nếu bạn sẵn sàng từ bỏ chức năng thực sự là một chức năng.

Đầu tiên, xác định một lớp cho loại mới của chúng tôi:

import functools 
class reprwrapper(object): 
    def __init__(self, repr, func): 
     self._repr = repr 
     self._func = func 
     functools.update_wrapper(self, func) 
    def __call__(self, *args, **kw): 
     return self._func(*args, **kw) 
    def __repr__(self): 
     return self._repr(self._func) 

Thêm trong một chức năng trang trí:

def withrepr(reprfun): 
    def _wrap(func): 
     return reprwrapper(reprfun, func) 
    return _wrap 

Và bây giờ chúng ta có thể xác định repr cùng với các chức năng:

@withrepr(lambda x: "<Func: %s>" % x.__name__) 
def mul42(y): 
    return y*42 

Bây giờ repr(mul42) sản xuất '<Func: mul42>'

+3

Vui lòng sử dụng 'functools.wraps' để trang trí để cập nhật tên và chuỗi tài liệu của các chức năng được trang trí. – schlamar

+1

Vấn đề là 'print mul42 .__ name__' sẽ tăng AttributeError mà không được mong đợi cho một hàm. Vì vậy, nó sẽ là: 'return wraps (func) (reprwrapper (reprfun, func))' để sửa lỗi này. – schlamar

+1

@ ms4py Trong trường hợp này, tôi nghĩ 'update_wrapper' hơi phù hợp/trực tiếp hơn một chút. Tôi đã sửa đổi lớp bao bọc để nó thực hiện điều này trong hàm tạo của nó. Bằng cách này, cập nhật xảy ra ngay cả khi bạn sử dụng lớp trực tiếp thay vì sử dụng trang trí 'withrepr'. – kwatford

5

Không, bởi vì repr(f) được thực hiện như type(f).__repr__(f) để thay thế.

3

Để làm điều đó, bạn cần thay đổi hàm __repr__ cho lớp đã cho, trong trường hợp này là lớp chức năng dựng sẵn (types.FunctionType). Vì trong Python bạn không thể chỉnh sửa các lớp dựng sẵn, chỉ phân lớp chúng, bạn không thể.

Tuy nhiên, có hai cách tiếp cận bạn có thể làm theo:

  1. Quấn một số chức năng như kwatford gợi ý
  2. Tạo giao thức đại diện của riêng bạn với chức năng repr của riêng bạn. Ví dụ: bạn có thể xác định hàm myrepr lần đầu tiên tìm kiếm các phương thức __myrepr__ mà bạn không thể thêm vào lớp chức năng nhưng bạn có thể thêm nó vào các đối tượng hàm riêng lẻ như bạn đề xuất (cũng như các lớp và đối tượng tùy chỉnh của bạn). repr nếu không tìm thấy __myrepr__. Một thực thể này sẽ là:

    def myrepr(x): 
        try: 
        x.__myrepr__ 
        except AttributeError: 
        return repr(x) 
        else: 
        return x.__myrepr__() 
    

    Sau đó, bạn có thể định nghĩa __myrepr__ phương pháp và sử dụng các chức năng myrepr. Ngoài ra, bạn cũng có thể làm __builtins__.repr = myrepr để đặt chức năng của mình làm mặc định repr và tiếp tục sử dụng repr. Cách tiếp cận này sẽ kết thúc thực hiện chính xác những gì bạn muốn, mặc dù chỉnh sửa __builtins__ có thể không phải lúc nào cũng mong muốn.

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