动态创建类的属性

时间:2018-11-30 15:22:54

标签: python oop dynamic properties

看看下面的代码片段:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [name] => one
                    [number] => 051
                )

            [1] => Array
                (
                    [name] => two
                    [number] => 052
                )

            [2] => Array
                (
                    [name] => three
                    [number] => 053
                )

        )

    [1] => Array
        (
            [0] => Array
                (
                    [name] => four
                    [number] => 061
                )

            [1] => Array
                (
                    [name] => five
                    [number] => 062
                )

        )

)

我为所有面孔创建了吸气剂和吸气剂。有没有办法通过动态创建getter和setter来使代码更紧凑?

4 个答案:

答案 0 :(得分:2)

以下代码假定您

  • 有理由拥有self.faces字典,而不是直接在实例上设置front这样的属性

  • 和/或想为self.faces中的键实现一些有意义的getter和setter逻辑。

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


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

在下面的示例代码中,我向numFace的面部添加了'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>}

答案 1 :(得分:0)

假设这是您课堂上的全部工作,您可以做类似的事情

class Cube:
   ...

def __getattr__(self, name):
    return self.faces[name]

def __setattr__(self, name, value):
    self.faces[name] = value

答案 2 :(得分:0)

如果您确实想这样做,可以使用__getattr____setattr__

class Cube:

   ...   

   def __getattr__(self, item):
        return self.faces[item]

   def __setattr__(self, item, value):
        self.faces[item] = value

但是当您在front中设置__init__时,您也可以使其成为普通会员...

答案 3 :(得分:0)

您的代码是多余的,因为实例属性已存储在词典中,该词典是 __ dict __ 属性。我认识到您专注于用更少的行编写代码。保持自己的成长是一个很好的挑战,但是从长远来看,您应该专注于代码的清晰度。

这是不使用属性即可编写代码的简单方法:

df[['C','D']] = df[['A','B']].shift()

df.loc[(df[['C','D']] == 0).all(1), ['C','D']] = np.nan

df.ffill().fillna(0).astype(int)

   A  B  C  D
0  1  1  0  0
1  0  0  1  1
2  2  3  1  1
3  0  0  2  3
4  0  0  2  3
5  5  4  2  3
6  0  3  5  4
7  0  0  0  3

这是封装的宗旨,您应该将“属性”隐藏在“属性”之后。即使在python中没有强烈执行此操作,执行此操作也不是一个坏主意。这是执行此操作的正确方法:

class Face():
    pass

class Cube():
    def __init__(self):
        self.front = Face()
        self.rear = Face()

要在最后回答您的问题,是的,您可以动态创建属性。 https://stackoverflow.com/a/1355444/3368572

但是请记住,应该为特殊情况保留编写动态代码的步骤,因为这会使IDE更加难以遵循程序的流程。如果您按预期使用约定,那么您的代码将对人和您的IDE变得不言自明。