5. 变量声明方法

1,368 阅读3分钟

背景:在做一个目标检测的项目。要对每张图片生成预测的mAP等指标。

def run():
    for batch_i, (im, targets, paths, shapes) in enumerate(pbar): 
        ...
        for si, pred in enumerate(preds):  
            labels = targets[targets[:, 0] == si, 1:]  
            nl, npr = labels.shape[0], pred.shape[0] 
            ...

        #生成单张图片测试结果的脚本
        single(stats_temp, plots, save_dir, names, nc, verbose, seen, training, npr, pred, id_string) 

出现的问题就是:pred为第二个for循环内的变量,但是我也想在第二个for循环外用到,应该怎样声明呢?

解决方法:

  1. 使用关键词global生成全局变量。
def run():
    for batch_i, (im, targets, paths, shapes) in enumerate(pbar): 
        ...
        for si, pred in enumerate(preds):  
            global pred
            labels = targets[targets[:, 0] == si, 1:]  
            nl, npr = labels.shape[0], pred.shape[0] 
            ...

        #生成单张图片测试结果的脚本
        single(stats_temp, plots, save_dir, names, nc, verbose, seen, training, npr, pred, id_string) 

弊端:代码难以维护。

  1. 将局部变量pred在for循环外声明,值赋为None
def run():
    for batch_i, (im, targets, paths, shapes) in enumerate(pbar): 
        ...
        pred=None
        for si, pred in enumerate(preds):  
            labels = targets[targets[:, 0] == si, 1:]  
            nl, npr = labels.shape[0], pred.shape[0] 
            ...

        #生成单张图片测试结果的脚本
        single(stats_temp, plots, save_dir, names, nc, verbose, seen, training, npr, pred, id_string) 

弊端:设置为NoneNone是Python中的一种特殊数据类型,表示变量没有值。当pred到被用的时候都没有被赋进去值,那么就会报错。

针对于变量报错,但是又希望整个程序运行完。可以使用异常处理来捕捉异常:

注:要用try包住pred变量整个的使用区域。

def run():
    for batch_i, (im, targets, paths, shapes) in enumerate(pbar): 
        ...
        try:
            pred=None
            for si, pred in enumerate(preds):  
                labels = targets[targets[:, 0] == si, 1:]  
                nl, npr = labels.shape[0], pred.shape[0] 
                ...

            #生成单张图片测试结果的脚本
            single(stats_temp, plots, save_dir, names, nc, verbose, seen, training, npr, pred, id_string) 
        except Exception:  
            print("有误")
  1. 将局部变量pred在for循环外声明,值赋为该变量的类型下的0值/空值。

第一步:获取该变量类型。

使用type()函数可以获取任何数据的类型。

print(type(pred))

第二步:获取该变量的形状。

#获取numpy类型的形状
my_array = np.zeros((3, 4))
print(my_array.shape)

#获取tensor类型的形状
my_tensor = torch.zeros(3, 4)
print(my_tensor.shape)

#获取list类型的形状
my_list = [[[2,3,4],[6,7,8]],[[2,3,0],[6,7,9]]]

def get_shape(lst):
    shape = []
    while isinstance(lst, list):
        shape.append(len(lst))
        lst = lst[0]
    return tuple(shape)

print(get_shape(my_list))  # Output: (2, 2, 3)

第三步:生成0/空的该变量

#生成numpy类型的0/空变量
my_array1 = np.zeros((3, 4))
my_array2 = np.ones((3, 4))
my_array3 = np.empty((3, 4))

#生成tensor类型的0/1空变量
my_tensor1 = torch.zeros(3, 4)
my_tensor2 = torch.ones(3, 4)
my_tensor3 = torch.empty(3, 4)

#生成list类型的空变量
my_list = []

最终:

def run():
    for batch_i, (im, targets, paths, shapes) in enumerate(pbar): 
        ...
        try:
            pred=torch.zeros((3,4))
            for si, pred in enumerate(preds):  
                labels = targets[targets[:, 0] == si, 1:]  
                nl, npr = labels.shape[0], pred.shape[0] 
                ...

            #生成单张图片测试结果的脚本
            single(stats_temp, plots, save_dir, names, nc, verbose, seen, training, npr, pred, id_string) 
        except Exception:  
            print("有误")

总结:通过自己写了一个脚本,对于代码块内的变量怎样在代码块外声明,有了一个经验:即在代码块外无类型声明None,或有类型声明0/1/空(获取类型→获取形状)。这里或许还有很多不足,比如这个变量形状可能是变化的,那么万一经下面的语句该变量都没被赋值上,就会报错,个人为了针对这种情况,往往用try..except..来捕捉的。

这里还请各位大佬给我指正!