-1

below is my python script which needs to traverse all the physical disks which are having logical-paths as well as direct disks

and if we found any logical_paths then we get corresponding physical disk then we remove the logical-part and add the physical-disk corresponding to it into the check dictionary

check={
        "/dev/disks/DISK2": "",
        "/dev/disks/DISK4": "",
        "/dev/disks/DISK5": "",
        "/dev/disks/DISK1": "",
        "/dev/disks/DISK6": "",
        "/dev/disks/DISK3": "",
        "/dev/sda": "/dev/sda"

}
logical_paths={
        "/dev/disks/DISK2": "/ dev / sdc1",
        "/dev/disks/DISK4": "/ dev / sdd2",
        "/dev/disks/DISK5": "/ dev / sde1",
       "/dev/disks/DISK1": "/dev/sdb4"
}
for a in check.keys():
     print("*****")
     print("disk is:"+a)
     if a in logical_paths:
         check[logical_paths[a]]=check[a]
         check.pop(a,None)
print("####")
print(check)

But output of my script is:

*****
disk is:/dev/oracleasm/disks/DISK2
*****
disk is:/dev/oracleasm/disks/DISK4
*****
disk is:/dev/oracleasm/disks/DISK5
*****
disk is:/dev/oracleasm/disks/DISK1
*****
disk is:/ dev / sdc1
*****
disk is:/ dev / sdd2
*****
disk is:/ dev / sde1
*****
disk is:/dev/sdb4

Why is it traversing the disk6,disk3 and SDA

2 Answers2

2

Simply create a list from your keys and then iterate above the created list of keys.

Background

Your problem is that you modify your dict while iterating over it. This results into changes of the underlying structure. If you want to see this explicitly, you can comment out the check.pop(a) and then you will get an error RuntimeError: dictionary changed size during iteration. In short, you should avoid modifying the keys of a dict while iterating over them. For an extended explanation of your problem see: Modifying a Python dict while iterating over it

Fixed code

check={
        "/dev/disks/DISK2": "",
        "/dev/disks/DISK4": "",
        "/dev/disks/DISK5": "",
        "/dev/disks/DISK1": "",
        "/dev/disks/DISK6": "",
        "/dev/disks/DISK3": "",
        "/dev/sda": "/dev/sda"

}
logical_paths={
        "/dev/disks/DISK2": "/ dev / sdc1",
        "/dev/disks/DISK4": "/ dev / sdd2",
        "/dev/disks/DISK5": "/ dev / sde1",
       "/dev/disks/DISK1": "/dev/sdb4"
}
for a in list(check):
     print("*****")
     print("disk is:"+a)
     if a in logical_paths:
         check[logical_paths[a]]=check[a]
         check.pop(a)
print("####")
print(check)

output:

*****
disk is:/dev/disks/DISK2
*****
disk is:/dev/disks/DISK4
*****
disk is:/dev/disks/DISK5
*****
disk is:/dev/disks/DISK1
*****
disk is:/dev/disks/DISK6
*****
disk is:/dev/disks/DISK3
*****
disk is:/dev/sda
####
{'/dev/disks/DISK6': '', '/dev/disks/DISK3': '', '/dev/sda': '/dev/sda', '/ dev / sdc1': '', '/ dev / sdd2': '', '/ dev / sde1': '', '/dev/sdb4': ''}
Sparky05
  • 4,692
  • 1
  • 10
  • 27
0

I agree that you should not remove items from a list/dictionary while iterate through it. So you should better not apply .pop to either list or dict! I made a simple change in your code:

for a in check.keys():
     print("*****")
     print("disk is:",a)
     if a in logical_paths:
         check[a]=logical_paths[a]
       #  check.pop(a,None)
print("####")
print(check)

Hope that it generates the correct output for you! The output is:

*****
disk is: /dev/disks/DISK2
*****
disk is: /dev/disks/DISK4
*****
disk is: /dev/disks/DISK5
*****
disk is: /dev/disks/DISK1
*****
disk is: /dev/disks/DISK6
*****
disk is: /dev/disks/DISK3
*****
disk is: /dev/sda
####
{'/dev/disks/DISK2': '/ dev / sdc1', '/dev/disks/DISK4': '/ dev / sdd2', '/dev/disks/DISK5': '/ dev / sde1', '/dev/disks/DISK1': '/dev/sdb4', '/dev/disks/DISK6': '', '/dev/disks/DISK3': '', '/dev/sda': '/dev/sda'}
tianlinhe
  • 991
  • 1
  • 6
  • 15