Python - 在调用时转换类属性

时间:2018-04-10 11:50:34

标签: python python-3.x class getattr class-attributes

假设我有以下课程

class Headings:
    standard_heading = {
        'height': 3.72,
        'width': 25.68,
        'left': 1.65,
        'top': 0.28
    }

作为一个例子,我想要以下结果,其中所有值都乘以10:

Headings.standard_heading

>>> {
            'height': 37.2,
            'width': 256.8,
            'left': 16.5,
            'top': 2.8
        }

是否无法通过向类添加类似于此类的方法来覆盖类属性的调用:

def __getattribute__(cls, attr):
    return {k:v*10 for k,v in attr.items()

我永远不会创建这个类的实例。我只是用它来分组。

由于

3 个答案:

答案 0 :(得分:3)

你几乎拥有它 - 只需将getter定义为类方法(也有一个小的语法错误,attr这里是一个字符串):

class Headings:
    standard_heading = {
        'height': 3.72,
        'width': 25.68,
        'left': 1.65,
        'top': 0.28
    }          
    @classmethod
    def __getattribute__(cls,attr):
        return {k:v*10 for k,v in cls.__dict__[attr].items()}

print(Headings().standard_heading)

请注意,您需要一个实际的实例来实现此功能,但这就是您在示例中使用的实例。这也会破坏在对象的任何方法中定义的对象特定字段的属性(例如__init__),所以要小心这一点。一个简单的解决方法是覆盖:

@classmethod
def __getattribute__(cls,attr):
    try:
        return {k:v*10 for k,v in cls.__dict__[attr].items()}
    except: raise AttributeError(attr)
def __getattr__(self,attr):
    return object.__getattribute__(self,attr)

现在如果你有:

def __init__(self): self.a = 'abc'

然后

print(Headings().a)

也会奏效。说明:

  1. 首先将__getattribute__称为类方法。
  2. 如果不存在类变量,则调用__getattr__,现在作为常规方法调用,所以使用实际对象(和对象成员)。
  3. 致电object __getattribute__以恢复正常行为。
  4. 最后一点 - 除了您的具体问题之外,如果您只想为一个类成员定义一个特殊的getter,那么只会影响所述成员的更安全的方法是使用@property和{{1例如在How does the @property decorator work?中解释了。感谢Adonis指出了这一点。

答案 1 :(得分:1)

如果要将此行为应用于许多不同的类,则可以创建父类。

class MultiplyBy10:
    def __getattribute__(self, attr):
        return {k:v*10 for k,v in super().__getattribute__(attr).items()}

class Headings(MultiplyBy10):
    standard_heading = {
        'height': 3.72,
        'width': 25.68,
        'left': 1.65,
        'top': 0.28
    }

h = Headings()
print(h.standard_heading)

将显示

{'height': 37.2, 'width': 256.8, 'left': 16.5, 'top': 2.8000000000000003}

答案 2 :(得分:0)

如果您的要求是更改字典中返回的值,则无法创建另一个字典,您可能需要构建自定义字典 ​​- How to "perfectly" override a dict?