我希望在加载类之后将类注册到管理器,就像http处理程序注册到处理程序管理器一样。
可以通过其他方式完成,例如在地图中定义关系或在类定义后调用寄存器函数。
但是有更好的方法可以自动执行此操作吗?
更新
虽然Dunes的回答满足了我的需要。我正在努力改进这个问题,并使其对遇到同样问题的其他人更有用。
以下是示例。
处理程序/ __初始化__。PY
handler / basehandler.py - classBase,HandlerManager
handler / handlerA.py - classA(classBase)
handler / hanlderB.py - classB(classBase)
handlerA和handlerB包含classA和classB,它们是classBase的子类。
classA处理程序来自/ a /,classB处理程序/ b /
的请求我需要在第一次导入处理程序模块时自动将它们注册到HandlerManager。
答案 0 :(得分:3)
如果“正在加载”这里意味着“正在导入”(第一次),那么类装饰器就是一个解决方案。以下示例代码是从this page
复制的registry = {}
def register(cls):
registry[cls.__clsid__] = cls
return cls
@register
class Foo(object):
__clsid__ = "123-456"
def bar(self):
pass
答案 1 :(得分:1)
是的,有一种方法可以自动执行此操作。
正如Inbar建议的那样,__init__
方法是注册对象创建的地方。
以下示例可用于有效地包装现有类,而不是覆盖super
。在这种情况下,我为lists类创建了一个包装器。通过调用class nlist(list):
""" """
def __init__(self, *args, **kwargs):
print('making a new list!') # overwrite with call to a manager
super().__init__(*args)
,您可以使用原始类中的初始化代码。
>>> list('hello')
['h', 'e', 'l', 'l', 'o']
>>> nlist('hello')
making a new list!
['h', 'e', 'l', 'l', 'o']
这看起来如何:
def ssh_ctrl(ip, user, password,cmd):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(hostname=ip, username=user, password=password, timeout=tout, compress = True,look_for_keys=False, allow_agent=False)
except (socket.error,paramiko.AuthenticationException,paramiko.SSHException) as message:
print "ERROR: SSH connection to "+ip+" failed: " +str(message)
sys.exit(1)
stdin, stdout, ssh_stderr = ssh.exec_command(cmd)
out = stdout.read()
stdin.flush()
ssh.close()
return out
答案 2 :(得分:0)
似乎可能用于元类。很难将元类用于任何事物 - 它们几乎可以解决所有问题。使用装饰器可以更容易地实现使用元类可以实现的大多数事情。但是,通过这种方式,您可以确保基本处理程序的任何子类也将自动注册(除非它要求不注册)。
class HandlerManager:
handlers = []
@classmethod
def register(cls, handler):
print("registering", handler)
cls.handlers.append(handler)
class HandlerRegisterer(type):
def __init__(self, name, bases, attrs, register=True):
super().__init__(name, bases, attrs)
if register:
HandlerManager.register(self)
def __new__(metaclass, name, bases, attrs, register=True):
return super().__new__(metaclass, name, bases, attrs)
class BaseHandler(metaclass=HandlerRegisterer, register=False):
# not actually a real handler, so don't register this class
pass
class MyHandler(BaseHandler):
# only have to inherit from another handler to make sure this class
# gets registered.
pass
print(HandlerManager.handlers)
assert BaseHandler not in HandlerManager.handlers
assert MyHandler in HandlerManager.handlers
如果需要使用抽象类,则需要创建元类子类ABCMeta
。这是因为抽象类是通过使用元类实现的,而python只允许类具有一个元类。通过继承ABCMeta,可以使两个子类兼容(任何一个都没有与另一个相冲突的代码)。
from abc import ABC, ABCMeta, abstractmethod
class HandlerRegisterer(ABCMeta):
# subclass ABCMeta rather than type
def __init__(self, name, bases, attrs, register=True):
super().__init__(name, bases, attrs)
if register:
HandlerManager.register(self)
def __new__(metaclass, name, bases, attrs, register=True):
return super().__new__(metaclass, name, bases, attrs)
class AbstractSubHandler(MyHandler, ABC, register=False):
# not strictly necessary to subclass ABC, but nice to know it won't
# screw things up
@abstractmethod
def some_method(self):
pass
try:
AbstractSubHandler()
except TypeError:
print("Can not instantiate abstract class")
print(HandlerManager.handlers)
assert AbstractSubHandler not in HandlerManager.handlers