属性子集的只读数据视图(非副本)

早上好

我需要所选属性的数据的只读视图(而不是副本)。我知道这可以通过描述符/或属性来解决,但到目前为止我还不知道如何解决。

如果有更好的方法/模式来解决这个问题,我很乐意学习。

class Data:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c


class View:
    def __init__(self, data, attributes):
        self.attributes = attributes
        self.data = data
        for a in attributes:
            #setattr(self, a, lambda: getattr(data, a))
            setattr(self, a, property(lambda: getattr(data, a)))


    #@property
    #def b(self):
    #    return self.data.b

    def __getattr__(self, item):
        if item in self.attributes:
            return getattr(self.data, item)
        raise AttributeError("can't get attribute")

def test_view():
    data = Data(1, 2, 3)

    mydata = View(data, ['b', 'c'])  # but not a!
    assert mydata.b == 2

    data.b = 9
    assert mydata.b == 9

    with pytest.raises(AttributeError, match="can't set attribute"):
        mydata.b = 10
马丁·彼得斯(Martijn Pieters)

我知道这可以通过描述符/或属性来解决,但到目前为止我还不知道如何解决。

这是不正确的,实际上。

描述符仅在类找到时起作用,而在实例不起作用(属性是描述符的一种类型,因此此处没有区别)。因为您的视图将属性定义为实例数据,所以您无法为这些属性生成属性并将其粘贴到View实例上。所以setattr(self, a, property(lambda: getattr(data, a)))不行,不行。

这不是用描述符解决的问题。坚持__getattr__执行查找,以及__setattr__防止向视图添加属性的相应方法:

class View:
    def __init__(self, source, *attrs):
        self._attrs = set(attrs)
        self._source = source

    def __getattr__(self, name):
        if name in self._attrs:
            return getattr(self._source, name)
        raise AttributeError(f"{type(self).__name__!r} object has no attribute {name!r}")

    def __setattr__(self, name, value):
        # special case setting self._attrs, as it may not yet exist
        if name == "_attrs" or name not in self._attrs:
            return super().__setattr__(name, value)
        raise AttributeError("can't set attribute")

    def __dir__(self):
        return self._attrs

我在这里做了一些修改。属性存储为一组,因此可以测试名称是否是构成视图的属性的一部分,我们可以高效地进行操作。我还实施__dir__使dir(mydata)返回可用属性。

请注意,我还在此处稍作更改了API ,并View()采用了任意数量的参数来定义属性名称。这将使您的测试如下所示:

data = Data(1, 2, 3)

mydata = View(data, 'b', 'c')  # but not a!
assert mydata.b == 2

data.b = 9
assert mydata.b == 9

with pytest.raises(AttributeError, match="can't set attribute"):
    mydata.b = 10

实际上,即使使用元类,也无法为此即时生成描述符,因为实例的属性查询不进行查询,__getattribute__也不__getattr__是在元类上进行(这是一种优化,请参见Special method lookup)。在类上定义的__getattributes____getattr__在类上定义的保留为挂钩点,并且在这两种方法中的任何一个用于绑定它们的属性对象的生成都比此处所需的间接性更多。

如果要创建许多这些View对象,则可能确实要使用__slots__如果使用此选项,则不会__dict__为您的类创建任何描述符,因此实例不会具有任意属性。取而代之的是,命名每个属性可以拥有的属性,Python会为这些属性创建特殊的描述符,并为其值保留空间。由于__dict__赋予实例任意属性所需字典要比为已知数量的属性保留的固定空间占用更多的内存空间,因此可以节省内存。它也带来了副作用,即您无法向View实例添加任何新属性,从而使该__setattr__方法变得不必要:

class View:
   __slots__ = ("_attrs", "_source")

   def __init__(self, source, *attrs):
       self._attrs = set(attrs)
       self._source = source

   def __getattr__(self, name):
       if name in self._attrs:
           return getattr(self._source, name)
       raise AttributeError(f"{type(self).__name__!r} object has no attribute {name!r}")

   def __dir__(self):
       return self._attrs

