为特定类型的所有对象调用方法

时间:2018-04-27 13:29:07

标签: python python-3.x iterator

我有一个从不同类实例化的对象列表。我想在该列表中的某个类的所有对象上调用某个方法。我觉得我找到的方式并不是很优雅,而且可能会有更好的方式。

目前,我这样做:

def execute(fn, classname, objlist):
    '''
    The function that iterates over all objects, 
    finds the fitting ones, and executes the chosen "fn"
    '''
    for obj in objlist:
        # Checks for the class from which the object was instantiated
        if type(obj) is classname:
            # Execute the function.
            fn(obj)

class C():
    def myfn(self):
        print("foo")

class D():
    def otherfn(self):
        print("bar")

objlist = []

objlist.append(C())
objlist.append(D())

execute(C.myfn, C, objlist)
execute(D.otherfn, D, objlist)

输出是:

foo
bar

有更好的方法吗?

编辑:澄清问题

我会尝试以简单的方式说明问题,我希望我不会用细节来压倒你。

我的应用程序与我网络上的以太网连接的嵌入式工作站连接。每个站由不同的类表示,每个类提供不同的功能来控制该站。

首先,必须执行扫描,以便我知道哪些站点实际上在网络上可用。因此,一个基本的"站"对象被创建并且"扫描"叫做。扫描是期望来自电台的答复的请求。如果有答案,它将指定所连接电台的确切类型。

其次,基站需要通过"模式扩展"这是刚刚通过第一次扫描步骤发现的。 "基本"模式由电台所在的特定模式取代。"基本"模式只允许刚执行的扫描。

这是实际的基站类。 __LinkUI包含有关输入用户界面的内容的一些信息,如IP地址范围和端口:

class Station(__LinkUI):
    '''
    Generic class for creating a station. This is used first for
    stations that have no known type yet
    '''
    def __init__(self, ip, storage):
        super().__init__(storage)

        # IP Address of this station
        self.ip = ip

        # The handling object for the TCP connection to this station
        self.handler = Handler(self.storage.network.confport, self.pool)

        # Last response value to a request message
        self.response = None

        # mode of this station. This is an object that details 
        # some functions and variables for controlling a certain 
        # type of station. "Basic" is the default mode with 
        # no special functions
        self.mode = Basic(self)

        # Hardware architecture of a station, like DDS/PLL
        self.architecture = None

这是"模式的一个例子" class,like" Boot",表示处于引导加载程序模式的工作站。这种"模式"扩展了" Station"的功能。对象

class Boot(__Mode):
    '''
    Extends a station by the boot mode
    '''
    def __init__(self, station):
        self.name = "Boot"
        super().__init__(self, station)

        # The interface for using the flash mode of the boot station
        self.flashInterface = FlashInterface(station)
        self.healthInterface = HealthInterface(station)

    def flash(self, callback, data):
        self.flashInterface.flash(callback, data)

    def run(self, callback):
        self.flashInterface.run(callback)

__ Mode是连接一些变量并生成" Messenger"的基类。用于生成发送到工作站的实际原始消息:

class __Mode():
    '''
    Base class for different station modes (Boot, Rx, Tx, Central)
    '''
    def __init__(self, child, station):
        # Generate a messenger object for this kind of station
        self.messenger = GetMessenger(child)

        # Connect variables
        self.station = station
        station.mode = child
        station.name = child.name
        station.messenger = child.messenger

我做了所谓的"接口"附加到" Mode"对象并提供以某种方式控制电台的功能。我可以将多个接口连接到一个站,因此它可以获得所有接口的功能。

总之,电台可能非常不同,我不确定多态是否适用。方法名称,功能或参数不同。

抱歉,如果缺少信息或提供太多信息。

2 个答案:

答案 0 :(得分:0)

一种解决方案是在基类Mode类中实现所有可能的操作(作为无操作),这样您就可以调用任何操作而无需担心对象的当前模式。

另一种解决方案是使用getattr()和方法名称:

def execute(objlist, methodname, *args, **kw):
    for obj in objlist:
        method = getattr(obj, methodname, None)
        if method:
            method(*args, **kw)

FWIW,你在Mode课程中所拥有的实际上是一个不完整的“状态”模式。 You may want to read about it...

答案 1 :(得分:0)

恕我直言你的测试,以了解一个对象属于一个类是否过于严格,并没有正确处理子类型。例如,我将它添加到您的代码中:

class E(C):
   pass

objlist.append(E())

objlist现在包含一个C实例,一个D和一个E.但是E实例也是C继承,所以我希望输出:

execute(C.myfn, C, objlist)

是:

foo
foo

所以我会重写你的功能:

def execute(fn, classname, objlist):
    '''
    The function that iterates over all objects, 
    finds the fitting ones, and executes the chosen "fn"
    '''
    for obj in objlist:
        # Checks for the class from which the object was instantiated
        if isinstance(obj, classname):
            # Execute the function.
            fn(obj)