1

I have this function for listing all the PNPdevices of a system. The issue is, even though the query and appended object is perfect, the list to which the object is being appended , copies the entire list with only the last object.

def getnicinfo():
    c = wmi.WMI()
    wql = "SELECT * FROM Win32_NetworkAdapter WHERE PhysicalAdapter=true AND Manufacturer != 'Microsoft' AND NOT PNPDeviceID LIKE 'ROOT\\%'"
    temp = c.query(wql)
    x = data.device() //user-defined class, does not really matter as the data exchanged is compatible

    deviceList = list()
    print("\nreturns physical NIC")
    for J in temp:
        x.ProductName = J.__getattr__('ProductName')
        deviceList.append(x)
    for i in deviceList:    // this is where the last element that was added in last loop replaces every other element
        print(i.ProductName) 
return deviceList

This should print the following :

Intel(R) HD Graphics Family
Intel(R) 8 Series USB Enhanced Host Controller #1 - 9C26
Generic USB Hub
ACPI Lid

whereas the output is

ACPI Lid
ACPI Lid
ACPI Lid
ACPI Lid

As you can see it copies the last object for all the objects. The previous output that I got was by printing the deviceList[-1].ProductName just after the append statement, hence the object being added is correct. However, as soon as I exit the first loop and go the second (print) loop, the objects are copied.

  • 3
    This is your problem: http://stackoverflow.com/questions/8122627/the-copy-variable-changes-the-original-var-in-python – palsch Nov 30 '15 at 14:29
  • 1
    Never call double-underscore methods directly. If you needed to do it, it should be `x.ProductName = getattr(J, 'ProductName')`, but you don't need to do it at all with a constant value: `x.ProductName = J.ProductName`. – Daniel Roseman Nov 30 '15 at 14:31
  • @pal sch I take for updating the value of "x" , I need to use copy function instead? Would be very helpful if you can help understand the side effects (if any) in the answer by -Arimaz, if it is a good practice. – Sushim Mukul Dutta Nov 30 '15 at 15:09
  • @DanielRoseman Surely, changing that, still fairly new to python overall. Thanks :) – Sushim Mukul Dutta Nov 30 '15 at 15:09
  • 1
    Have you read the answers you can find there? Imagine, the content of variables is stored in RAM and the variable names are pointers (they are) to this content. So, if you say that x=y the content you can find under x is the same as the content under y - it points to the same point in RAM. Now, if you say x=»other content« the content in RAM is changed, so y points there, too. This only works for some variable types, keywords (Google or so): mutable variables, immutable variables. – palsch Nov 30 '15 at 15:17
  • 1
    Oh, and when you use [:] or copy module there will be two content instances in RAM. So you use more RAM when doing that. – palsch Nov 30 '15 at 15:19
  • Thanks a lot, I understood that part, however, was referencing to @Arimaz 's answer for explanation. Even though that solved the problem, I am bit skeptical about defining a new object for every single iteration. Also, since I am creating a new object every time with a same name, does that discard the previous object and it's references from the memory pool? TIA – Sushim Mukul Dutta Nov 30 '15 at 15:23
  • 1
    Have a look at python's garbage collector. – palsch Nov 30 '15 at 15:26

1 Answers1

2

This is because all elements of your list references the same object x. They have the value of the last iteration because it is a mutable object, so every time you do x.ProductName = J.__getattr__('ProductName') you change the ProductName of the same object referenced N times in your list. See your list as a list containing pointers that points all to the same object.

What you have to do is define a new object of your user-defined class at each iteration of your loop like:

y = UserDefinedClass(x) y.ProductName = J.__getattr__('ProductName') deviceList.append(y)

Arimaz
  • 61
  • 2
  • Thanks a lot, initialized x = data.device() inside the loop instead of outside. However, I wonder what are the side - effects (in terms of memory) when the object is created for every iteration. – Sushim Mukul Dutta Nov 30 '15 at 15:04
  • @SushimMukulDutta, in your case you need a list of N "distinct" objects, so creating them in a loop or not does not change the fact that you will have in the end N objects in memory has long has your list is referenced. Loop or not you need to have those N objects in memory at some point. – Arimaz Nov 30 '15 at 16:31