一个包装类,只公开它所包装的类的属性的一个子集

2024-05-12 23:38:44 发布

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

我想知道是否有比现在更优雅的方式来公开包装类的属性:

class WrapperClass:
    EXPOSED_ATTRIBUTES = ["a"]

    def __init__(self):
        self.wrapped_class = Foo()

    def print_a(self):
        print(f"The value of a is :{self.wrapped_class.a}")

    def __getattr__(self, item):
        if item in self.EXPOSED_ATTRIBUTES:
            return getattr(self.wrapped_class, item)
        elif item in self.__dict__:
            return getattr(self, item)
        else:
            raise AttributeError


class Foo:
    def __init__(self):
        self.a = 1
        self.b = 2

编辑:我好像不清楚自己的意图。包装类的目的是在我的代码和第三方库之间创建边界。我只想减少暴露在代码中的属性和方法的数量


Tags: 代码inselfreturn属性fooinitdef
1条回答
网友
1楼 · 发布于 2024-05-12 23:38:44

如果您所要做的只是限制公开字段的数量,那么应该利用Python动态生成类的能力。也就是说,创建一个工厂来生成新的类,其中只有公开的字段可用

目前,EXPOSED_ATTRIBUTES查找使用的是数组,并且(相对地)比直接查找慢,因为每次调用__getattr_()时,它都必须迭代整个数组,以确保属性是公开的。通过动态生成一个类,您的访问时间将与任何其他类相同,并且它将为您处理所有AttributeError异常

您可以使用^{}命令来创建新类型(aka:classes)。在您的例子中,您可以编写这样一个简单的工厂函数:

def wrap(wrapped, name, exposed_attributes=[]):
  attributes = {attr:wrapped[attr] for attr in exposed_attributes}
  return type(name, (object,), attributes)

这个应该是这样用的

class SomeClass(object):
  def __init__(self):
    self.name = 'Joe Blow'
    self.age  = 27

WrappedClass = wrap(SomeClass, 'WrappedClass', ['name'])
wrapped_class = WrappedClass()
wrapped_class.name # 'Joe Blow'
wrapped_class.age  # AttributeError

# another wrapper on the same class
AnotherWrappedClass = wrap(SomeClass, 'AnotherWrappedClass', ['age'])
another_wrapped_class = AnotherWrappedClass()
wrapped_class.age  # 27
wrapped_class.name # AttributeError

在代码中,我们使用字典理解来构建属性的dict。每个属性都指向包装类上的一个属性。返回新类型,然后可以创建它的实例。新类上只存在公开的字段,因此尝试访问任何其他属性都会像您所期望的那样抛出AttributeError

相关问题 更多 >