绕过Python';不经意间的私人属性

绕过Python';不经意间的私人属性,python,python-3.x,class,oop,encapsulation,Python,Python 3.x,Class,Oop,Encapsulation,我使用以下代码绕过了setter: t = TrajetGPS() # will call t.getPoints(), which will return the list by reference # we can then modify it at will, bypassing the setter points = t.points points.append(PointGPS(0, 0, 0)) points.append(PointGPS(1, 1, 1)) print(t

我使用以下代码绕过了setter:

t = TrajetGPS()

# will call t.getPoints(), which will return the list by reference
# we can then modify it at will, bypassing the setter
points = t.points 
points.append(PointGPS(0, 0, 0))
points.append(PointGPS(1, 1, 1))


print(t) # will show : Points : (0, 0, 0) (1, 1, 1)
TrajetGPS()。但这一切在这里都无关紧要

我可以在没有警告的情况下绕过设定器,这正常吗?


Python被设计为对初学者友好,但这似乎不是很友好,因为它可以很快地将格式错误的数据插入列表(不知道!)。

Python对初学者并不特别友好,但有一条规则是,所有未明确禁止的内容都是允许的,很少有东西是禁止的。可变类型是可变的,完全停止。如果API返回一个内部可变对象,它将隐式地允许API用户修改该对象

尽管如此,这可能是个问题,也可能不是。通常只需记录不支持修改对象并可能导致意外行为就足够了


它通常比试图阻止API用户的错误操作更具python风格。毕竟,猴子补丁是允许的,就像使用任何所谓的类的私有成员一样,只要你能猜出它们的名字。

Python对初学者并不特别友好,但有一条规则是,所有没有明确禁止的东西都是允许的,很少有东西是禁止的。可变类型是可变的,完全停止。如果API返回一个内部可变对象,它将隐式地允许API用户修改该对象

尽管如此,这可能是个问题,也可能不是。通常只需记录不支持修改对象并可能导致意外行为就足够了

它通常比试图阻止API用户的错误操作更具python风格。毕竟,猴子补丁是允许的,就像使用类的任何所谓私有成员一样,只要你能猜出它们的名字。

你实际上不是在“绕过setter”——setter在你试图设置
t.points
(即:
t.points=[]
)时被调用,而不是在你改变setter返回的列表时被调用

如果您不想让客户机代码改变列表,可以返回一些不可变的结构(这将表明它不应该被更改),或者至少返回列表的一个副本(该副本仍然是可变的,但是修改不会影响原始列表-请注意,这可能会让您的代码用户感到惊讶)

注意:在您的代码片段中有以下注释:

它将通过引用返回列表

如果您希望用Python完成任何事情,请停止用其他语言来思考,转而理解Python是如何工作的。Python中没有“按引用”或“按值”这样的东西,只有名称和对象。您的getter不会“通过引用返回列表”,而是返回列表,句号。我强烈建议您(是的,蹩脚的双关语,对不起)更多地了解Python的名称和对象概念。

您实际上并没有“绕过setter”——setter是在您试图设置
t.points
(即:
t.points=[]
)时调用的,而不是在您改变setter返回的列表时调用的

如果您不想让客户机代码改变列表,可以返回一些不可变的结构(这将表明它不应该被更改),或者至少返回列表的一个副本(该副本仍然是可变的,但是修改不会影响原始列表-请注意,这可能会让您的代码用户感到惊讶)

注意:在您的代码片段中有以下注释:

它将通过引用返回列表


如果您希望用Python完成任何事情,请停止用其他语言来思考,转而理解Python是如何工作的。Python中没有“按引用”或“按值”这样的东西,只有名称和对象。您的getter不会“通过引用返回列表”,而是返回列表,句号。我强烈建议您(是的,蹩脚的双关语,对不起)更多地了解Python的名称和对象概念。

Python无法避免您在不将手臂绑在背后的情况下自食其力,这也不会产生任何效果。如果要确保不可变,请从属性返回不可变的数据结构,或返回列表的副本。决定返回其私有成员的是类,而不是调用方。为属性赋值和更改属性值是两回事。setter可以阻止您执行前者,但不能执行后者——因为您没有设置属性,而是在修改属性。需要注意的是,Python没有私有属性。由于答案有注释,这与“绕过设定者”无关。即使在像Java这样的语言中,私有访问修饰符被强烈地强制执行,如果你的属性是一个你改变的对象,那么这种改变将在属性所属的实例中被看到。Python不能避免你在不把手臂绑在背后的情况下自食其果,这也不会产生任何效果。如果要确保不可变,请从属性返回不可变的数据结构,或返回列表的副本。决定返回其私有成员的是类,而不是调用方。为属性赋值和更改属性值是两回事。setter可以阻止您执行前者,但不能执行后者——因为您没有设置属性,而是在修改属性。需要注意的是,Python没有私有属性。由于答案有注释,这与“绕过设定者”无关。即使在像Java这样具有强强制私有访问修饰符的语言中,如果您的属性是一个经过修改的对象,那么该更改将在该属性所属的实例中看到。