【问题标题】:Python 2.7: How to build getter/setter functions to access class attributes without inheritance?Python 2.7:如何构建 getter/setter 函数以在不继承的情况下访问类属性?
【发布时间】:2023-09-04 11:56:01
【问题描述】:

这可能是一个超级小问题,抱歉。我正在尝试在 Python 中实现我熟悉的 PHP 效果,它正在为私有属性构建 getter 和 setter 函数。

在 PHP 中,我通常会这样做:

<?php
class newClass() {
    private $var = null;

    function newClass($initVal) {
        //init
    }

    public function get($var) {
        if ( isset($this->$var) ) {
            return $this->$var;
        }
    }
}
?>

但是,在 Python 中尝试同样的想法:

class newClass():
    def __init__(self, initVal):
        self.__nameOfVar1 = initVal
        self.__nameOfVar2 = initVal


    def get(self, var):
                #assuming, when called, var = nameOfVar1
        if self.__var:
            return self.__var

抛出错误AttributeError:'newClass' object has no attribute '__var'

完全正确,事实并非如此。如何构建 getter 和 setter 函数来访问私有属性?


更新:

我留下了最初的问题,因为这对于 Python 新手来说似乎很有用,可以了解他们可能不小心引入的其他语言的哪些约定。但实际上,我最初的问题有点不同,在试图使问题更普遍时,我混淆了我的实际需求。所以这里有一个修正:

事实上,我并没有使用私有属性;事实上,我正在处理试图通过组合环境向下传递属性。即:

Class A,作为一个属性,有一个不继承自 Class AClass B 对象。 Class B 几乎从来没有需要来自 Class A 的任何信息,但是在我的项目中,有一种情况,如果用户选择不向 Class B 提供信息,则有一个声明是最后一搏试图推断出一个合理的解决方案,但它需要来自Class A 的信息,通常情况下,它永远不需要。

我可以构建Class B 以始终拥有该信息,但这意味着我几乎总是在浪费时间和内存(尽管它可能是微不足道的)。为了具体化,想象一下:

toothbrushbristlesbristles 可以,只要用户提供首选的刷牙体验,创建适合“软”或“硬”刷子的刷毛数量。但是,如果用户不提供此信息,那么我希望 bristlesbrush 询问它的表面积,让它猜测平均数应该是多少。

我想出了这个,尽管我直觉 Python 程序员会因此而讨厌我;我只是想了解原因:

@staticmethod
def request(self, var):
    appIndex = self.__dict__
    if appIndex[var]:
        return appIndex[var]

print Class.request(instance, var)

就像一个魅力,但我认为这是 Python 的异端邪说。 为什么?

【问题讨论】:

  • 在做这件事之前你应该问自己两个问题:1)你为什么要使用私有属性? 2) 你为什么使用 getter/setter 函数?这两者都不是非常 Pythonic,通常有更好的方法可以在 Python 中完成您的任务。第三个问题是,不要检查变量是否已设置,而应始终将其初始设置为某个默认值,然后检查它而不是检查它是否“已设置”。
  • 不,不会的;这段代码将抛出一个SyntaxError,因为__init__ 没有def。即使存在,__var 也不会引发属性错误,因为它与 __init__ 中的引用一样是 mangled
  • 请记住,在 python 中没有真正的私有变量这样的东西......
  • @MartijnPieters 是的,你是对的,但这真的不是问题,我真的很明显使用问题的一般形式来遵循关于对每个人有用的 * 约定。所以,感谢您指出这个非常非常明显和微不足道的问题,它不可能抛出我在问题中实际提到的错误,但是,虽然我是 python 新手,但我确实知道如何定义一个函数。但是,嘿,你肯定得到了我,好工作代码警察。
  • @Jonline:你声称代码会抛出AttributeError 我有问题,因为它没有。我试图运行你的代码来验证我没有读错。你问的是关于一段特定代码的问题,所以也许你应该测试代码,说明该代码的作用?

标签: php python oop getter getter-setter


【解决方案1】:

你要搜索的是properties:

class Foo():
    def __init__(self):
        self._spam = 0

    @property
    def spam(self):
        print("in the getter: ")
        return self._spam

    @spam.setter
    def spam(self, move):
        print("in the setter: ")
        self._spam = move + self._spam

f = Foo()
f.spam = 2
print(f.spam)

输出:

in the setter: 
in the getter: 
2

【讨论】:

  • 啊。我懂了。感谢您不只是说出我现在意识到您应该说的话,那就是“去阅读如何在 python 中完成面向对象编程”。非常感谢,呵呵。
  • @Jonline:“如何在 Python 中完成面向对象的编程”是数据属性是对象接口的一部分。除非绝对必要,否则不要使用 getter 和 setter。当必要时,使用@property 从界面中隐藏getter 和setter。如果您从中吸取的教训是“我应该使用 @property 为每个属性构建 getter 和 setter”,那么您做的事情就尽可能的错了。
  • @abarnert 谢谢,这是我非常感激的建议。我基于私有属性做了一个例子,因为这似乎(当时!)更可能普遍有用。事实上,我真正的问题是构建一个函数来允许没有共享继承(除了作为对象之外)的兄弟类相互请求(在罕见场合)属性。您能否指出您推荐的用于学习 Py 的 OOP 约定的资源?
  • @Jonline:对于您的第一个问题,您想要的已经并且应该被允许。这是鸭子打字的关键。就 99% 的代码而言,对象的“类型”或“接口”不是它的类,而是它支持的一组成员/方法/运算符。因此,一个类不必与另一个类有任何继承关系,甚至不必知道另一个类的存在;它只需要使用另一个隐含指定的隐含合同。你不在乎某事是否与list 相关,只是它可以下标,对吧?嗯,这就是一切应该如何运作。
  • @Jonline:对于你的第二个问题,遗憾的是,我不知道有什么好的资源来学习 Python 的 OOP 约定,或者除了基础知识之外的几乎任何领域(PEP 8 和 @987654328 中的内容) @) 和最近/很酷的东西(例如,David Beazley 关于生成器管道的演讲,Greg Ewing 的教程中的收益,......)。而且我什至想不出你可以在哪里有用地问这个问题(在 SO 上,它几乎肯定会被关闭,并且可能会被否决,因为不适合问答格式)。对此感到抱歉。
【解决方案2】:

首先,Python 没有私有变量。您指的是名称修改。目的是在导入模块时防止名称冲突。每当您在一个前面有两个非下划线的类中编写一个变量时,该类的名称就会添加到它的前面。因此,最好将变量命名为“__var__”,这是python“私有”事物的自定义。

然而,另一方面,在 python 中,如果您希望某些 on 能够设置和获取变量,通常只允许直接访问是最有意义的(与 Java 或其他语言不同)。

【讨论】:

  • "__magic__" 名称保留用于实现(即 Python 实现)。 “private”的pythonic命名约定(如“您不关心,如果未密封,保修无效”)属性是'_single_leading_underscore'
  • 好的。我想我没有在那里区分,但这是一个很好的区分。