পাইথনের বর্তমান মডিউলটির মধ্যে সমস্ত শ্রেণীর তালিকা কীভাবে পেতে পারি?


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"? কেন কাজ করবে না?
এস .লট

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
@ ফ্যাসেটওন্টি, ইন্সপেক্ট.আইক্লাসের পরিবর্তে আপনার মতো কিছু থাকতে পারে:inspect.getmembers(sys.modules[__name__], lambda member: member.__module__ == __name__ and isnpect.isclass)
নাদিয়া আলরামলি

1
তবে dict(inspect.getmembers(sys.modules[__name__])) == globals()সর্বদা Trueতাই কেন আমদানি?
কোজিরো

16
নাদিয়ার উত্তর প্রায় সঠিক is আরও ভাল: 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)
কোজিরো

4
আমি এই উত্তরটি আরও ভাল পছন্দ করি কারণ এটি বর্তমান মডিউলটি সিস.মডিউলগুলিতে না রাখা হলেও এটি কাজ করবে, যেমন ডকস.পিথন.আর.
ক্রিস স্মিথ

@ ক্রিসস্মিথ বিশেষত, আমি আজ আবিষ্কার করেছি যে কিছু ডিবাগার যেমন pudbআপনার প্রোগ্রামটি এইভাবে চালায়, যার ফলে কোডটি sys.modulesডিবাগ করার সময় এলোমেলোভাবে ব্রেক ব্যবহার করে ফলাফল হয় । globals()কিছুটা কুরুচিপূর্ণ মনে হলেও এটি অনেক বেশি নির্ভরযোগ্য বলে মনে হচ্ছে।
সোরেন জর্নস্ট্যাড

15

এটি করার কোনও 'যথাযথ' উপায় আছে কিনা তা আমি জানি না, তবে আপনার স্নিপেটটি সঠিক পথে রয়েছে: কেবল import foofoo.py এ যুক্ত করুন, করুন inspect.getmembers(foo), এবং এটি ভাল কাজ করা উচিত।


ওহ, আমি ভেবেছি এটি একটি বিজ্ঞপ্তি নির্ভরতা বা কিছু তৈরি করবে, কিন্তু এটি কার্যকর!
mcccclean

আপনি কোনও বৃত্তাকার নির্ভরতা বা আমদানি লুপ না পাওয়ার কারণ হ'ল একবার মডিউল আমদানি করার পরে এটি বিশ্বব্যাপী নেমস্পেসে যুক্ত হবে। যখন আমদানি করা মডিউলটি কার্যকর করা হয় এবং 'ইম্পোর্ট ফু' হয়ে যায় তখন তা আমদানি এড়িয়ে যায় কারণ মডিউলটি ইতিমধ্যে গ্লোবালে উপলব্ধ। আপনি প্রধান হিসাবে foo বিন্যাস (ক স্ক্রিপ্ট হিসাবে) চালানো হলে মডিউল আসলে দুইবার চালানোর কারণ যখন আপনি করতে 'আমদানি foo বিন্যাস' get হয় প্রধান foo বিন্যাস বিশ্বব্যাপী নামস্থান কিন্তু হবে না। 'ইম্পোর্ট 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

এটি বর্তমান রেডটি আমি বর্তমান মডিউলে সংজ্ঞায়িত ক্লাসগুলির সমস্ত (যেমন আমদানি করা হয়নি) পেতে পেতে ব্যবহার করি। এটি পিইপি -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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.