8

我在 Python 中有一些面向对象的代码,其中一些类旨在扩展以提供缺少的自定义代码位(一个 la模板方法模式,但也有变量),这些代码只会由超类使用,而不是由使用它们的客户端代码。

这种抽象(或枯燥,因为它们在超类中的实现要么是要么pass引发NonImplemented异常)方法和属性有任何样式约定吗?

我一直在浏览PEP-0008,它只提到在不打算被子类使用的私有成员前面加上下划线。

4

3 回答 3

13

我通常使用单下划线,例如_myvar用于受保护的(如在 C++ 中)方法/属性,它可以被派生类使用并使用双下划线,例如__var,当它不应该被其他任何人使用时,以及作为类定义级别的双下划线名称是mangled,因此它们不能在派生类中被覆盖,例如

class A(object):
    def result1(self): # public method
        return self._calc1()

    def result2(self): # public method
        return self.__calc2()

    def _calc1(self): # protected method, can be overridden in derived class
        return 'a1'

    def __calc2(self): # private can't be overridden
        return 'a2'


class B(A):
    def _calc1(self):
        return 'b1'

    def __calc2(self):
        return 'b2'

a = A()
print a.result1(),a.result2()
b = B()
print b.result1(),b.result2()

在这里,派生类似乎B覆盖了两者_calc1__calc2__calc2没有被覆盖,因为它的名称已经与类名混淆,因此输出是

a1 a2
b1 a2

代替

a1 a2
b1 b2

但最终选择任何约定并记录它,在上述情况下,也不是基类不能覆盖私有,这是一种方法:)

class B(A):
    def _calc1(self):
        return 'b1'

    def _A__calc2(self):
        return 'b2'
于 2011-10-18T15:13:45.963 回答
10

首先,我认为当您这样说时您是错误的:

关于在不打算被子类使用的私有成员前面加上下划线。

实际上,通过下划线添加方法/属性是一种 python 约定,这意味着不应在类(及其子类)之外访问此方法/属性,我认为您忘记阅读有关用于制作方法的双下划线/attribute 无法覆盖。

class Foo(object):
    def __foo(self):
        print "foo"
    def main(self):
        self.__foo()


class Bar(Foo):
    def __foo(self):
        print "bar"


bar = Bar()
bar.main()
# This will print "foo" and not "bar".

还有另一种声明存根方法的方法是使用abc.ABCMetaabc.abstractmethod

于 2011-10-18T15:14:13.177 回答
2

这些方法并没有真正的命名约定,因为当它们被覆盖时它们将具有相同的名称。否则他们不会被覆盖!我认为让方法被覆盖做一些微不足道的事情,并相应地记录它就足够了:

class MyClass:

  def aMethod():
    '''Will be overridden in MyDerivedClass'''
    pass

如果您有一个将被覆盖的重要方法,但您仍然希望能够访问基本版本,那么您在问题中提到的名称修饰很有用。有关更多信息和示例,请参阅文档。

于 2011-10-18T15:15:24.587 回答