Python 2.7: How to build getter/setter functions to access class attributes without inheritance?
这可能是一个超级裸体问题,抱歉。我正试图在我熟悉的Python中从PHP中获得一种效果,它正在为私有属性构建getter和setter函数。
在PHP中,我通常会这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
class newClass () {
private $var = null;
function newClass ($initVal) {
//init
}
public function get ($var) {
if ( isset($this->$var) ) {
return $this->$var;
}
}
}
?> |
但是,在python中尝试同样的想法:
1 2 3 4 5 6 7 8 9 10
| 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的人来说,从他们可能无意中提出的其他语言中学习哪些约定似乎很有用。但实际上,我最初的问题有点不同,在试图使问题更普遍的时候,我混淆了我的实际需要。所以这里有一个修正案:
事实上,我没有处理私有属性;事实上,我正在处理如何通过组合环境向下传递属性。IE:
Class A作为一个属性,有一个不从Class A继承的Class B对象。Class B几乎不需要来自Class A的任何信息,但在我的项目中,有一种情况是,如果用户选择不向Class B提供信息,则会有一个声明试图推断出合理的解决方案,但它需要来自Class A的信息,通常情况下,我会不需要。
我可以构建Class B来一直拥有这些信息,但这意味着我几乎总是在浪费时间和记忆(尽管可能是微不足道的)。要使其具体化,请想象一下:
toothbrush有bristles和bristles可以,只要用户提供首选的刷牙体验,创建一个适合"软"或"硬"刷的刷毛数量。但是,如果用户不提供,那么我想让bristles向brush询问它的表面积,让它可以猜测平均值应该是多少。
我想到了这一点,尽管我有一种直觉,那就是Python程序员会因此而讨厌我;我只是想理解为什么:
1 2 3 4 5 6 7
| @staticmethod
def request(self, var):
appIndex = self.__dict__
if appIndex[var]:
return appIndex[var]
print Class.request(instance, var) |
很有魅力,但我认为这是Python异端。为什么?
- 在这样做之前,您应该问自己两个问题:1)为什么使用私有属性?2)为什么要使用getter/setter函数?这两种方法都不是很Python式的,通常有更好的方法来用Python完成任务。第三个问题是,您不必检查是否设置了变量,而应该始终首先将其设置为某个默认值,然后检查它,而不是检查它是否"设置了"。
- 不,它不会;此代码将抛出一个SyntaxError,而不是因为__init__没有def。即使存在这种情况,__var也不会抛出属性错误,因为它像__init__中的引用一样被损坏。
- 请记住,在Python中没有真正的私有变量……
- @MartijnPieters是的,你是对的,但这并不是问题所在,我很明显使用了问题的一般形式来遵循StackOverflow约定,即对每个人都有用。所以,感谢您指出了一个非常、非常、非常明显和微不足道的问题,这个问题不可能引发我在问题中实际提到的错误,但是,尽管我对Python还不熟悉,但我知道如何定义函数。但是,嘿,你肯定抓到我了,很好的工作守则,警察。
- @琼琳:更重要的是,你声称代码会使我有问题的AttributeError,因为它没有。我试着运行你的代码来验证我没有读错。您在询问有关特定代码段的问题,所以也许您应该测试代码,说明该代码的作用?
- 如果没有,那是因为一些微不足道的原因,但我把它改得更清楚了。就我个人而言,我仍然认为我所问的问题是一般的、显而易见的,而这一页上的其他回答也证实了这一点。如果你不得不运行这个代码来理解这个问题,那么这可能不是你应该回答的问题。我不是不感激你的帮助,我是,但没有其他人有任何困难理解我的观点。我本可以复制和粘贴自己的代码,但选择了为其他人以一般的方式编写代码。抱歉,这不是完美的,但它确实传达了这一点。
- 可能是使用getter和setter的Python方法的复制品?
你要找的是properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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) |
输出:
1 2 3
| in the setter:
in the getter:
2 |
号
- 啊。我懂了。感谢您不仅告诉我我现在意识到您应该说的话,也就是"阅读一下如何在Python中完成面向对象的编程"。非常感谢,啊哈。
- @jonline:"如何在Python中完成面向对象的编程"是指数据属性是对象接口的一部分。除非绝对必要,否则不要使用getter和setter。必要时,使用@property将getter和setter从接口中隐藏。如果您从中得到的教训是"我应该使用@property为每个属性构建getter和setter",那么您所做的事情就越是错误。
- @谢谢,这是我非常感激的建议。我以私有属性为基础做了一个例子,因为当时看起来是这样的!通常更有用。事实上,我真正的问题是构建一个函数,允许没有共享继承的兄弟类(除了作为一个对象之外)彼此请求(偶尔)属性。你能指出你为学习Py的OOP约定推荐的资源吗?
- @对于你的第一个问题,你想要的已经是,应该是,允许的。这是避免打字的关键。就99%的代码而言,对象的"类型"或"接口"不是它的类,而是它支持的成员/方法/运算符集。因此,一个类不必与另一个类有继承关系,甚至不必知道另一个类的存在;它只需要使用另一个类隐式指定的隐式契约。你不在乎某个东西是否与list有关,只是为了它能被订阅,对吧?好吧,这就是一切应该如何运作的。
- @jonline:对于您的第二个问题,遗憾的是,除了基础知识(PEP 8和EDOCX1中的内容(3))和最新/最酷的东西(例如,David Beazley在发电机管道上的演示,Greg Ewing从教程中获得的收益,…)之外,我不知道有什么好的资源来学习Python的OOP约定,或者几乎任何领域。我甚至想不出你在哪里可以有效地问这个问题(因此,它几乎肯定会被关闭,可能会被否决,因为这不适合问答格式)。很抱歉。
- @Abarner感谢你的指点,这是像我这样的业余爱好者从中受益的一种东西,因为现在我对哪些东西有了更好的理解——明确地说——我需要继续学习;我总是发现最困难的部分不是学习,而是找到要学的东西。如俗话所说,我真的很感激你花时间"教人钓鱼"。
首先,python没有私有变量。你所指的是名字——马格林。目的是在导入模块时防止名称冲突。每当你在一个前面有两个下划线的类中编写一个变量时,该类的名称就会添加到它的前面。因此,最好将变量命名为"EDOCX1"(1),这是Python"private"事物的定制。
另一方面,在Python中,如果希望一些ON能够设置和获取变量,通常只允许直接访问(与Java或其他语言不同)是最有意义的。
- "__magic__名称保留用于实现(即python实现)。"private"的pythonic命名约定(如"none of your concerns,warranty void if unsealed")属性是"_single_leading_下划线"
- 可以。我想我没有在那画出区别,但这是一个很好的区别。