我有一个班级:
class Portfolio:
def __init__(self, value):
self.value = value
class GenericStrategy:
def __init__(self, portfolio: Portfolio):
self.portfolio = portfolio
def modify_ptf_value(new_value):
self.portfolio.value = new_value
# This should return an error
我将编写一些将继承自GenericStrategy
的策略。我希望他们的方法能够读取属性组合但不能修改它,也不能修改它的属性。
我读了一些关于@properties
装饰器的内容,但只有当我不想从外面访问属性(及其属性)时它才有效,我仍然可以修改属性(及其属性)来自方法'内部'物体。
有没有办法使属性(及其属性)'只读' __init__
方法除外?我的设计是错的,应该重新开始吗?我知道用户不得修改" protected"属性,但我想让它成为防弹。任何想法都被广泛接受,即使它需要对课堂设计进行重大改变。
由于
答案 0 :(得分:1)
与其他(常用的)编程语言相反, Python 提供了一种关于访问类/实例成员的新方法。例如,没有什么是真正的私有,字段/方法:
_
开头,是常规字段__
开始(最多只有一个_
),只是名称被破坏,但仍然可以从课外访问(甚至修改/删除)所以,最后它是一个常规问题,并且它依赖于编写代码的人。底线是 nothing 会阻止用户访问类/实例的内部。
注意:在其他语言中,访问私有成员也是可能的:有正式支持的方法(如 Reflection ( {em> Java )的[Oracle]: Trail: The Reflection API),或者不受官方支持(需要一些"技巧" - 例如:reinterpret_cast
class
到struct
与{em> C ++ )具有相同结构的class LockedAttribute(object):
def __init__(self, name):
self._name = name
self._set_count = 0
self._set_treshold = 1
def __get__(self, instance, cls):
return instance.__dict__[self._name]
def __set__(self, instance, value):
if self._set_count >= self._set_treshold:
raise AttributeError("Can't set attribute '{}'".format(self._name))
else:
instance.__dict__[self._name] = value
self._set_count += 1
def __delete__(self, instance):
raise AttributeError("Can't delete attribute '{}'".format(self._name))
class GenericStrategy(object):
portfolio = LockedAttribute("portfolio")
def __init__(self, portfolio):
self.portfolio = portfolio
try:
self.portfolio = portfolio
except AttributeError as e:
print(" ERROR: {}".format(e))
def set_portfolio(self, new_value):
self.portfolio = new_value
if __name__ == "__main__":
strategy = GenericStrategy("some portfolio name")
print("Portfolio: {}".format(strategy.portfolio))
try:
del strategy.portfolio
except AttributeError as e:
print(" ERROR: {}".format(e))
try:
strategy.set_portfolio("some 2nd portfolio name")
except AttributeError as e:
print(" ERROR: {}".format(e))
try:
strategy.portfolio = "some 3rd portfolio name"
except AttributeError as e:
print(" ERROR: {}".format(e))
print("Portfolio: {}".format(strategy.portfolio))
。如今,越来越多的语言倾向于提供一种改变实例结构的方法。
无论如何,有一个所谓的 描述符协议 ([Python]: Descriptor HowTo Guide),它是 Python '之一。最强大(也是最容易被误解)的功能。
使用描述符(作为旁注,属性依赖于它们),我写了一段代码(在某种程度上)实现了你的目标要求:
__
备注强>:
portfolio
)中删除了object
,以避免在我的代码中使用我正在谈论的修改(会使其更难阅读)< / LI>
try/except
。如果兼容性不是强制性的,则可以删除继承关系(默认情况下在 Py3x 中)width
块来说明行为,在生产中应删除它们