2008-09-15 12 views
8

Làm cách nào để thêm một phương thức thể hiện vào một lớp bằng cách sử dụng một metaclass (có, tôi cần phải sử dụng một metaclass)? Các loại sau đây của tác phẩm, nhưng FUNC_NAME vẫn sẽ là "foo":Làm thế nào để thêm phương thức sử dụng metaclass

def bar(self): 
    print "bar" 

class MetaFoo(type): 
    def __new__(cls, name, bases, dict): 
     dict["foobar"] = bar 
     return type(name, bases, dict) 

class Foo(object): 
    __metaclass__ = MetaFoo 

>>> f = Foo() 
>>> f.foobar() 
bar 
>>> f.foobar.func_name 
'bar' 

Vấn đề của tôi là một số mã thư viện thực sự sử dụng các FUNC_NAME và sau đó thất bại trong việc tìm ra phương pháp 'bar' của instance Foo. Tôi có thể làm:

dict["foobar"] = types.FunctionType(bar.func_code, {}, "foobar") 

Cũng có các loại.MethodType, nhưng tôi cần một cá thể chưa tồn tại để sử dụng. Tôi có thiếu gì đó ở đây không?

+0

Tại sao các bạn cố gắng để thay đổi tên của phương pháp này? không dict [bar.func_name] = thanh thực hiện những gì bạn muốn? –

+0

Câu hỏi hay ... Tôi ban đầu đã tạo tên phương thức dựa trên các thuộc tính được định nghĩa trong dict, nhưng tôi nhận ra điều này là vô nghĩa nếu việc triển khai các phương thức giống hệt nhau. –

Trả lời

15

Cố gắng tự động mở rộng các căn cứ như vậy bạn có thể tận dụng lợi thế của MRO và các phương pháp là phương pháp thực tế:

class Parent(object): 
    def bar(self): 
     print "bar" 

class MetaFoo(type): 
    def __new__(cls, name, bases, dict): 
     return type(name, (Parent,) + bases, dict) 

class Foo(object): 
    __metaclass__ = MetaFoo 

if __name__ == "__main__": 
    f = Foo() 
    f.bar() 
    print f.bar.func_name 
+2

Điều gì sẽ xảy ra nếu tôi muốn tạo một số phương pháp tham chiếu triển khai 'thanh'? –

+0

Hi Aaron, nó hoạt động tốt nhưng nếu bạn cố gắng tạo ra một lớp mới NewFoo thừa hưởng từ Foo bạn nhận được một lỗi thừa kế do các vấn đề MRO. Tôi đã cố giải quyết vấn đề này bằng cách tiếp cận tương tự: https://github.com/tierratelematics/pypom_form/blob/refactor/pypom_form/meta.py#L111 nhưng tôi không biết đó có phải là cách tiếp cận tốt nhất hay không có một cách thức sâu sắc hơn để làm như vậy. Nó cũng hoạt động tốt trên Python 3 –

2

Tôi nghĩ rằng những gì bạn muốn làm điều này là:

>>> class Foo(): 
... def __init__(self, x): 
...  self.x = x 
... 
>>> def bar(self): 
... print 'bar:', self.x 
... 
>>> bar.func_name = 'foobar' 
>>> Foo.foobar = bar 
>>> f = Foo(12) 
>>> f.foobar() 
bar: 12 
>>> f.foobar.func_name 
'foobar' 

Bây giờ bạn có thể tự do vượt qua Foo s đến một thư viện mà hy vọng Foo trường hợp để có một phương thức có tên foobar.

Thật không may, (1) Tôi không biết cách sử dụng metaclasses và (2) Tôi không chắc tôi đã đọc câu hỏi của bạn một cách chính xác, nhưng tôi hy vọng điều này sẽ hữu ích.

Lưu ý rằng func_name chỉ có thể gán trong Python 2.4 trở lên.