2009-11-25 23 views
214

Tôi đã nhìn thấy rất nhiều ví dụ về những người giải nén tất cả các lớp từ một mô-đun, thường cái gì đó như:Làm cách nào để có danh sách tất cả các lớp trong mô-đun hiện tại bằng Python?

# foo.py 
class Foo: 
    pass 

# test.py 
import inspect 
import foo 

for name, obj in inspect.getmembers(foo): 
    if inspect.isclass(obj): 
     print obj 

ảnh vui nhộn.

Nhưng tôi không thể tìm hiểu cách nhận tất cả các lớp học từ mô-đun hiện tại.

# foo.py 
import inspect 

class Foo: 
    pass 

def print_classes(): 
    for name, obj in inspect.getmembers(???): # what do I do here? 
     if inspect.isclass(obj): 
      print obj 

# test.py 
import foo 

foo.print_classes() 

Đây có thể là điều thực sự rõ ràng, nhưng tôi chưa thể tìm thấy bất kỳ thứ gì. Ai có thể giúp tôi không?

+0

Có gì sai khi đọc nguồn cho '" lớp "'? Tại sao nó sẽ không hoạt động? –

+48

Tôi đoán câu hỏi là về việc muốn tự động hóa một số tác vụ, vì vậy điều quan trọng là nó được thực hiện theo chương trình. Có lẽ người hỏi nghĩ rằng làm điều đó bằng tay, bằng cách đọc mã nguồn bằng mắt, có thể lặp đi lặp lại, dễ bị lỗi hoặc tốn thời gian. –

+0

Có một [PEP] (http://www.python.org/dev/peps/pep-3130/) cho một tính năng như thế này, nhưng nó đã bị từ chối. –

Trả lời

272

Hãy thử điều này:

import sys 
current_module = sys.modules[__name__] 

Trong bối cảnh của bạn:

import sys, inspect 
def print_classes(): 
    for name, obj in inspect.getmembers(sys.modules[__name__]): 
     if inspect.isclass(obj): 
      print(obj) 

Và thậm chí tốt hơn:

clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass) 

inspect.getmembers() mất một vị ngữ.

+5

Nếu tôi nhập các lớp học trong mô-đun này ở cấp mô-đun (tức là, 'từ tùy chọn nhập khẩu OptionParser'), các mô-đun đó được bao gồm trong danh sách in. Làm thế nào tôi có thể tránh điều đó? – Chris

+3

@phasetwenty, thay vì inspect.isclass bạn có thể có một cái gì đó như: 'inspect.getmembers (sys.modules [__ name__], lambda member: member .__ module__ == __name__ và isnpect.isclass)' –

+1

nhưng 'dict (inspect.getmembers (sys.modules [__ name__])) == globals() 'luôn luôn là' True', vậy tại sao nhập khẩu? – kojiro

9

Tôi không biết nếu có cách 'thích hợp' để làm điều đó, nhưng đoạn mã của bạn đang đi đúng hướng: chỉ cần thêm import foo vào foo.py, làm inspect.getmembers(foo) và nó sẽ hoạt động tốt.

+0

Whoa, tôi đã nghĩ rằng điều này sẽ tạo ra một phụ thuộc vòng tròn hoặc một cái gì đó, nhưng nó hoạt động! – mcccclean

+0

Lý do bạn không nhận được phụ thuộc vòng tròn hoặc vòng lặp nhập là khi bạn nhập mô-đun, nó được thêm vào không gian tên chung. Khi mô-đun đã nhập được thực hiện và được 'nhập foo', nó bỏ qua việc nhập vì mô-đun đã có sẵn trong hình cầu. Nếu bạn thực hiện foo là chính (như là một kịch bản) các mô-đun thực sự chạy hai lần bởi vì khi bạn nhận được để 'nhập khẩu foo' __main__ sẽ được trong không gian tên toàn cầu nhưng không foo. Sau khi 'import foo' cả '__main__' và 'foo' sẽ nằm trong vùng tên globals. – galinden

16

gì về

g = globals().copy() 
for name, obj in g.iteritems(): 

?

+0

Đây là những gì tôi thường làm.Các câu trả lời khác có vẻ nhiều hơn" sạch "mặc dù, không biết về họ. – Mizipzor

+0

Dường như rất sạch sẽ cho tôi, đặc biệt nếu bạn lọc trên' isinstance (obj, types.ClassType) ' – kojiro

+2

Tôi thích câu trả lời này tốt hơn vì nó sẽ hoạt động ngay cả khi mô-đun hiện tại chưa được đặt trong sys.modules, ví dụ: từ http://docs.python.org/2/library/functions.html#execfile –

6
import pyclbr 
print(pyclbr.readmodule(__name__).keys()) 

Lưu ý rằng mô-đun trình duyệt lớp Python của stdlib sử dụng phân tích nguồn tĩnh, vì vậy nó chỉ hoạt động cho các mô-đun được hỗ trợ bởi tệp .py thực.

5

Tôi có thể nhận tất cả những gì tôi cần từ số dir được tích hợp thêm getattr.

# Works on pretty much everything, but be mindful that 
# you get lists of strings back 

print dir(myproject) 
print dir(myproject.mymodule) 
print dir(myproject.mymodule.myfile) 
print dir(myproject.mymodule.myfile.myclass) 

# But, the string names can be resolved with getattr, (as seen below) 

Mặc dù, nó đi ra trông như một Hairball:

def list_supported_platforms(): 
    """ 
     List supported platforms (to match sys.platform) 

     @Retirms: 
      list str: platform names 
    """ 
    return list(itertools.chain(
     *list(
      # Get the class's constant 
      getattr(
       # Get the module's first class, which we wrote 
       getattr(
        # Get the module 
        getattr(platforms, item), 
        dir(
         getattr(platforms, item) 
        )[0] 
       ), 
       'SYS_PLATFORMS' 
      ) 
      # For each include in platforms/__init__.py 
      for item in dir(platforms) 
      # Ignore magic, ourselves (index.py) and a base class. 
      if not item.startswith('__') and item not in ['index', 'base'] 
     ) 
    )) 
1

Một giải pháp mà các công trình bằng Python 2 và 3:

#foo.py 
import sys 

class Foo(object): 
    pass 

def print_classes(): 
    current_module = sys.modules[__name__] 
    for key in dir(current_module): 
     if isinstance(getattr(current_module, key), type): 
      print(key) 

# test.py 
import foo 
foo.print_classes() 
2

Nếu bạn muốn có tất cả các lớp , thuộc về mô-đun hiện tại, bạn có thể sử dụng điều này:

import sys, inspect 
def print_classes(): 
    is_class_member = lambda member: inspect.isclass(member) and member.__module__ == __name__ 
    clsmembers = inspect.getmembers(sys.modules[__name__], is_class_member) 

Nếu bạn sử dụng câu trả lời của Nadia và bạn đã nhập các lớp khác trên mô-đun của mình, các lớp đó cũng sẽ được nhập.

Vì vậy, đó là lý do tại sao member.__module__ == __name__ đang được thêm vào vị từ được sử dụng trên is_class_member. Câu lệnh này kiểm tra xem lớp đó có thuộc về module hay không.

Vị từ là hàm (có thể gọi), trả về giá trị boolean.

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