Tôi thường thấy mình viết các tiện ích dòng lệnh trong đó đối số đầu tiên có nghĩa là đề cập đến một trong nhiều lớp khác nhau. Ví dụ ./something.py feature command —-arguments
, đâu Feature
là một lớp và command
là một phương thức trên lớp đó. Đây là một lớp cơ sở làm cho điều này dễ dàng.
Giả định là lớp cơ sở này nằm trong một thư mục cùng với tất cả các lớp con của nó. Sau đó, bạn có thể gọi ArgBaseClass(foo = bar).load_subclasses()
mà sẽ trả lại một từ điển. Ví dụ: nếu thư mục trông như thế này:
- arg_base_group.py
- tính năng
Giả sử feature.py
thực hiện class Feature(ArgBaseClass)
, sau đó lời mời trên load_subclasses
sẽ trở lại { 'feature' : <Feature object> }
. Cùng kwargs
( foo = bar
) sẽ được truyền vào Feature
lớp.
#!/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