类中只读的Python属性

2024-06-28 23:53:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一节课:

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”属性,但我想让它防弹。任何想法都是被广泛接受的,即使它需要在类设计中进行实质性的更改。

谢谢


Tags: 方法selfnew属性initvaluedef策略
1条回答
网友
1楼 · 发布于 2024-06-28 23:53:26

与其他(常用的)编程语言不同,Python提供了一种访问类/实例成员的新方法。例如,没有什么是真正的私有字段/方法:

  • _开头,是常规字段
  • __开始(最多以一个_结束),它们只是名称损坏,但仍然可以从类外部访问(甚至修改/删除)

所以,在最后,这是一个约定的问题,它依赖于编写代码的人会遵循这个约定。归根结底,没有什么可以阻止用户访问类/实例的内部。

<> > En> EME>:在其他语言中,也可以访问私有成员:有正式支持的方法(如<> C++ > EME>反射Ejava ><强>([Oracle]: Trail: The Reflection API),或不支持官方(这需要一些技巧)-例如:^ {< CD4> } {{CD5>},以“{{CD6}},对于C++EEE>相同的结构”。现在,越来越多的语言倾向于提供一种改变实例结构的方法。

总之,有一个所谓的描述符协议,它是Python最强大的(也是最容易被误解的)特性之一。

使用描述符(作为附加注释,属性依赖于它们),我编写了一段代码,在某种程度上实现了您的要求:

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))

注意:

  • 我从private属性的名称(portfolio)中删除了__,以避免在代码中使用我所说的损坏(这将使阅读更加困难)
  • 对于Py27兼容性,类继承object。如果兼容性不是必需的,则可以删除继承关系(默认情况下在Py3x中)
  • 我添加了try/except块来说明行为,在production中应该删除它们
  • 如上所述,如果有人想改变这种行为,可以

相关问题 更多 >