파이썬에서 현재 모듈 내의 모든 클래스 목록을 어떻게 얻을 수 있습니까?


301

모듈에서 모든 클래스를 추출하는 사람들의 많은 예를 보았습니다. 보통 다음과 같습니다.

# foo.py
class Foo:
    pass

# test.py
import inspect
import foo

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

대박.

그러나 현재 모듈 에서 모든 클래스를 얻는 방법을 찾을 수 없습니다 .

# 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()

이것은 아마도 명백한 것이지만, 나는 아무것도 찾을 수 없었습니다. 누구든지 나를 도울 수 있습니까?


2
이와 같은 기능 에 대한 PEP 가 있었지만 거부되었습니다.
Gary van der Merwe

소스를 읽는 데있어 무엇이 문제입니까 "class"? 왜 작동하지 않습니까?
S.Lott

66
문제는 일부 작업을 자동화하려는 것이므로 프로그래밍 방식으로 수행하는 것이 중요합니다. 아마도 질문자는 눈으로 소스 코드를 읽음으로써 수동으로하는 것이 반복적이거나 오류가 발생하기 쉽거나 시간이 많이 걸릴 수 있다고 생각합니다.
Jonathan Hartley

답변:


386

이 시도:

import sys
current_module = sys.modules[__name__]

당신의 맥락에서 :

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

그리고 더 나은 :

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

inspect.getmembers()술어를 취하기 때문에 .


9
이 모듈의 클래스를 모듈 수준 (예 :)으로 가져 오면 from optparse import OptionParser해당 모듈이 인쇄 목록에 포함됩니다. 어떻게 피할 수 있습니까?
Chris

5
@phasetwenty, inspect.isclass 대신 다음과 같은 것을 가질 수 있습니다.inspect.getmembers(sys.modules[__name__], lambda member: member.__module__ == __name__ and isnpect.isclass)
Nadia Alramli

1
그러나 dict(inspect.getmembers(sys.modules[__name__])) == globals()항상입니다 True. 왜 수입품입니까?
kojiro

16
나디아의 대답은 거의 맞습니다. 더 나은 : inspect.getmembers(sys.modules[__name__], lambda member: inspect.isclass(member) and member.__module__ == __name__
윌리엄 Budington

1
@JohnM. 나디아 전화를 잊었 때문에 isclass.
Alex Hall

20

이건 어떤가요

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

?


이것이 제가 보통하는 일입니다. 그러나 다른 답변은 훨씬 더 "깨끗한"것처럼 보이지만 알지 못했습니다.
Mizipzor

1
당신이 걸러 isinstance(obj, types.ClassType)
내면

4
현재 모듈을 sys.modules에 넣지 않은 경우에도 작동 하므로이
Chris Smith

@ChrisSmith 특히, 오늘은 pudb프로그램을 이런 식 으로 실행하는 것과 같은 일부 디버거 가 코드를 sys.modules디버깅하는 동안 무작위로 코드를 사용 하는 것을 발견했습니다. globals()조금 추한 것 같지만 훨씬 더 신뢰할만한 것 같습니다.
Soren Bjornstad

15

'적절한'방법이 있는지는 모르겠지만 스 니펫은 올바른 길을 가고 있습니다 : import foofoo.py에 추가 하고 수행 inspect.getmembers(foo)하면 정상적으로 작동합니다.


우와, 이것이 순환 종속성이나 무언가를 만들 것이라고 생각했을 것입니다.하지만 작동합니다!
mcccclean

순환 종속성이나 가져 오기 루프가 발생하지 않는 이유는 모듈을 가져 오면 전역 네임 스페이스에 추가되기 때문입니다. 가져온 모듈이 실행되고 'import foo'에 도달하면 모듈이 이미 전역에서 사용 가능하므로 가져 오기를 건너 뜁니다. foo를 main (스크립트로)으로 실행하면 모듈이 실제로 두 번 실행됩니다. 'import foo'에 도달하면 main 은 전역 네임 스페이스에 있지만 foo는 아니기 때문입니다. 'import foo'후에 ' main '과 'foo'는 모두 globals 네임 스페이스에 있습니다.
galinden

10

dir내장 된 plus 에서 필요한 모든 것을 얻을 수있었습니다 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)

