我应该如何公开Python类中的只读字段?

发布于 2021-01-29 15:14:28

我有许多不同的小类,每个小类都有几个字段,例如:

class Article:
    def __init__(self, name, available):
        self.name = name
        self.available = available

name字段设为只读的最简单和/或最惯用的方法是什么,以便

a = Article("Pineapple", True)
a.name = "Banana"  # <-- should not be possible

不可能了吗?

到目前为止,这是我考虑的内容:

  1. 使用吸气剂(嗯!)。
    class Article:
    def __init__(self, name, available):
        self._name = name
        self.available = available
    
    def name(self):
        return self._name
    

丑陋的,非pythonic的-以及很多要编写的样板代码(特别是如果我有多个要设置为只读的字段)。但是,它确实可以胜任工作,而且很容易明白为什么会这样。

  1. 用途__setattr__
    class Article:
    def __init__(self, name, available):
        self.name = name
        self.available = available
    
    def __setattr__(self, name, value):
        if name == "name":
            raise Exception("%s property is read-only" % name)
        self.__dict__[name] = value
    

在调用方看来很漂亮,这似乎是完成工作的惯用方式-
但不幸的是,我有很多类,只有几个字段可以使每个字段只读。因此,我需要__setattr__为所有这些添加实现。还是使用某种mixin?无论如何,如果客户端尝试将值分配给只读字段,我将需要下定决心。我猜会产生一些例外-
但是哪个呢?

  1. 使用实用程序功能自动定义属性(以及可选的吸气剂)。这与(1)基本上是相同的想法,除了我没有明确地写出吸气剂而是做类似的事情
    class Article:
    def __init__(self, name, available):
        # This function would somehow give a '_name' field to self
        # and a 'name()' getter to the 'Article' class object (if
        # necessary); the getter simply returns self._name
        defineField(self, "name")
        self.available = available
    

缺点是我什至不知道这是否可能(或如何实现),因为我不熟悉Python中的运行时代码生成。:-)

到目前为止,(2)对我来说似乎最有前途,除了我需要__setattr__为所有班级定义之外。我希望有一种“注释”字段的方法,以便自动进行。有人有更好的主意吗?

对于它的价值,我要使用Python 2.6。

更新: 感谢所有有趣的回复!现在,我有了这个:

def ro_property(o, name, value):
    setattr(o.__class__, name, property(lambda o: o.__dict__["_" + name]))
    setattr(o, "_" + name, value)

class Article(object):
    def __init__(self, name, available):
        ro_property(self, "name", name)
        self.available = available

这似乎工作得很好。对原始课程的唯一更改是

  • 我需要继承object(我想这绝对不是一件愚蠢的事情)
  • 我需要更改self._name = namero_property(self, "name", name)

这对我来说看起来很整洁-有人可以看到它的缺点吗?

关注者
0
被浏览
43
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    我将property用作装饰器来管理您的getter
    name(请参阅Parrot文档中该类的示例)。使用例如:

    class Article(object):
        def __init__(self, name, available):
            self._name = name
            self.available = available
    
        @property
        def name(self):
            return self._name
    

    如果未定义name属性的设置器(x.setter在函数周围使用装饰器),则AttributeError在尝试重置时会抛出name

    注意 :必须使用Python的新型类(即,在python
    2.6中必须从继承object),属性才能正常工作。
    @SvenMarnach则不是这种情况。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看