【问题标题】:Automatic transformation from getter/setter to properties从 getter/setter 到属性的自动转换
【发布时间】:2011-01-17 14:54:48
【问题描述】:

我有一个用 C++ 编写的大型库,有人创建了一个接口以自动方式在 python (2.6) 中使用它。现在我有很多带有 getter 和 setter 方法的类。真的:我讨厌他们。

我想使用属性重新实现具有更 Pythonic 接口的类。问题是每个类都有数百个 getter 和 setter,而我有很多类。如何自动创建属性?

例如,如果我有一个名为MyClass 的类具有GetX()SetX(x)GetYSetY 等...方法,我如何自动创建派生类MyPythonicClass使用属性X(如果有getter则可读,如果有setter则可写),等等?我想要一种机制,让我可以选择跳过一些最好手动完成工作的 getter/setter 组合。

【问题讨论】:

    标签: python properties metaprogramming automatic-properties


    【解决方案1】:
    class BaseObj:
        test = None
        def __init__(self, attributes_dict):
            self.attributes_dict = attributes_dict
            self.define_getters(attributes_dict.keys())
        def define_getters(self, attributes_names):
            for attribute_name in attributes_names:
                setattr(self, "get_"+attribute_name, self.getter_factory(attribute_name))
        def getter_factory(self, attribute_name):
            """Method for generating getter functions"""
            def getter():
                return self.attributes_dict[attribute_name]
            return getter
    
    class DerivedObj(BaseObj):
        attributes_keys = ['name']
        def __init__(self, attributes_dict):
            BaseObj.__init__(self, attributes_dict)
    
    a = DerivedObj({'name':'kuku'})
    a.get_name()  # -> kuku
    

    【讨论】:

      【解决方案2】:

      小心使用魔法,尤其是用魔法改变其他人的绑定。这样做的缺点是

      • 您的代码与访问同一库的其他人不兼容。有人无法导入您的模块或复制和粘贴您的代码并使其与访问同一库的程序完美配合,并且
      • 您的接口与 C++ 代码的接口不同。如果您的包装器为您提供了更好、更高级别的界面,这将是有意义的,但您的更改只是微不足道的。

      考虑一下,只处理你正在使用的库是否更有意义。

      【讨论】:

      • 你说得对,但这不是一个很大的问题,我不是为其他人开发的,我正在创建这个接口,因为我不喜欢 getter/setter 接口(也在 C++ )。我的接口扩展了旧接口,不是替代,getter/setter方法还在。
      【解决方案3】:

      这是一种使用类装饰器的方法

      def make_properties(c):
          from collections import defaultdict
          props=defaultdict(dict)
          for k,v in vars(c).items():
              if k.startswith("Get"):
                  props[k[3:]]['getter']=v
              if k.startswith("Set"):
                  props[k[3:]]['setter']=v
          for k,v in props.items():
              setattr(c,k,property(v.get('getter'),v.get('setter')))
          return c
      
      @make_properties
      class C(object):
          def GetX(self):
              print "GetX"
              return self._x
      
          def SetX(self, value):
              print "SetX"
              self._x = value
      
      c=C()
      c.X=5
      c.X
      

      这是一个稍微复杂的版本,允许您指定要跳过的项目列表

      def make_properties(skip=None):
          if skip is None:
              skip=[]
          def f(c):
              from collections import defaultdict
              props=defaultdict(dict)
              for k,v in vars(c).items():
                  if k.startswith("Get"):
                      props[k[3:]]['getter']=v
                  if k.startswith("Set"):
                      props[k[3:]]['setter']=v
              for k,v in props.items():
                  if k in skip:
                      continue
                  setattr(c,k,property(v.get('getter'),v.get('setter')))
              return c
          return f
      
      @make_properties(skip=['Y'])
      class C(object):
          def GetX(self):
              print "GetX"
              return self._x
      
          def SetX(self, value):
              print "SetX"
              self._x = value
      
          def GetY(self):
              print "GetY"
              return self._y
      
          def SetY(self, value):
              print "SetY"
              self._y = value
      
      c=C()
      c.X=5
      c.X
      c.Y=5
      c.Y
      

      【讨论】:

        【解决方案4】:

        使用metaclass 查找所有属性,例如Get*Set*,并向类添加适当的属性。有一个类属性,您可以将其设置为包含将被跳过的属性的序列。有关在类中设置属性的详细信息,请参阅this answer

        【讨论】:

        • 我不是很专业,你能给我一个具体的例子吗?
        • 您不必为此使用元类。定义__getattr____setattr__ 的代码可能更容易理解。您可以通过继承将它们带入您的类中。
        猜你喜欢
        • 2014-09-05
        • 2012-09-09
        • 2015-08-24
        • 1970-01-01
        • 2019-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-06
        相关资源
        最近更新 更多