2009-06-07 44 views
52

Làm thế nào tôi có thể nhận được lớp đã định nghĩa một phương thức bằng Python?Nhận lớp học đã định nghĩa phương thức

Tôi muốn ví dụ sau để in "__main__.FooClass":

class FooClass: 
    def foo_method(self): 
     print "foo" 

class BarClass(FooClass): 
    pass 

bar = BarClass() 
print get_class_that_defined_method(bar.foo_method) 
+0

Bạn đang sử dụng phiên bản Python nào? Trước 2.2 bạn có thể sử dụng im_class, nhưng điều đó đã được thay đổi để hiển thị loại đối tượng tự ràng buộc. –

+1

Điều cần biết. Nhưng tôi đang sử dụng 2.6. –

Trả lời

54
import inspect 

def get_class_that_defined_method(meth): 
    for cls in inspect.getmro(meth.im_class): 
     if meth.__name__ in cls.__dict__: 
      return cls 
    return None 
+0

Nó hoạt động, cảm ơn! –

+0

Bạn được chào đón! –

+1

Cảm ơn, nó sẽ đưa tôi một thời gian để con số này ra trên riêng của tôi – David

5

Cảm ơn Sr2222 để chỉ ra tôi đã bị mất điểm ...

Dưới đây là cách tiếp cận điều chỉnh đó là giống như Alex nhưng không yêu cầu nhập bất cứ thứ gì. Tôi không nghĩ rằng đó là một cải tiến mặc dù, trừ khi có một hệ thống phân cấp khổng lồ của các lớp kế thừa như cách tiếp cận này dừng lại ngay khi lớp xác định được tìm thấy, thay vì trả lại toàn bộ thừa kế là getmro. Như đã nói, đây là trường hợp không phải là rất.

def get_class_that_defined_method(method): 
    method_name = method.__name__ 
    if method.__self__:  
     classes = [method.__self__.__class__] 
    else: 
     #unbound method 
     classes = [method.im_class] 
    while classes: 
     c = classes.pop() 
     if method_name in c.__dict__: 
      return c 
     else: 
      classes = list(c.__bases__) + classes 
    return None 

Và Ví dụ:

>>> class A(object): 
...  def test(self): pass 
>>> class B(A): pass 
>>> class C(B): pass 
>>> class D(A): 
...  def test(self): print 1 
>>> class E(D,C): pass 

>>> get_class_that_defined_method(A().test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(A.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(B.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(C.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(D.test) 
<class '__main__.D'> 
>>> get_class_that_defined_method(E().test) 
<class '__main__.D'> 
>>> get_class_that_defined_method(E.test) 
<class '__main__.D'> 
>>> E().test() 
1 

Alex giải pháp trả về kết quả tương tự. Miễn là tiếp cận Alex có thể được sử dụng, tôi sẽ sử dụng nó thay vì này.

+0

'Cls(). Meth .__ self__' chỉ cho bạn ví dụ của' Cls' bị ràng buộc với trường hợp cụ thể của 'meth'. Nó tương tự như 'Cls(). Meth.im_class'. Nếu bạn có 'lớp SCLS (Cls)', 'SCLS(). Meth .__ self__' sẽ lấy cho bạn một cá thể' SCls', không phải là một cá thể 'Cls'. Những gì OP muốn là để có được 'Cls', mà nó xuất hiện chỉ có sẵn bằng cách đi bộ MRO như @ Marta Martelli. –

+0

@ sr2222 Bạn nói đúng. Tôi đã sửa đổi câu trả lời như tôi đã bắt đầu mặc dù tôi nghĩ rằng giải pháp Alex là nhỏ gọn hơn. – estani

+0

Đó là một giải pháp tốt nếu bạn cần phải tránh nhập khẩu, nhưng vì bạn về cơ bản chỉ tái triển khai MRO, nó không đảm bảo hoạt động mãi mãi. MRO có thể sẽ vẫn như cũ, nhưng nó đã được thay đổi một lần trong quá khứ của Python, và nếu nó được thay đổi một lần nữa, mã này sẽ dẫn đến những lỗi phổ biến, tinh vi. –

1

Tôi bắt đầu làm một cái gì đó hơi tương tự, về cơ bản ý tưởng đã được kiểm tra bất cứ khi nào một phương pháp trong một lớp cơ sở đã được thực hiện hay không trong một lớp phụ. Hóa ra cách tôi đã làm nó ban đầu tôi không thể phát hiện khi một lớp trung gian đã thực sự thực hiện phương pháp.

Cách giải quyết của tôi cho nó khá đơn giản; đặt phương thức thuộc tính và kiểm tra sự hiện diện của nó sau này. Dưới đây là một đơn giản hóa toàn bộ điều:

class A(): 
    def method(self): 
     pass 
    method._orig = None # This attribute will be gone once the method is implemented 

    def run_method(self, *args, **kwargs): 
     if hasattr(self.method, '_orig'): 
      raise Exception('method not implemented') 
     self.method(*args, **kwargs) 

class B(A): 
    pass 

class C(B): 
    def method(self): 
     pass 

class D(C): 
    pass 

B().run_method() # ==> Raises Exception: method not implemented 
C().run_method() # OK 
D().run_method() # OK 

UPDATE: Thực ra gọi method() từ run_method() (không phải là tinh thần?) Và có nó vượt qua tất cả các đối chưa sửa đổi để phương pháp này.

P.S .: Câu trả lời này không trả lời trực tiếp câu hỏi. IMHO có hai lý do người ta muốn biết lớp nào đã định nghĩa một phương thức; đầu tiên là trỏ các ngón tay vào một lớp trong mã gỡ lỗi (như xử lý ngoại lệ), và thứ hai là xác định xem phương thức đã được triển khai lại chưa (phương thức là một sơ đồ được thực hiện bởi lập trình viên). Câu trả lời này giải quyết trường hợp thứ hai theo một cách khác.

2

Tôi không biết lý do tại sao không có ai đã từng được đưa lên này hoặc lý do tại sao câu trả lời đầu có 50 upvotes khi nó là chậm như là địa ngục, nhưng bạn cũng có thể làm như sau:

def get_class_that_defined_method(meth): 
    return meth.im_class.__name__ 

Đối với python 3 Tôi tin rằng điều này đã thay đổi và bạn sẽ cần phải xem xét .__qualname__.

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