python: 函数指针打破了多态性

python: Function pointer breaks polymorphism

我想在基 class 中存储函数签名的字典,并让子 classes 覆盖其中一些函数签名。但是,我的实现似乎破坏了多态性。我想要一些关于优雅替代方案的建议。谢谢!

class Base:
    def __init__(self, key):
        self.FXN[key](self)

    def f(self):
        pass

    def g(self):
        pass

    a = 1
    FXN = {
        1 : f,
        2 : g
    }

class Child1(Base):
    def __init__(self, key):
        self.FXN[key](self)

    def f(self):
        print 'hi'

class Child2(Base):
    def __init__(self, key):
        self.FXN[key](self)

    def f(self):
        print 'hey'

    def g(self):
        print 'hello'

if __name__ == '__main__':
    Child1(1) # Nothing happens
    Child2(1) # Nothing happens
    Child2(2) # Nothing happens

编辑:澄清问题

编辑 2:再次澄清问题

评论:在更复杂的情况下,每个构造函数都可以接受某种类型的对象。键是一个枚举,它标识对象类型并指示实例启动采用的路径。

Bruno的解法:下面Bruno先生给了我一个比较优雅的解法

class Base:
    def __init__(self, key):
        self.FXN[key](self)

    def f(self):
        pass

    def g(self):
        pass

    FXN = {
        1 : lambda self: self.f(),
        2 : lambda self: self.g()
    }

class Child1(Base):
    def __init__(self, key):
        self.FXN[key](self)

    def f(self):
        print 'hi'

class Child2(Base):
    def __init__(self, key):
        self.FXN[key](self)

    def f(self):
        print 'hey'

    def g(self):
        print 'hello'

if __name__ == '__main__':
    Child1(1) # hi
    Child2(1) # hey
    Child2(2) # hello

FXN 如果您有对象实例

则无关紧要

试试这个:

class Base:
    def f(self):
        pass

    def g(self):
        pass

class Child1(Base):
    def f(self):
        print 'hi'

class Child2(Base):
    def g(self):
        print 'hello'

if __name__ == '__main__':
    c1 = Child1()
    c2 = Child2()

    c1.f() 
    c2.g()

FXN 是一个 class 变量,未绑定到子 classes。它还引用字典中原始的 f、g 函数对象,而不是子 classes 中定义的名称。它应该如何,因为当执行 bas class' 主体时它们甚至不存在?

为什么不用正常的方法呢?这些将绑定到每个 class。作为替代方案,您可以使用 types.MethodType in __init__().

将函数绑定到每个实例

并且,请记住:instance/class 的所有属性都已存储在对象的字典中 (__dict__),因此实际上无需创建自己的。

这将使您的示例执行您似乎想要的操作:

class Base:
    def __init__(self):
        self.FXN = {
            1 : self.f,
            2 : self.g
        }
    def f(self):
        pass

    def g(self):
        pass


def receive_some_bases():
    return [Child1(), Child2(), Child1(), Child2(), Child1()]

if __name__ == '__main__':
    for base in receive_some_bases():
        base.FXN[1]()
        base.FXN[2]()

更新: 根据您问题的最新更新,听起来您想要某种工厂。 类 的字典可能符合要求:

FXN={
    1: Child1,
    2: Child2
}
def receive_some_integers():
    return [1, 2, 1, 2, 1]

if __name__ == '__main__':
    for value in receive_some_integers():
        c = FXN[value]()  # instantiate Childx
        c.f()             # call a method on instance

这些不是 "function pointers",只是 "functions" - Python 的函数是第一个 class 对象。它确实不会像您预期的那样工作,因为您在 Base.FXN 中存储的是本地(对 class 语句)函数 fg.

有几种可能的解决方案,具体取决于您的 真实 用例(您什么也没说,我怀疑是 XY problem),一个最简单的方法是将这些函数定义为简单的包装器并将实现委托给另一个函数(然后根据需要在子 classes 中重写),即:

class Base(object):
    def f(self):
        return self._f()

    def _f(self):
        pass

    def g(self):
        return self._g()

    def _g(self):
        pass

    FXN = {
        1 : f,
        2 : g
    }


class Child1(Base):
    def _f(self):
        print 'hi'

class Child2(Base):
    def _g(self):
        print 'hello'

if __name__ == '__main__':
    c1 = Child1()
    c2 = Child2()
    c1 = Child1.FXN[1](c1) 
    c2 = Child1.FXN[2](c2) 

更复杂(但可能更有效,再次取决于您要解决的实际问题)解决方案可能基于装饰器(class装饰器或函数装饰器),自定义描述符或(and/or...)自定义元class。

编辑:给定编辑示例,两个简单的解决方案:

使用 lambda:

 class Base(object):
     def f(self):
         pass

     def g(self):
         pass

     FXN = {
         1 : lambda self: self.f(),
         2 : lambda self: self.g()
     }

 for base in receive_some_bases():
     base.FXN[1](base) 
     base.FXN[2](base) 

使用getattr():

class Base(object):
    def f(self):
        pass

    def g(self):
        pass

    FXN = {
        1 : "f",
        2 : "g",
    }

for base in receive_some_bases():
    getattr(base, base.FXN[1])() 
    getattr(base, base.FXN[2])()