Python属性和方法的命名约定(可重写)

8 投票
3 回答
8916 浏览
提问于 2025-04-17 04:33

我在Python中写了一些面向对象的代码,有些类是为了扩展而设计的,目的是添加一些缺失的自定义代码(就像模板方法模式那样,但也包括变量),这些代码只会被超类使用,而不会被使用这些类的客户端代码调用。

对于这种抽象(或者说有点无聊,因为在超类中的实现可能只是pass或者抛出NonImplemented异常)的方法和属性,有没有什么风格上的约定呢?

我查阅了PEP-0008,里面只提到要在不打算被子类使用的私有成员前加一个下划线。

3 个回答

2

其实这些方法没有特别的命名规则,因为当它们被重写的时候,名字是一样的。要不然就不能重写了!我觉得让被重写的方法做一些简单的事情,并且把这个说明清楚就可以了:

class MyClass:

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

你提到的名字改编(name mangling)是很有用的,特别是当你有一个比较复杂的方法需要被重写,但你还是想访问原来的版本。想了解更多信息和例子,可以查看这个文档

13

我通常用一个下划线,比如 _myvar,来表示受保护的方法或属性(就像在C++中一样),这意味着这些方法或属性可以被子类使用。而当我希望某个方法或属性不被其他任何人使用时,我会用两个下划线,比如 __var。因为在类定义时,带有双下划线的名字会被“改名”,这样在子类中就无法覆盖它们。

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'
10

首先,我觉得你在说这句话的时候有些误解:

关于在私有成员前加下划线,这些成员不打算被子类使用。

其实,在方法或属性前加下划线是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

撰写回答