Python中的受保护方法

42
“可能重复问题”:
如何在Python子类中将方法设置为私有的?
Python中的私有变量和方法

我该如何在Python类中定义一个受保护的方法,仅限于子类可见?

这是我的代码:

class BaseType(Model):
    def __init__(self):
        Model.__init__(self, self.__defaults())


    def __defaults(self):
        return {'name': {},
                'readonly': {},
                'constraints': {'value': UniqueMap()},
                'cType': {}
        }


    cType = property(lambda self: self.getAttribute("cType"), lambda self, data:              self.setAttribute('cType', data))
    name = property(lambda self: self.getAttribute("name"), lambda self, data: self.setAttribute('name', data))
    readonly = property(lambda self: self.getAttribute("readonly"),
                        lambda self, data: self.setAttribute('readonly', data))

    constraints = property(lambda self: self.getAttribute("constraints"))

    def getJsCode(self):
        pass

    def getCsCode(self):
        pass


    def generateCsCode(self, template=None, constraintMap=None, **kwargs):
        if not template:
            template = self.csTemplate

        if not constraintMap: constraintMap = {}
        atts = ""

        constraintMap.update(constraintMap)

        for element in self.getNoneEmptyAttributes():
            if not AbstractType.constraintMap.has_key(element[0].lower()):
                continue
            attTemplate = Template(AbstractType.constraintMap[element[0].lower()]['cs'])
            attValue = str(element[1]['value'])
            atts += "%s  " % attTemplate.substitute({'value': attValue})

        kwargs.update(dict(attributes=atts))

        return template.substitute(kwargs)



class  MainClass(BaseType, Model):
    def __init__(self):
        #Only Model will initialize
        Model.__init__(self, self.__defaults())
        BaseType.__init__(self)

    def __defaults(self):
        return {'name': {},
                'fields': {'value': UniqueMap()},
                'innerClass': {'value': UniqueMap()},
                'types': {}
        }

    fields = property(lambda self: self.getAttribute("fields"))
    innerClass = property(lambda self: self.getAttribute("innerClass"))
    types = property(lambda self: self.getAttribute("types"))


    @staticmethod
    def isType(iType):
    #        return type(widget) in WidgetSelector.widgets.itervalues()
        return isinstance(iType, AbstractType)

    def addType(self, type):
        if not MainClass.isType(type):
            raise Exception, "Unknown widget type %s" % type
        self.types[type.name] = type

我希望只有BaseType的子类才能看到BaseTypegenerateCsCode方法。

@jamylak 不不不不不,我只是想说如何定义一个受保护的方法,我知道下划线。 - Pooya
1
@Pooya:你已经得到了答案:在Python中不这样做。描述一下更大的问题,我们可以帮助你找到一个适合Python的解决方案。 - Ned Batchelder
@Pooya:顺便说一句,这行代码constraintMap.update(constraintMap)没有作用,你正在用一个字典更新它本身。 - Ned Batchelder
2
@Pooya,好的,你做不到。编写文档,解释开发人员应该调用什么和不应该调用什么。这就是Python的方式。 - Ned Batchelder
3
如果你的开发人员不读文档,那么你就有一个更大的问题。首先要解决这个问题。我知道这很困难,但编译器不能改善你的团队。 - Ned Batchelder
显示剩余6条评论
2个回答

103

Python不像C++/Java/C#一样支持访问保护,所有东西都是公共的。座右铭是“我们这里全是成年人”。记录你的类,并坚持要求你的合作者阅读和遵循文档。

在Python中,以下划线开头的名称意味着“除非你真的知道应该使用它们,否则不要使用它们”。你可以选择用下划线开始你的“受保护”方法。但请记住,这只是一个惯例,它不会改变方法被访问的方式。

以双下划线(__name)开头的名称是被破坏的,这样就可以构建继承层次结构而不用担心名称冲突。有些人将其用于“私有”方法,但同样,这不会改变方法被访问的方式。

最好的策略是逐渐习惯这样一种模式,在单个进程中的所有代码都必须编写得协调一致。


1
是的,我知道关于 _ 和 __ 的内容,但我想知道如何使我的方法受保护,就像 Java 中的 protected 一样。 - Pooya
50
答案很简单,已经提供了:在Python中你无法这样做。 - Ned Batchelder
5
"我们已经成年了!"我希望你能对破坏者和黑客说出这句话 :( - John Strood
11
希望“破坏者和黑客”的评论与受保护的方法无关。如果黑客在您的进程中运行其代码,任何数量的受保护的方法都无法拯救您。 - Ned Batchelder

13

不行。Python有意不支持访问控制。按照惯例,以下划线开头的方法是私有的,并且你应该在文档中明确声明谁应该使用该方法。


17
按照惯例,一个下划线被认为是受保护的,而两个下划线被认为是私有的。 - l__flex__l
1
@l__flex__l:在实例属性中使用双下划线前缀会触发名称重整,具有非常特定的语义。这不是一种约定,而是语言定义的一部分。根据 PEP 8,一个下划线前缀表示“弱内部使用指示符”。我认为没有任何有用的类比可以与 C++ 的“protected”和“private”访问修饰符相提并论。 - Sven Marnach
3
请参考 PEP 8 中“Designing for inheritance”部分,特别是以“Another category of attributes are those that are part of the "subclass API" (often called "protected" in other languages)"开头的段落。对我来说,该部分描述了受保护属性。许多其他人也这样认为比如这个人。我知道互联网上的文章并不能作为证据。但是,足够多的人都同意这一点,因此按照定义来说这是一种约定,不是吗? - l__flex__l
@l__flex__l:好的,没问题。 :) - Sven Marnach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接