मैं पायथन में वर्तमान मॉड्यूल के भीतर सभी वर्गों की सूची कैसे प्राप्त कर सकता हूं?


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
इस तरह की सुविधा के लिए एक पीईपी था , लेकिन इसे अस्वीकार कर दिया गया था।
गैरी वैन डेर मेरवे

स्रोत को पढ़ने में क्या गलत है "class"? वह काम क्यों नहीं करेगा?
S.Lott

66
मैं यह अनुमान लगा रहा हूं कि प्रश्न कुछ कार्य को स्वचालित करने की इच्छा के बारे में है, इसलिए यह महत्वपूर्ण है कि इसे प्रोग्रामेटिक रूप से किया जाए। संभवतः प्रश्नकर्ता सोचता है कि स्रोत कोड को अपनी आंखों से पढ़कर, मैन्युअल रूप से कर रहा है, पुनरावृत्ति, त्रुटि-प्रवण या समय लेने वाली हो सकती है।
जोनाथन हार्टले

जवाबों:


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) उन मॉड्यूल को प्रिंट सूची में शामिल किया गया है। मैं इससे कैसे बच सकता हूं?
क्रिस

5
@phasetwenty, इंस्पेक्ट के बजाय। आपके पास कुछ इस तरह हो सकता है:inspect.getmembers(sys.modules[__name__], lambda member: member.__module__ == __name__ and isnpect.isclass)
नादिया अलरामली

1
लेकिन dict(inspect.getmembers(sys.modules[__name__])) == globals()हमेशा है True, इसलिए आयात क्यों?
कोजिरो

16
नादिया का जवाब लगभग सही है। बेहतर: inspect.getmembers(sys.modules[__name__], lambda member: inspect.isclass(member) and member.__module__ == __name__
विलियम बुडिंगटन

1
@JohnM। क्योंकि नादिया फोन करना भूल गई थी isclass
एलेक्स हॉल

20

व्हाट अबाउट

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

?


यह वही है जो मैं आमतौर पर करता हूं। अन्य उत्तर बहुत अधिक "साफ" लगते हैं, हालांकि उनके बारे में कुछ पता नहीं था।
मिज़िपज़ोर

1
मेरे लिए बहुत साफ लगता है, खासकर अगर आप पर फिल्टरisinstance(obj, types.ClassType)
kojiro

4
मुझे यह उत्तर बेहतर लगता है क्योंकि यह तब भी काम करेगा जब वर्तमान मॉड्यूल को sys.modules में नहीं डाला गया है, उदाहरण के लिए docs.python.org/2/library/functions.html#execfile से
Chris Smith

@ChrisSmith विशेष रूप से, मैंने आज पाया कि कुछ डिबगर्स जैसे कि pudbआपके प्रोग्राम को इस तरह से चलाते हैं, जिसके परिणामस्वरूप कोड sys.modulesडिबगिंग करते समय बेतरतीब ढंग से ब्रेकिंग का उपयोग करते हैं। globals()थोड़ा बदसूरत लगता है, लेकिन यह बहुत अधिक विश्वसनीय लगता है।
सोरेन ब्योर्नस्टैड

15

मुझे नहीं पता कि ऐसा करने का कोई 'उचित' तरीका है, लेकिन आपका स्निपेट सही रास्ते पर है: बस import foofoo.py जोड़ें , करें inspect.getmembers(foo), और यह ठीक काम करना चाहिए।


वाह, मैंने सोचा होगा कि यह एक परिपत्र निर्भरता या कुछ और पैदा करेगा, लेकिन यह काम करता है!
मैक्क्लीन

एक परिपत्र निर्भरता या आयात लूप न मिलने का कारण यह है कि एक बार जब आप एक मॉड्यूल आयात करते हैं तो यह वैश्विक नामस्थान में जोड़ दिया जाता है। जब आयातित मॉड्यूल को निष्पादित किया जाता है और 'आयात फू' हो जाता है तो यह आयात को रोक देता है क्योंकि मॉड्यूल पहले से ही ग्लोबल्स में उपलब्ध है। यदि आप फू को मुख्य (स्क्रिप्ट के रूप में) निष्पादित करते हैं, तो मॉड्यूल वास्तव में दो बार चलाया जाता है क्योंकि जब आप 'आयात फू' प्राप्त करते हैं तो मुख्य वैश्विक नामस्थान में होगा लेकिन फू नहीं। 'आयात फू' के बाद ' मुख्य ' और ' फू' दोनों ग्लोबल्स नेमस्पेस में होंगे।
गेलिंडेन

10

मैं dirबिल्ट इन प्लस से अपनी जरूरत की सभी चीजें प्राप्त कर सकता था 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 का पायथन वर्ग ब्राउज़र मॉड्यूल स्थिर स्रोत विश्लेषण का उपयोग करता है, इसलिए यह केवल उन मॉड्यूल के लिए काम करता है जो वास्तविक .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)

यदि आप नादिया के उत्तर का उपयोग करते हैं और आप अपने मॉड्यूल पर अन्य कक्षाएं आयात कर रहे थे, तो वह कक्षाएं भी आयात की जा रही होंगी।

तो इसीलिए 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 में काम नहीं करता है। मुझे कोई मॉड्यूल त्रुटि नहीं मिली।
अविरल श्रीवास्तव

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__]

यह आपको वर्ग नामों की एक सूची देता है। यदि आप चाहते हैं कि कक्षा की वस्तुएं स्वयं इसके बजाय सिर्फ ऑब्जेक्टिव रखें।

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, जहां 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.