python使用dataclass数据类有个坑

文章讲述了在使用Python的dataclass创建类时,由于默认的实例化策略导致多个Motor对象共享InPut实例的问题,以及如何通过定义__post_init__方法来实现每个Motor实例独立的InPut实例,以解决id相同的问题。
摘要由CSDN通过智能技术生成

今天在创建数据类时,遇到一个问题。发现数据出现了问题。代码如下:


from dataclasses import dataclass
@dataclass
class InPut:
    start:bool = False
    stop:bool = 0
    fault:bool = None
    interval:int = 0



@dataclass
class OutPut:
    星启动:bool = None
    主启动:bool = None
    三角启动:bool = None

@dataclass
class Temp():
    ...

@dataclass
class Motor:
    input:InPut = InPut()
    outPut:OutPut = OutPut()
    temp:Temp = Temp()

上面创建了4个类,其中Motorl 里面的3个属性是由上面的3个数据类对象构成。这样Motor类就会很方便的操作输入和输出。然后分别写两个类,没个类属性保存Motor对象代码如下:


class Devices:
    motor1 = Motor()
    motor2 = Motor()
    motor3 = Motor()
    motor4 = Motor()
    motor5 = Motor()



class HMI:
    input:InPut = InPut(interval=50)
    input2:InPut = InPut(interval=100)
    input3:InPut = InPut(interval=300)
    input4:InPut = InPut(interval=400)
    input5:InPut = InPut(interval=600)

在写个映射函数,把HMI类的数据映射给Devices类,代码如下:


def mapping():
    Devices.motor1.input.interval = HMI.input.interval
    Devices.motor2.input.interval = HMI.input2.interval
    Devices.motor3.input.interval = HMI.input3.interval
    Devices.motor4.input.interval = HMI.input4.interval
    Devices.motor5.input.interval = HMI.input5.interval

    print("motor1.input.interval:",Devices.motor1.input.interval)
    print("motor2.input.interval:",Devices.motor2.input.interval)
    print("motor3.input.interval:",Devices.motor3.input.interval)
    print("motor4.input.interval:",Devices.motor4.input.interval)
    print("motor5.input.interval:",Devices.motor5.input.interval)

if __name__ == '__main__':
    mapping()

貌似没问题,打印结果如下:

motor1.input.interval: 600
motor2.input.interval: 600
motor3.input.interval: 600
motor4.input.interval: 600
motor5.input.interval: 600

结果都是600,怎么会这样?先把motor对象的ID打出来。


def mapping():
    Devices.motor1.input.interval = HMI.input.interval
    Devices.motor2.input.interval = HMI.input2.interval
    Devices.motor3.input.interval = HMI.input3.interval
    Devices.motor4.input.interval = HMI.input4.interval
    Devices.motor5.input.interval = HMI.input5.interval

    # print("motor1.input.interval:",Devices.motor1.input.interval)
    # print("motor2.input.interval:",Devices.motor2.input.interval)
    # print("motor3.input.interval:",Devices.motor3.input.interval)
    # print("motor4.input.interval:",Devices.motor4.input.interval)
    # print("motor5.input.interval:",Devices.motor5.input.interval)

    print("motor1",id(Devices.motor1))
    print("motor2",id(Devices.motor2))
    print("motor3",id(Devices.motor3))
    print("motor4",id(Devices.motor4))
    print("motor5",id(Devices.motor5))

if __name__ == '__main__':
    mapping()

