从getter/setter自动转换为属性

4 投票
4 回答
2698 浏览
提问于 2025-04-15 19:22

我有一个用C++写的大型库,有人创建了一个接口,可以自动在Python(2.6)中使用它。现在我有很多类,每个类都有获取和设置的方法。说实话,我真心不喜欢这些方法。

我想用更符合Python风格的方式,重新实现这些类,使用属性来代替。问题是,每个类都有成百上千个获取和设置的方法,而我有很多类。有没有办法可以自动创建这些属性呢?

举个例子,如果我有一个叫做MyClass的类,它有GetX()SetX(x),还有GetYSetY等等方法,我该如何自动创建一个派生类MyPythonicClass,让它有一个属性X(如果有获取方法就可以读取,如果有设置方法就可以写入),其他的也是这样?我希望有一个机制,可以让我选择跳过一些获取/设置方法的组合,这样我可以手动处理那些更复杂的情况。

4 个回答

1

使用魔法(这里指的是一些特殊的编程技巧)时要小心,特别是当你试图改变别人代码的绑定时。这样做有几个缺点:

  • 你的代码可能和其他人使用的同一个库不兼容。比如说,有人想导入你的模块或者复制粘贴你的代码,但他们的程序却无法和你的代码正常工作,因为它们都在使用同一个库。
  • 你的接口和C++代码的接口不一样。如果你的包装器(就是把复杂的东西变简单的工具)能提供一个更好、更高级的接口,那还说得过去,但如果你做的改动只是一些微不足道的小改动,那就没什么意义了。

考虑一下,直接使用你所用的库,可能会更简单、更有效。

2

使用一个叫做元类的东西,它会查找所有以Get*Set*开头的属性,并为这个类添加合适的属性。你可以设置一个类属性,这个属性可以包含一个列表,用来指定哪些属性需要被跳过。想了解更多关于如何在类中设置属性的内容,可以查看这个回答

9

这里有一种方法可以使用类装饰器来实现

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

撰写回答