但是,当您尝试设置属性时,如果没有__setattr__消息AttributeError抛出,则会发生一些变化:

>>> mydata.b = 10
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'View' object has no attribute 'b'

因此您可能仍要保留它。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用数据注释对属性子集进行强制验证

来自分类Dev

只读数据合同

来自分类Dev

将只读数据库副本用于只读GORM方法和条件

来自分类Dev

如何基于仅具有公共属性子集的多个表创建视图?

来自分类Dev

DerivativesApi.GetModelviewProperties 用于属性子集

来自分类Dev

确定类属性是否为只读数据描述符

来自分类Dev

升级只读数据库

来自分类Dev

Neo4j:是否可以创建仅包含数据子集的只读副本?

来自分类Dev

如何实现带有属性子集的类?

来自分类Dev

具有属性子集的对象数组克隆

来自分类Dev

从ES6中的内联属性子集创建对象

来自分类Dev

确定SqlTransaction是写数据还是只读数据

来自分类Dev

只读数据库上的PDO :: exec()不返回

来自分类Dev

如何从资产打开只读数据库

来自分类Dev

以最少的停机时间刷新只读数据库

来自分类Dev

最佳实践:使用Redux处理只读数据

来自分类Dev

在只读数据库中的任何位置查找值

来自分类Dev

在Unity中存储只读数据的良好做法

来自分类Dev

应该将Solr用作只读数据库吗?

来自分类Dev

使用Rspec / Rails模拟只读数据库

来自分类Dev

SQL Server Express版-只读数据库?

来自分类Dev

Django - OperationalError - 尝试编写只读数据库

来自分类Dev

返回带有Spray-json对象属性子集的json响应

来自分类Dev

给定类实例上的属性子集,则随机增加一个

来自分类Dev

打字稿。如何指定对象字面量属性子集的类型?

来自分类Dev

“数据库”已压缩,但不驻留在只读数据库或文件组中

来自分类Dev

如何使用`defineProperty`创建一个只读数组属性?

来自分类Dev

C ++的做法类似于C#的只读数据成员行为

来自分类Dev

System.Data.SQLite.SQLiteException尝试在Windows 8上编写只读数据库

Related 相关文章

  1. 1

    使用数据注释对属性子集进行强制验证

  2. 2

    只读数据合同

  3. 3

    将只读数据库副本用于只读GORM方法和条件

  4. 4

    如何基于仅具有公共属性子集的多个表创建视图?

  5. 5

    DerivativesApi.GetModelviewProperties 用于属性子集

  6. 6

    确定类属性是否为只读数据描述符

  7. 7

    升级只读数据库

  8. 8

    Neo4j:是否可以创建仅包含数据子集的只读副本?

  9. 9

    如何实现带有属性子集的类?

  10. 10

    具有属性子集的对象数组克隆

  11. 11

    从ES6中的内联属性子集创建对象

  12. 12

    确定SqlTransaction是写数据还是只读数据

  13. 13

    只读数据库上的PDO :: exec()不返回

  14. 14

    如何从资产打开只读数据库

  15. 15

    以最少的停机时间刷新只读数据库

  16. 16

    最佳实践:使用Redux处理只读数据

  17. 17

    在只读数据库中的任何位置查找值

  18. 18

    在Unity中存储只读数据的良好做法

  19. 19

    应该将Solr用作只读数据库吗?

  20. 20

    使用Rspec / Rails模拟只读数据库

  21. 21

    SQL Server Express版-只读数据库?

  22. 22

    Django - OperationalError - 尝试编写只读数据库

  23. 23

    返回带有Spray-json对象属性子集的json响应

  24. 24

    给定类实例上的属性子集,则随机增加一个

  25. 25

    打字稿。如何指定对象字面量属性子集的类型?

  26. 26

    “数据库”已压缩,但不驻留在只读数据库或文件组中

  27. 27

    如何使用`defineProperty`创建一个只读数组属性?

  28. 28

    C ++的做法类似于C#的只读数据成员行为

  29. 29

    System.Data.SQLite.SQLiteException尝试在Windows 8上编写只读数据库

热门标签

归档