#运行结果:
motor1 2213315589264
motor2 2213317258400
motor3 2213316869232
motor4 2213317974672
motor5 2213317975920
def mapping():
    Devices.motor1.input.interval = HMI.input.interval
    Devices.motor2.input.interval = HMI.input2.interval
    Devices.motor3.input.interval = HMI.input3.interval
    Devices.motor4.input.interval = HMI.input4.interval
    Devices.motor5.input.interval = HMI.input5.interval

    # print("motor1.input.interval:",Devices.motor1.input.interval)
    # print("motor2.input.interval:",Devices.motor2.input.interval)
    # print("motor3.input.interval:",Devices.motor3.input.interval)
    # print("motor4.input.interval:",Devices.motor4.input.interval)
    # print("motor5.input.interval:",Devices.motor5.input.interval)

    print("motor1.input",id(Devices.motor1.input))
    print("motor2.input",id(Devices.motor2.input))
    print("motor3.input",id(Devices.motor3.input))
    print("motor4.input",id(Devices.motor4.input))
    print("motor5.input",id(Devices.motor5.input))

结果
motor1.input 2891784968080
motor2.input 2891784968080
motor3.input 2891784968080
motor4.input 2891784968080
motor5.input 2891784968080

上面的id是一样的,说明指向了同一个内存地址。这里就有一个坑。

分析原因及解决办法如下:

在这个代码中,因为使用了`dataclass`的默认值初始化方式,会导致所有`Motor`类的实例都共享相同的`InPut`类的实例,从而导致它们的`id`都是相同的。如果希望每个`Motor`实例拥有独立的`InPut`实例,可以通过在`Motor`类的`__post_init__`方法中为`input`属性赋予新的`InPut`实例来实现。下方修改代码:

@dataclass
class Motor:
    input: InPut = None
    outPut: OutPut = OutPut()
    temp: Temp = Temp()

    def __post_init__(self):
        if self.input is None:
            self.input = InPut()


通过在`Motor`类中定义`__post_init__`方法,可以确保每个`Motor`实例都有独立的`InPut`实例,从而使它们的`id`不再相同。

完整代码如下:


from dataclasses import dataclass
@dataclass
class InPut:
    start:bool = False
    stop:bool = 0
    fault:bool = None
    interval:int = 0



@dataclass
class OutPut:
    星启动:bool = None
    主启动:bool = None
    三角启动:bool = None

@dataclass
class Temp():
    ...

@dataclass
class Motor:
    input:InPut = None
    outPut:OutPut = OutPut()
    temp:Temp = Temp()

    def __post_init__(self):
        if self.input is None:
            self.input = InPut()



class Devices:
    motor1 = Motor()
    motor2 = Motor()
    motor3 = Motor()
    motor4 = Motor()
    motor5 = Motor()



class HMI:
    input:InPut = InPut(interval=50)
    input2:InPut = InPut(interval=100)
    input3:InPut = InPut(interval=300)
    input4:InPut = InPut(interval=400)
    input5:InPut = InPut(interval=600)


def mapping():
    Devices.motor1.input.interval = HMI.input.interval
    Devices.motor2.input.interval = HMI.input2.interval
    Devices.motor3.input.interval = HMI.input3.interval
    Devices.motor4.input.interval = HMI.input4.interval
    Devices.motor5.input.interval = HMI.input5.interval

    print("motor1.input.interval:",Devices.motor1.input.interval)
    print("motor2.input.interval:",Devices.motor2.input.interval)
    print("motor3.input.interval:",Devices.motor3.input.interval)
    print("motor4.input.interval:",Devices.motor4.input.interval)
    print("motor5.input.interval:",Devices.motor5.input.interval)

    print("motor1.input",id(Devices.motor1.input))
    print("motor2.input",id(Devices.motor2.input))
    print("motor3.input",id(Devices.motor3.input))
    print("motor4.input",id(Devices.motor4.input))
    print("motor5.input",id(Devices.motor5.input))

if __name__ == '__main__':
    mapping()

问题得以解决。

结果如下:

motor1.input.interval: 50
motor2.input.interval: 100
motor3.input.interval: 300
motor4.input.interval: 400
motor5.input.interval: 600
motor1.input 2353790703552
motor2.input 2353793639328
motor3.input 2353793640240
motor4.input 2353793638944
motor5.input 2353793639808

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值