python中for循环赋值奇怪问题

图片描述

听说for循环里面的变量是会泄露到外面,另外还存在地址引用的问题。
参考了几个文章说的,所以特意加了一行info={}来每次都创建一个新的对象。

1.但是,结果还是没变,返回的集合全部是同一个结果。
2.这个info还是灰色的,提示是该变量创建后没有被引用到,这尼玛是逗我吧,,,python什么个机制?

万不得已,把info再弄个深度复制,再append算了?

下面是这个类的源码,这个类的目的是把某A数据源,根据B的结构,构件出一个B。

class PubClass:
    @staticmethod
    def getInfo(model, data):
        info = model
        for k, v in vars(model).items():
            if isinstance(data, object):
                if hasattr(data, k):
                    setattr(info, k, getattr(data, k))
            elif isinstance(data, dict):
                if k in data:
                    setattr(info, k, data[k])
        return info

    @classmethod
    def getList(cls, obj, data, toDict=True):
        datalist = []
        for d in data:
            if toDict:
                info = cls.getInfo(obj, d).__dict__
            else:
                info = cls.getInfo(obj, d)
            datalist.append(copy.deepcopy(info))   # 目前只能弄个深度复制来解决,但是性能感觉不太好
        return datalist
阅读 7.9k
3 个回答

题主,你这里先info={},又对info赋值,实际上和

a = 1
a = 2

这样赋值是一样的,变量a对1的引用已经断了,最后得到的只会是a = 2
同理,

info = {}
info = cls.getInfo(obj, d).__dict__

重新建立了引用关系,第一次创建的info确实没有用到,你可以尝试在循环体中用info.update(),把获取的字典更新到info中。或者把你想要存进infokey value直接用info = {key: value}的方式创建,也是可以的。

不知道你怎么调用,也许一个 shallow copy就足够了
再说一下

d={}
print isinstance(d,object)

输出

True

getInfo方法的第二个isinstance下的部分不会执行?

光看截图我就觉得 getinfo() 有问题
一看后面,果然

手机占坑,电脑编辑

先给你看一段代码

def func(l, n):
    # 没有return
    l.append(n)

obj = []
for x in range(100):
    # 也没有赋值
    func(obj, x)

# 猜猜obj的长度
print(len(obj))

再看看这段代码

class PubClass:
    @staticmethod
    def getInfo(model, data):
        info = model
        # for k, v in vars(model).items():
            # if isinstance(data, object):
                # if hasattr(data, k):
                    # setattr(info, k, getattr(data, k))
            # elif isinstance(data, dict):
                # if k in data:
                    # setattr(info, k, data[k])
        return info

    @classmethod
    def getList(cls, obj, data, toDict=True):
        datalist = []
        for d in data:
            info = {} # 第一次赋值,列表引用
            # if toDict:
                # info = cls.getInfo(obj, d).__dict__
            # else:
                info = cls.getInfo(obj, d) # 第二次赋值,列表引用,覆盖
            datalist.append(info)
        return datalist

注释掉无关紧要的部分,这就是你的代码的实际作用

再精简一点就是下面这样

def getList(cls, obj, data, toDict=True):
    datalist = []
    for d in data:
        info = obj
        datalist.append(info)
    return datalist

看出问题来了吗?

你连问题的原因都没找到,根本不是for的锅,而是引用造成的。
在Python中,参数除了基础类型是按值传递,其他都是按引用传递
getInfo()函数,传入的参数,返回值,实际上都是同一个内存地址的引用,info 或者说是obj
然后你把info这个变量,存进了datalist 列表,一共len(data)
存的全部是同一个内存地址
如果你学过C语言的指针,你应该能理解

那么现在说说第二个问题:
info 第一次赋值,创建了一个空字典,并引用新字典的地址
第二次赋值,重新引用了obj这个对象的地址
新字典一次都没用过,所以你的编辑器给你灰色加亮提示了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题