有没有办法在python中加载类后调用函数?

时间:2016-04-11 13:10:41

标签: python

我希望在加载类之后将类注册到管理器,就像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。

3 个答案:

答案 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