Python 中的私有方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17193457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:43:38  来源:igfitidea点击:

Private methods in Python

pythonoopstatic-methods

提问by freude

I would like to have a function in my class, which I am going to use only inside methods of this class. I will not call it outside the implementations of these methods. In C++, I would use a method declared in the private section of the class. What is the best way to implement such a function in python? I am thinking of using static decorator for this case. Can I use a function without any decorators and selfword

我想在我的类中有一个函数,我将只在这个类的方法中使用它。我不会在这些方法的实现之外调用它。在 C++ 中,我将使用在类的私有部分中声明的方法。在python中实现这样一个功能的最佳方法是什么?我正在考虑在这种情况下使用静态装饰器。我可以使用没有任何装饰器和self单词的函数吗

采纳答案by Ashwini Chaudhary

Python doesn't have the concept of private methods or attributes, it's all about how you implement your class. But you can use pseudo-private variables(name mangling), any variable preceded by __(two underscores) becomes a pseudo-private variable.

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

From the docs:

文档

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam(at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

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

class A:
    def __private(self):
       pass

So __privatenow actually becomes _A__private

所以__private现在实际上变成了_A__private

example of static method:

静态方法示例:

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

回答by Silas Ray

Python doesn't have the concept of 'private' the way many other languages do. It is built on the consenting adult principle that says that users of your code will use it responsibly. By convention, attributes starting with a single or double leading underscore will be treated as part of the internal implementation, but they are not actually hidden from users. Double underscore will cause name mangling of the attribute name though.

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

Also, I'd note for you that selfis only special by convention, not by any feature of the language. For instance methods, when called as members of an instance, they are implicitly passed the instance as a first argument, but in the implementation of the method itself, that argument can technically be named any arbitrary thing you want. selfis just the convention for ease of understanding code. As a result, not including selfin the signature of a method has no actual functional effect other than causing the implicit instance argument to be assigned to the next variable name in the signature. This is of course different for class methods, which receive the instance of the class object itself as an implicit first argument, and static methods, which receive no implicit arguments at all.

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

回答by zmo

you just don't do it:

你只是不这样做:

  • The pythonic way is to not document those methods/members using docstrings, only with "real" code comments. And the convention is to append a single or a double underscore to them ;

  • Then you can use double underscores in front of your member, so you they are made local to the class (it's mostly name mangling, i.e. the real name of the member outside of the class becomes : instance.__classname_membername). It's useful to avoid conflicts when using inheritance, or create a "private space" between children of a class.

  • AFAICT, it is possible to "hide" variables using metaclasses, but that violates the whole philosophy of python, so I won't go into details about that

  • pythonic 方法是不使用文档字符串记录这些方法/成员,只使用“真实”代码注释。约定是在它们后面附加一个单下划线或双下划线;

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

  • AFAICT,可以使用元类“隐藏”变量,但这违反了python的整个哲学,所以我不会详细介绍

回答by John La Rooy

Python just doesn't do private. If you like you can follow convention and precede the name with a single underscore, but it's up to other coders to respect that in a gentlemanly? fashion

Python 只是不做私有。如果您愿意,您可以遵循惯例并在名称前加上一个下划线,但其他编码人员是否应该以绅士的态度尊重这一点?时尚

? or gentlewomanly

? 或绅士风度

回答by circld

Plenty of great stuff here with obfuscation using leading underscores. Personally, I benefit greatly from the language design decision to make everything public as it reduces the time it takes to understand and use new modules.

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

However, if you're determined to implement private attributes/methods and you're willing to be unpythonic, you could do something along the lines of:

但是,如果您决定实现私有属性/方法并且您愿意不使用 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))

Hard to imagine a case where you'd want to do this, but it is possible.

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