当前位置: 首页 > 面试题库 >

Python名称修饰

百里雅珺
2023-03-14
问题内容

在其他语言中,有助于产生更好代码的通用准则总是使所有内容都尽可能隐藏。如果不确定变量是私有变量还是受保护变量,最好使用私有变量。

同样适用于Python吗?我是否应该一开始在所有内容上使用两个前导下划线,并且仅在需要时才使它们隐藏程度降低(仅一个下划线)?

如果约定仅使用一个下划线,则我也想知道其基本原理。

这是我对JBernardo的回答所留下的评论。它解释了为什么我问这个问题,以及为什么我想知道为什么Python与其他语言不同的原因:


问题答案:

如有疑问,请将其保留为“ public”-我的意思是,请勿添加任何内容以掩盖你的属性名称。如果你的类具有某些内部值,请不要理会。而不是写:

class Stack(object):

    def __init__(self):
        self.__storage = [] # Too uptight

    def push(self, value):
        self.__storage.append(value)
默认写这个:

class Stack(object):

    def __init__(self):
        self.storage = [] # No mangling

    def push(self, value):
        self.storage.append(value)

这无疑是一种有争议的做事方式。Python的新手只是讨厌它,甚至一些老的Python人士都鄙视了此默认设置-但无论如何它都是默认设置,因此即使你感到不舒服,我也建议你遵循它。

如果你确实要发送消息“无法触摸此!” 对于你的用户,通常的方法是在变量前加一个下划线。这只是一个约定,但人们理解它并在处理此类内容时要格外小心:

class Stack(object):

    def __init__(self):
        self._storage = [] # This is ok but pythonistas use it to be relaxed about it

    def push(self, value):
        self._storage.append(value)

这对于避免属性名称和属性名称之间的冲突也很有用:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

那双下划线呢?好吧,双下划线魔术主要用于避免方法的意外重载以及与超类的属性发生名称冲突。如果你编写一个预期会扩展很多次的类,这将非常有用。

如果你想将其用于其他目的,可以,但是既不推荐也不推荐使用。

编辑:为什么会这样?好吧,通常的Python风格并不强调将事情变成私有的-相反!造成这种情况的原因很多-其中大多数存在争议…让我们看看其中的一些原因。

Python具有属性

如今,大多数OO语言都使用相反的方法:不应该使用的内容应该不可见,因此属性应该是私有的。从理论上讲,这将产生更易于管理,耦合更少的类,因为没有人会不顾一切地更改对象内部的值。

但是,它并不是那么简单。例如,Java类确实有很多的属性和 getter方法,只是得到的值和刚刚制定者设定的值。让我们说,你需要七行代码来声明一个属性-Python程序员会说这不必要地复杂。另外,实际上,你只需编写全部代码即可获得一个公共字段,因为你可以使用getter和setter更改其值。

那么,为什么要遵循这种默认的私有策略?默认情况下只需公开你的属性即可。当然,这在Java中是有问题的,因为如果你决定向属性添加一些验证,那么它将要求你更改所有

person.age = age;

在你的代码中,让我们说,

person.setAge(age);

setAge() 存在:

public void setAge(int age) {
    if (age >= 0) {
        this.age = age;
    } else {
        this.age = 0;
    }
}

因此,在Java(和其他语言)中,默认设置是无论如何都使用getter和setter,因为它们可能很烦人,但是如果你遇到我描述的情况,可以节省很多时间。

但是,由于Python具有属性,因此你不需要在Python中执行此操作。如果你有此类:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self.age = age

然后你决定验证年龄,则无需更改person.age = age代码段。只需添加一个属性(如下所示)

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

如果你可以做到并仍然使用 person.age = age,为什么还要添加私有字段以及getter和setter方法?

(另外,请参阅Python不是Java,而本文则介绍了使用getter和setter的危害。)

一切都是可见的-试图隐藏只会使你的工作复杂化
即使在具有私有属性的语言中,你也可以通过某种反射/自省库来访问它们。人们在框架和解决紧急需求方面做了大量工作。问题在于,自省库只是完成公共属性所用的一种困难方法。

由于Python是一种非常动态的语言,因此将这种负担添加到类中只会适得其反。

无法看到问题- 必须看到
对于Pythonista,封装不是无法看到类的内部,而是避免查看它的可能性。我的意思是说,封装是组件的属性,它使组件可以使用而无需用户担心内部细节。如果你可以使用某个组件而不必担心其实现,那么它将被封装(Python程序员认为)。

现在,如果你以这种方式编写类,就可以使用它而不必考虑实现细节,那么出于某种原因想要查看类内部就没有问题。关键是:你的API应该很好,其余的就是细节。

圭多这么说

好吧,这没有争议:实际上他是这么说的。(寻找“开放和服”。)

这是文化

是的,有一些原因,但没有关键原因。这主要是Python编程的文化方面。坦白说,也可能是另一种方式,但事实并非如此。同样,你可以轻松地反过来问:为什么某些语言默认使用私有属性?出于与Python实践相同的主要原因:因为这是这些语言的文化,每种选择都有其优点和缺点。

由于已经存在这种文化,因此建议你遵循它。否则,__当你在Stack Overflow中提问时,Python程序员会告诉你将其从代码中删除,这会使你感到烦恼:)



 类似资料:
  • 接口说明 修改团队名称 如需调用,请访问 开发者文档 来查看详细的接口使用说明 该接口仅开放给已获取SDK的开发者 API地址 POST /permissions/api/team/v1.0.0/modifyTeamName 是否需要登录 是 请求字段说明 参数 类型 请求类型 是否必须 说明 token string header 是 当前登录用户的TOKEN teamName string f

  • 接口说明 修改团队名称 如需调用,请访问 开发者文档 来查看详细的接口使用说明 该接口仅开放给已获取SDK的开发者 如开启https功能,请求地址的协议应改为https,如:https://www.example.com/wish3dearth/api/access/v1.0.0/getLicenseInfo API地址 POST /permissions/api/team/v1.0.0/modi

  • 怎么修这个东西?我需要“Karetski”用户名而不是“Pavelmetsko”

  • 我正在使用cogs来缩短和组织我的discord机器人。然而,在尝试“事件”cog时,我遇到了一个名称错误,即没有定义changePlaying,尽管它实际上是关于on_ready命令的 我忘了输入discord。ext并因此导入了该文件。B:我已经尝试过在changePlaying事件中更改可能状态列表的位置 嗯,我认为很明显预期的结果是什么,但要澄清机器人应该启动。它确实在线,并听取命令,但状

  • 本文向大家介绍ubuntu (linux)修改网卡名称命令,包括了ubuntu (linux)修改网卡名称命令的使用技巧和注意事项,需要的朋友参考一下 linux 修改网卡 网卡名称eno16777736改为eth0 1.vim /etc/sysconfig/grub 然后,往这个文件中添加“net.ifnames=0 biosdevname=0”内容,如下图所示: 上图中,红框部分是我所添加的内

  • 问题内容: 我刚刚开始学习Python,并在Python中遇到了 “命名空间” 概念。虽然我了解了它的本质,但无法理解这个概念的严重性。 网上的一些浏览显示,反对PHP的原因之一是它没有对名称空间的本地支持。 有人可以解释如何使用名称空间以及此功能如何使编程更好 (不只是在Python中,因为我假设名称空间的概念不限于特定语言)。 我主要来自Java和C编程背景。 问题答案: 命名空间是一种实现范