【问题标题】:Convert Instance Fields into Properties [closed]将实例字段转换为属性 [关闭]
【发布时间】:2019-11-01 22:37:25
【问题描述】:

我想将对象的所有实例字段转换为属性(仅限 getter),以使它们只读。这些字段可能由子类定义。

我怎样才能做到这一点?

class SomeClass(object):

    def __init__(self, foo, bar):

        self.foo = foo
        self.bar = bar

        convert_all_instance_fields_into_properties(self)   # implementation ?

【问题讨论】:

    标签: python properties python-decorators readonly-attribute


    【解决方案1】:

    Python 中没有“私有”之类的东西。如果你愿意并且足够努力,你可以提取任何东西。

    半私有有2个级别:

    • 一个下划线前缀供内部使用,通常可在外部访问 - 但大多数 IDE 会在其下划线并警告不推荐的做法
    • 伪私有的两个下划线前缀,如果有人真的想要它仍然可以访问但丑陋

    大多数时候,您只需要一个下划线 - 人们只有在他们认为他们真正需要时才会访问它。

    在我正在使用的代码中,我看到两个下划线仅用作封装延迟加载的属性的一种方式(一个下划线是“getter”并检查变量是否已加载)。

    请记住,即使使用“getter”,您也将返回一个对象,除非您自己返回一个副本。重新思考你的设计,用 Python 思考,而不是“私有”和“getters”。 ;)


    编辑:

    好像我误解了这个问题。

    标有@property装饰器的函数将返回不带括号的函数来调用它们(spam.eggs,而不是spam.eggs())并且是“只读的”(你可以做bacon = spam.eggs但不能做spam.eggs = bacon)。

    但我的其余评论仍然有效:

    • 只要有足够的决心,一切都可以访问
    • 使用下划线很好地要求人们不要访问该值
    • 如果你的 getter 属性返回一个可变对象,它在内部仍然是可变的(只有引用保持不变),例如eggs.list = [] 不起作用,但 eggs.list.append("spam") 会!

    【讨论】:

    • 您在这里混淆了 privateread-only。我希望它是公开的但只读的。 IE。 a = obj.foo 有效,但 obj.foo = 2 无效。
    • 编辑了我的答案以解决只读部分。对我来说太早了。
    • 谢谢。我知道你指出的所有问题。但这不是答案。答案是:你就是这样做的不可能。如果您认为它的风格不好,很公平,请将其放在评论中。请让它成为一个真实的答案,否则我将不得不标记它。
    • 我解释了如何你可以做一些类似你想要的。而且总会有一种方法可以访问和更改您的“只读”变量。在我的编辑中,我解释了 @property 装饰器是如何工作的(举例说明什么可行,什么不可行)。你还想要什么?您不能“转换”问题中的内容,您必须以 Python 方式编写代码并使用我给您的内容。
    • 您可以将其转换为您可以删除该字段(我知道这是可能的),并添加一个属性(也可能)。我想要的是人们给我一个问题的答案,而不是其他问题的答案(无论它是否是 Pythonic)。并且能够进行民间讨论,谢谢。
    【解决方案2】:

    使用 python 内置函数很容易实现只读字段:

    class X:
    
        def __init__(self, val):
            self.foo = val
    
        def __setattr__(self, key, value):
            if not hasattr(self, key):  # only for first set
                super(X, self).__setattr__(key, value)
            else:
                raise ValueError
    
    
    def main():
        x = X('bar')
        y = X('baz')
    
        assert x.foo == 'bar'
        assert y.foo == 'baz'
    
        # raises ValueError
        x.foo = 'Raise an error!'
    

    如果要指定哪些字段是只读的

    class X:
    
        readonly = ['foo']
    
        def __init__(self, val):
            self.foo = val
    
        def __setattr__(self, key, value):
            if key in self.readonly and not hasattr(self, key):
                super(X, self).__setattr__(key, value)
            else:
                raise ValueError
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-05
      • 1970-01-01
      • 2019-12-30
      • 2013-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多