Python中的私有方法

Python中的私有方法,python,oop,static-methods,Python,Oop,Static Methods,我希望在我的类中有一个函数,我将只在这个类的方法中使用它。我不会在这些方法的实现之外调用它。在C++中,我将使用类的私有部分中声明的方法。在python中实现这样一个函数的最佳方法是什么?我正在考虑在这个案例中使用静态装饰器。我可以在没有任何装饰符的情况下使用函数吗?Python不像许多其他语言那样具有“私有”的概念。它建立在成年人同意的原则之上,即代码的用户将负责任地使用它。按照惯例,以单下划线或双下划线开头的属性将被视为内部实现的一部分,但它们实际上不会对用户隐藏。但是,双下划线将导致属性名

我希望在我的类中有一个函数,我将只在这个类的方法中使用它。我不会在这些方法的实现之外调用它。在C++中,我将使用类的私有部分中声明的方法。在python中实现这样一个函数的最佳方法是什么?我正在考虑在这个案例中使用静态装饰器。我可以在没有任何装饰符的情况下使用函数吗?Python不像许多其他语言那样具有“私有”的概念。它建立在成年人同意的原则之上,即代码的用户将负责任地使用它。按照惯例,以单下划线或双下划线开头的属性将被视为内部实现的一部分,但它们实际上不会对用户隐藏。但是,双下划线将导致属性名称的名称混乱

另外,我要提醒你的是,
self
只是按照惯例,而不是语言的任何特征。例如实例方法,当作为实例的成员调用时,它们会作为第一个参数隐式地传递给实例,但在方法本身的实现中,该参数在技术上可以被命名为任何您想要的任意对象
self
只是一种便于理解代码的惯例。因此,在方法的签名中不包含
self
,除了导致隐式实例参数被分配给签名中的下一个变量名之外,没有实际的功能效果。当然,对于类方法(将类对象本身的实例作为隐式第一个参数接收)和静态方法(根本不接收隐式参数),这两种方法是不同的。

您只是不这样做:

  • pythonic的方法是不使用docstring记录那些方法/成员,只使用“真实”代码注释。惯例是在它们后面加上一个或两个下划线

  • 然后,您可以在成员前面使用双下划线,使其成为类的本地名称(主要是名称混乱,即类外成员的真实名称变为:
    instance.\uu classname\u membername
    )。在使用继承时避免冲突,或者在类的子类之间创建“私有空间”,这很有用

  • 首先,可以使用元类“隐藏”变量,但这违反了python的全部理念,因此我将不详细介绍


Python没有私有方法或属性的概念,而是关于如何实现类。但是您可以使用伪私有变量(名称mangling),任何前面有
\uuu
(两个下划线)的变量都将成为伪私有变量

从:

因为类私有成员有一个有效的用例(即 避免名称与子类定义的名称发生名称冲突) 对这种机制的支持是有限的,称为名称混乱。任何 垃圾邮件格式的标识符(至少两个前导下划线,至少 大多数尾随下划线)在文本上替换为
\u classname\uu spam
,其中classname是当前类名,去掉前导下划线。这种弄脏是不加考虑的 标识符的语法位置,只要它出现 在类的定义中

所以
\u private
现在实际上变成了
\u A\u private

静态方法示例:

>>> class A:
...     @staticmethod         #not required in py3.x
...     def __private():
...         print 'hello'
...         
>>> A._A__private()
hello

Python只是不做私有的。如果您愿意,您可以遵循惯例,在名称前面加一个单下划线,但这取决于其他编码人员是否以绅士风度†的方式尊重这一点


†或温柔的女人

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

但是,如果您决心实现私有属性/方法,并且愿意不使用pythonic,那么您可以按照以下思路做一些事情:

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))

很难想象您会想这样做,但这是可能的。

Python中没有真正的“私有”方法。请看-更具体地说,.我想问的是做这件事的好方式静态方法和“私有”方法是两件不同的事情。。。你能解释一下你到底想要什么吗?您想要一个既静态又私有的方法吗?好的样式是在方法名称前加下划线。双下划线会激活名称混乱。这绝对不同于Private这正是我所说的:你不做,但你使用约定!您可以通过元类混淆属性访问,也可以创建只读属性,并使用装饰器或元类实现private/setter/getter模式,但是混淆某些东西的唯一方法是将其隐藏在C扩展中,而有些人确实无法从Python代码中获得。我可以只做def_uprivate()吗:没有自我通过?然后在我的类中调用它_private()。我可以在类之外访问这个函数吗?@freude您已经将它定义为一个静态方法,并将其称为:
a.\u a\u private()
在这种情况下,静态是什么意思?
\u
的目标是避免与子类发生冲突。它通过名称混乱来实现这一点,将类名合并到变量中。这会使变量更难找到和访问,这是一个副作用。您确实需要一个装饰器。Python专门处理类方法的第一个参数,因此除非应用
@staticmethod
或类似的修饰符,否则会出现错误。这是一个不使用Python的好例子,但很有教育意义)
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))