【问题标题】:Python naming conventions for attributes and methods meant to be overwritten旨在被覆盖的属性和方法的 Python 命名约定
【发布时间】:2011-10-18 14:53:56
【问题描述】:

我在 Python 中有一些面向对象的代码,其中一些类旨在扩展以提供缺少的自定义代码位(例如 Template Method pattern,但也带有变量),这些代码只会被超类使用,而不是由使用它们的客户端代码。

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

我一直在浏览 PEP-0008,它只提到在 private 成员不打算被子类使用之前添加下划线。

【问题讨论】:

  • 据我所知,约定是在类的文档字符串中记录它......我认为除此之外没有特定的约定。

标签: python naming-conventions template-method-pattern


【解决方案1】:

我通常使用单下划线,例如_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'

【讨论】:

    【解决方案2】:

    首先我认为你这样说是错误的:

    关于为不打算被子类使用的私有成员添加下划线。

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

    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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-19
        • 1970-01-01
        • 2019-07-25
        • 2010-11-14
        • 1970-01-01
        • 2012-12-03
        • 1970-01-01
        相关资源
        最近更新 更多