从 getter/setter 到属性的自动转换

发布于 2024-08-21 23:51:02 字数 453 浏览 1 评论 0原文

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

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

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

I have a big library written in C++ and someone created an interface to use it in python (2.6) in an automatic way. Now I have a lot of classes with getter and setter methods. Really: I hate them.

I want to re-implement the classes with a more pythonic interface using properties. The problem is that every class has hundreds of getters and setters and I have a lot of classes. How can I automatically create properties?

For example, if I have a class called MyClass with a GetX() and SetX(x), GetY, SetY, etc... methods, how can I automatically create a derived class MyPythonicClass with the property X (readable if there is the getter and writable if there is the setter), and so on? I would like a mechanism that lets me to choose to skip some getter/setter couples where it is better to do the work by hand.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

随波逐流 2024-08-28 23:51:02

这是使用类装饰器的方法

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

Here's a way to do it with a class decorator

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

Here is a slightly more complicated version that allows you to specify a list of items to skip

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
心碎无痕… 2024-08-28 23:51:02

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

Use a metaclass that looks for all attributes like Get* and Set* and adds appropriate properties to the class. Have a class attribute that you can set to a sequence containing properties that will be skipped. See this answer for details about setting attributes in the class.

云柯 2024-08-28 23:51:02

使用魔法时要小心,尤其是用魔法改变他人的束缚。这样做的缺点是

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

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

Be careful using magic, especially magically altering other people's bindings. This has the disadvantages that

  • Your code is incompatible with other people accessing the same library. Someone can't import one of your modules or copy and paste your code and have it work perfectly with their program accessing the same library, and
  • Your interface is different from the interface to the C++ code. This would make sense if your wrapper gave you a nicer, higher-level interface, but your changes are only trivial.

Consider whether it wouldn't make more sense just to deal with the library you are using as it came to you.

梦开始←不甜 2024-08-28 23:51:02
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
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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文