this took me a full day to find

Posted on
Mon Feb 26, 2018 10:46 pm
kw123 offline
User avatar
Posts: 8363
Joined: May 12, 2013
Location: Dallas, TX

this took me a full day to find

Code: Select all
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(a)
    b[-1][2]+=1

will change a[2]!!! from 3 to 3+1 ; 4+1;5+1 ...

though that "append()" would not just copy pointers to data but the data itself ..
this works correctly:
Code: Select all
import copy
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(copy.copy(a))
    b[-1][2]+=1


The actual code a bit more complex but the principle in shown

Karl

Posted on
Tue Feb 27, 2018 7:17 am
DaveL17 offline
User avatar
Posts: 6753
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: this took me a full day to find

As you found, append() wouldn't change the rule that a and b point to the same thing. With your corrected code, I get this:

Code: Select all
import copy
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(copy.copy(a))
    b[-1][2]+=1

print(b)

>>> [[1, 2, 4, 4, 5], [1, 2, 4, 4, 5], ... [1, 2, 4, 4, 5]]
Are you looking to get 100 copies of a? You now have 100 separate lists within b. Consider this:

Code: Select all
import copy
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(copy.copy(a))
    b[-1][2]+=1

b[-1][2]+=1
print(b)

>>> [[1, 2, 4, 4, 5], [1, 2, 4, 4, 5], ... [1, 2, 5, 4, 5]]

I'm curious why you would want 100 copies of list a. Maybe I'm misunderstanding something.

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Tue Feb 27, 2018 7:55 am
kw123 offline
User avatar
Posts: 8363
Joined: May 12, 2013
Location: Dallas, TX

Re: this took me a full day to find

This was a simplified example The logic was several lines of code with several “if” date < xx and bin> yt etc
Just to illustrate the problem.


Sent from my iPhone using Tapatalk

Posted on
Tue Feb 27, 2018 10:11 am
jay (support) offline
Site Admin
User avatar
Posts: 18219
Joined: Mar 19, 2008
Location: Austin, Texas

Re: this took me a full day to find

The majority of objects in Python are passed around by reference rather than by value. copy.copy() works for basic objects, but for containers like lists and dictionaries (or objects which maintain references to other objects) it will just copy the container, but the objects will still be references.

Code: Select all
>>> a = range(0, 5)
>>> a
[0, 1, 2, 3, 4]
>>> b = range(5, 10)
>>> b
[5, 6, 7, 8, 9]
>>> c = [a, b]
>>> c
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> d = copy.copy(c)
>>> d
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> e = copy.deepcopy(c)
>>> e
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> c[0][0] = None
>>> c
[[None, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> d
[[None, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> e
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>>


So, copy.copy(c) copies the array with references to the contained objects (represented by d). When we change one of the elements contained in c, the change is reflected in d. However, it's not reflected in e because we used copy.deepcopy(c), which attempts to make copies of all objects contained in the c container recursively.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Tue Feb 27, 2018 10:32 am
matt (support) offline
Site Admin
User avatar
Posts: 21417
Joined: Jan 27, 2003
Location: Texas

Re: this took me a full day to find

And to further confuse the issue, note that indigo.List() and indigo.Dict() instances behave differently than python list/dicts in that they always return copies of the object and not references. More details are on this thread.

Image

Posted on
Tue Feb 27, 2018 1:30 pm
DaveL17 offline
User avatar
Posts: 6753
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: this took me a full day to find

Now you guys are just showing off. :wink:

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Tue Feb 27, 2018 1:33 pm
Colorado4Wheeler offline
User avatar
Posts: 2794
Joined: Jul 20, 2009
Location: Colorado

Re: this took me a full day to find

If we want to show off we could start talking about super classes... :shock: :roll: :D

My Modest Contributions to Indigo:

HomeKit Bridge | Device Extensions | Security Manager | LCD Creator | Room-O-Matic | Smart Dimmer | Scene Toggle | Powermiser | Homebridge Buddy

Check Them Out Here

Posted on
Tue Feb 27, 2018 11:18 pm
kw123 offline
User avatar
Posts: 8363
Joined: May 12, 2013
Location: Dallas, TX

Re: this took me a full day to find

replaced all copy.copy() with copy.deepcopy()

now I get:
Code: Select all
addToStatesUpdateList in Line '12682' has error='Pickling of "indigo.Device" instances is not enabled (http://www.boost.org/libs/python/doc/v2/pickle.html)'


one of the list elements is an indigo device. (>>dev<< from dev=indigo.device{123] )

code works fine with copy .copy() .. that does not complain as it does not try to do a deep copy of the indigo device I guess.

is there any other situation where copy. deepcopy() will not work?


Karl

Posted on
Wed Feb 28, 2018 4:29 pm
jay (support) offline
Site Admin
User avatar
Posts: 18219
Joined: Mar 19, 2008
Location: Austin, Texas

Re: this took me a full day to find

Yeah, deepcopy() on custom objects requires that the class implements the __deepcopy__ method. Indigo objects don't support that because they fundamentally are thin wrappers around C++ objects (and creating copies like that are not really possible).

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 5 guests