그러나 머리카락처럼 보입니다.

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']
        )
    ))

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

stdlib의 Python 클래스 브라우저 모듈은 정적 소스 분석을 사용하므로 실제 .py파일 이 지원하는 모듈에서만 작동 합니다.


4

현재 모듈에 속하는 모든 클래스를 가지려면 다음을 사용할 수 있습니다.

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)

Nadia의 답변을 사용하고 모듈에서 다른 클래스를 가져 오면 해당 클래스도 가져옵니다.

그래서에 member.__module__ == __name__사용 된 술어에 추가되는 이유 입니다 is_class_member. 이 명령문은 클래스가 실제로 모듈에 속하는지 확인합니다.

술어는 부울 값을 리턴하는 함수 (호출 가능)입니다.


3

파이썬 2와 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()

3.6.8에서는 작동하지 않습니다. 모듈 오류가 없습니다.
Aviral Srivastava

3

이것은 현재 모듈에 정의 된 모든 클래스를 가져 오는 데 사용하는 라인입니다 (즉 가져 오지 않음). PEP-8에 따르면 조금 길지만 적합하다고 생각되면 변경할 수 있습니다.

import sys
import inspect

classes = [name for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass) 
          if obj.__module__ is __name__]

클래스 이름 목록이 제공됩니다. 클래스 객체 자체를 원한다면 대신 obj를 유지하십시오.

classes = [obj for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass)
          if obj.__module__ is __name__]

이것은 내 경험에 더 유용했습니다.



0

나는 당신이 이런 식으로 할 수 있다고 생각합니다.

class custom(object):
    __custom__ = True
class Alpha(custom):
    something = 3
def GetClasses():
    return [x for x in globals() if hasattr(globals()[str(x)], '__custom__')]
print(GetClasses())`

자신의 수업이 필요한 경우


0

나는 종종 첫 번째 인수가 많은 다른 클래스 중 하나를 가리키는 명령 줄 유틸리티를 작성한다는 것을 알게되었습니다. 예를 들어 ./something.py feature command —-arguments, where Feature는 클래스이고 command해당 클래스의 메소드입니다. 이것을 쉽게 만드는 기본 클래스가 있습니다.

이 기본 클래스는 모든 서브 클래스와 함께 디렉토리에 상주한다고 가정합니다. 그런 다음 전화를 걸어 ArgBaseClass(foo = bar).load_subclasses()사전을 반환합니다. 예를 들어 디렉토리가 다음과 같은 경우

  • arg_base_class.py
  • feature.py

feature.py구현을 가정하면 class Feature(ArgBaseClass)위의 호출 load_subclasses이 반환 { 'feature' : <Feature object> }됩니다. 같은 kwargs( foo = bar)이 Feature수업에 전달됩니다 .

#!/usr/bin/env python3
import os, pkgutil, importlib, inspect

class ArgBaseClass():
    # Assign all keyword arguments as properties on self, and keep the kwargs for later.
    def __init__(self, **kwargs):
        self._kwargs = kwargs
        for (k, v) in kwargs.items():
            setattr(self, k, v)
        ms = inspect.getmembers(self, predicate=inspect.ismethod)
        self.methods = dict([(n, m) for (n, m) in ms if not n.startswith('_')])

    # Add the names of the methods to a parser object.
    def _parse_arguments(self, parser):
        parser.add_argument('method', choices=list(self.methods))
        return parser

    # Instantiate one of each of the subclasses of this class.
    def load_subclasses(self):
        module_dir = os.path.dirname(__file__)
        module_name = os.path.basename(os.path.normpath(module_dir))
        parent_class = self.__class__
        modules = {}
        # Load all the modules it the package:
        for (module_loader, name, ispkg) in pkgutil.iter_modules([module_dir]):
            modules[name] = importlib.import_module('.' + name, module_name)

        # Instantiate one of each class, passing the keyword arguments.
        ret = {}
        for cls in parent_class.__subclasses__():
            path = cls.__module__.split('.')
            ret[path[-1]] = cls(**self._kwargs)
        return ret
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.