【问题标题】:Mimic Python (pure) virtual functions like C#模仿 C# 之类的 Python(纯)虚函数
【发布时间】:2013-06-09 21:56:12
【问题描述】:

在 Python 中模仿 C# 中的虚函数和纯虚函数的最佳方法是什么?

目前我使用的架构如下:

class AbstractClass(object):
    '''Abstract class'''
    def __init__(self):
        assert False, 'Class cannot be instantiated'

    def _virtual_init(self):
        print 'Base "constructor"'

    def pure_virtual_function(self):
        assert False, 'Pure virtual function should be derived'

    def virtual_function(self):
        print 'Base: virtual function'

class Derived1(AbstractClass):
    '''All functions derived'''
    def __init__(self):
        print 'Derived1: constructor'
        AbstractClass._virtual_init(self)

    def pure_virtual_function(self):
        print 'Derived1: pure virtual function'

    def virtual_function(self):
        print 'Derived1: virtual function'

class Derived2(AbstractClass):
    '''Pure virtual method missing.'''
    def __init__(self):
        print 'Derived2: constructor'
        AbstractClass._virtual_init(self)

    def virtual_function(self):
        print 'Derived3: virtual function'

class Derived3(AbstractClass):
    '''Virtual method missing (use base class)'''
    def __init__(self):
        print 'Derived3: constructor'
        AbstractClass._virtual_init(self)

    def pure_virtual_function(self):
        print 'Derived3: pure virtual function'


# ab = AbstractClass() # Gives error -> OK

print 'DERIVED 1'    
dv1 = Derived1()
dv1.pure_virtual_function()
dv1.virtual_function()

print 'DERIVED 2'    
dv2 = Derived2()
# dv2.pure_virtual_function() # Gives error: Pure virtual function should be derived -> OK
dv2.virtual_function()

print 'DERIVED 3'    
dv3 = Derived3()
# dv3.pure_virtual_function() # Gives error: Pure virtual function should be derived -> OK
dv3.virtual_function()

我得到输出:

DERIVED 1
Derived1: constructor
Base "constructor"
Derived1: pure virtual function
Derived1: virtual function
DERIVED 2
Derived2: constructor
Base "constructor"
Derived3: virtual function
DERIVED 3
Derived3: constructor
Base "constructor"
Derived3: pure virtual function
Base: virtual function

但是我的具体问题是:

  1. 有没有更优雅的方式在 Python (2.7) 中定义抽象基类? 上述解决方案仅在运行时给出错误(例如使用 pylint) Python afaik 中没有“抽象”关键字。
  2. 有没有更优雅的方式在 Python (2.7) 中定义纯虚方法? 同样,上述解决方案只会在运行时出错。
  3. 有没有更优雅的方式在 Python (2.7) 中定义虚拟方法? 不需要检查,但在 Python afaik 中没有像“virtual”这样的关键字。

提前致谢。

【问题讨论】:

  • 我对这些设计模式并不完全熟悉......但是阅读这段代码让我想起了abc 模块。您可能想看看那里,看看它是否提供了您正在寻找的功能。
  • 您永远不会得到比运行时错误更多的信息。除了语法的有效性之外,没有可言的编译时检查。 (尽管您可以尝试 pylint 为您执行此类检查。)更好的是,忘记所有那些简洁的设计工具。就吧。定义几个具有兼容接口但没有继承的类,传递实例等,而不试图让计算机强制执行这些不变量。你似乎在用 C#/Java 思考。这会导致糟糕的 Python 输出,就像 Python 思维方式会产生糟糕的 C#/Java 代码一样。
  • 你为什么要这样做?每种语言都有自己的做事方式。在 python 中你不需要这个。
  • 我认为继承是一种非常好的软件设计方式,但它在 Python 中并没有很好地实现......但正如@mgilson 已经注意到的那样,有一个很好的 abc 模块可以解决部分问题.

标签: c# python abstract-class virtual-functions pure-virtual


【解决方案1】:
class AbstractBaseClass(object):
    def __init__(self):
        if self.__class__.__name__ == 'AbstractBaseClass':
            raise NotImplementedError("Can't instantiate AbstractBaseClass")

class DerivedClass(AbstractBaseClass):
    def __init__(self):
        super().__init__()
        # ...

这个例子表明派生类(具有不同的__class__.__name__ 成员)可以被实例化,并继承AbstractBaseClass 提供的属性。但是如果 AbstractBaseClass 被直接实例化,就会抛出NotImplementedError 异常。

【讨论】:

  • 在你的答案中添加一些 cmets
【解决方案2】:

当您询问虚拟方法时,我不确定您到底是什么意思,因为在 Python 中所有方法都是虚拟的。而且我也不确定您为什么使用_virtual_init 而不是__init__...只是重命名一个方法会给您带来什么好处吗?

更新:啊,我有个主意。您可能这样做是为了禁止基类的实例化仍然保留初始化功能。这里的答案是:强迫事物不是pythonic。只需证明这个类是抽象的(可能称之为AbstractSmth)。

谈到运行时错误。 Python 是一种动态 语言,所以它就是这样工作的。一个常见的习惯用法是在__init__ 中提高NotImplementedError 以表明您的类是抽象的(对于抽象(纯虚拟)方法也是如此)。您还可以查看abc,因为它可以执行您想要的操作:它禁止实例化抽象类。但我也强烈建议阅读PEP-3119 以了解抽象基类什么以及它们不是

AFAIK,提高 NotImplementedError 足以让 pylint 了解您的类/方法是抽象的。

【讨论】:

  • 我使用 _virtual_init 而不是 init 因为我不希望用户直接实例化抽象类。但是 abc 模块克服了这个问题。记录不如执行好。而且我知道 Python 是一种动态语言,NotImplementedError 确实比断言更好。感谢您提供 PEP-3119 链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-04
  • 1970-01-01
  • 2013-01-15
  • 2014-03-08
  • 2016-07-22
  • 1970-01-01
相关资源
最近更新 更多