मैं अक्सर खुद को कमांड लाइन उपयोगिताओं को लिखने में पाता हूं, जिसमें पहला तर्क कई अलग-अलग वर्गों में से एक को संदर्भित करने के लिए है। उदाहरण के लिए ./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