首页 > 解决方案 > 动态创建类的属性

问题描述

看看这个代码片段:

class Face():
    pass

class Cube():
    def __init__(self):
        self.faces = {
                'front': Face(1),
                ...
                }

    @property
    def front(self):
        return self.faces['front']

    @front.setter
    def front(self, f):
        pass

我已经为所有的面孔创建了 getter 和 setter。有没有办法让这段代码更紧凑,也许是通过动态创建getter和setter?

标签: pythonoopdynamicproperties

解决方案


以下代码假设您

  • 有理由拥有self.facesdict 而不是front直接在实例上设置属性

  • 和/或想要为self.faces.

否则,此练习毫无意义,因为正如 Corentin Limier 指出的那样,您可以简单地设置self.front = Face(1),依此类推。


您可以使用描述符、保存人脸名称的类变量和类装饰器。将描述符视为可重用的属性。

在下面的示例代码中,我添加了一个num实例变量Face和 face'side'仅用于演示目的。

class FaceDescriptor:
    def __get__(self, instance, owner):
        # your custom getter logic

        # dummy implementation
        if instance is not None:                
            return instance.faces[self.face]

    def __set__(self, instance, value):
        # your custom setter logic

        # dummy implementation
        instance.faces[self.face] = value

def set_faces(cls):
     for face in cls._faces:
         desc = FaceDescriptor()
         desc.face = face
         setattr(cls, face, desc)
     return cls

class Face():
    def __init__(self, num):
        self.num = num   

@set_faces
class Cube():
    _faces = ['front', 'side']

    def __init__(self):
        self.faces = {face:Face(i) for i, face in enumerate(self._faces, 1)}

在行动:

>>> c = Cube()                                                                                                                                                                                         
>>> c.front.num                                                                                                                                                                                         
1
>>> c.side.num                                                                                                                                                                                          
2
>>> c.front = 'stuff'                                                                                                                                                                                   
>>> c.front                                                                                                                                                                                             
'stuff'
>>> c.faces                                                                                                                                                                                             
{'front': 'stuff', 'side': <__main__.Face at 0x7fd0978f37f0>}

推荐阅读