25

我想在我的类中有一个函数,我将只在这个类的方法中使用它。我不会在这些方法的实现之外调用它。在 C++ 中,我会使用在类的私有部分中声明的方法。在 Python 中实现这样一个函数的最佳方法是什么?

我正在考虑在这种情况下使用静态装饰器。我可以使用没有任何装饰器和self单词的函数吗?

4

5 回答 5

39

Python 没有私有方法或属性的概念。这完全取决于您如何实现您的课程。但是您可以使用伪私有变量(名称修改);任何以__(两个下划线)开头的变量都成为伪私有变量。

文档中

由于类私有成员有一个有效的用例(即避免名称与子类定义的名称发生名称冲突),因此对这种称为名称修饰的机制的支持有限。表单的任何标识符__spam(至少两个前导下划线,最多一个尾随下划线)在文本上替换为 _classname__spam,其中 classname 是当前类名,前导下划线被去除。只要它出现在类的定义中,就无需考虑标识符的句法位置,就可以完成这种修饰。

class A:
    def __private(self):
       pass

所以__private现在居然变成了_A__private

静态方法示例:

>>> class A:
...     @staticmethod         # Not required in Python 3.x
...     def __private():
...         print 'hello'
...
>>> A._A__private()
hello
于 2013-06-19T14:14:01.313 回答
8

Python 不像许多其他语言那样具有“私有”的概念。它建立在同意成人原则的基础上,即您的代码的用户将负责任地使用它。按照惯例,以单下划线或双下划线开头的属性将被视为内部实现的一部分,但它们实际上并未对用户隐藏。但是,双下划线会导致属性名称的名称混乱。

另外,请注意,这self只是约定的特殊之处,而不是语言的任何特性。实例方法,当作为实例的成员调用时,会隐式地将实例作为第一个参数传递,但在方法本身的实现中,从技术上讲,该参数可以命名为您想要的任何任意事物。 self只是为了便于理解代码的约定。结果,不包括self在方法的签名中除了导致将隐式实例参数分配给签名中的下一个变量名称外,没有实际的功能影响。

这对于接收类对象本身的实例作为隐式第一个参数的类方法和根本不接收任何隐式参数的静态方法来说当然是不同的。

于 2013-06-19T14:13:19.573 回答
4

这里有很多很棒的东西,使用前导下划线进行混淆。就个人而言,我从语言设计决策中受益匪浅,因为它减少了理解和使用新模块所需的时间。

但是,如果您决心实现私有属性/方法并且您愿意成为 unpythonic,您可以执行以下操作:

from pprint import pprint


# CamelCase because it 'acts' like a class
def SneakyCounter():

    class SneakyCounterInternal(object):

        def __init__(self):
            self.counter = 0

        def add_two(self):
            self.increment()
            self.increment()

        def increment(self):
            self.counter += 1

        def reset(self):
            print 'count prior to reset: {}'.format(self.counter)
            self.counter = 0

    sneaky_counter = SneakyCounterInternal()

    class SneakyCounterExternal(object):

        def add_two(self):
            sneaky_counter.add_two()

        def reset(self):
            sneaky_counter.reset()

    return SneakyCounterExternal()


# counter attribute is not accessible from out here
sneaky_counter = SneakyCounter()

sneaky_counter.add_two()
sneaky_counter.add_two()
sneaky_counter.reset()

# `increment` and `counter` not exposed (AFAIK)
pprint(dir(sneaky_counter))

很难想象您想要这样做的情况,但这是可能的。

于 2017-04-24T03:52:22.180 回答
3

Python 只是不做私有的。如果您愿意,您可以遵循约定并在名称前加上一个下划线,但其他编码人员必须以绅士的方式尊重这一点†

† 或绅士风度

于 2013-06-19T14:14:01.240 回答
1

你只是不这样做:

  • Pythonic 方法是不使用docstrings记录这些方法/成员,仅使用“真实”代码注释。约定是在它们后面加上一个或两个下划线;

  • 然后你可以在你的成员前面使用双下划线,这样它们就成为了类的局部(主要是名称修饰,即类外成员的真实名称变为:)instance.__classname_membername。在使用继承时避免冲突或在类的子级之间创建“私有空间”很有用。

  • 据我所知,可以使用元类“隐藏”变量,但这违反了 Python 的整个哲学,所以我不会对此进行详细介绍。

于 2013-06-19T14:13:43.043 回答