Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation change // Copying data vs by-ref + optional feature request for surprising behavior #280

Open
garzola opened this issue Oct 20, 2024 · 0 comments

Comments

@garzola
Copy link

garzola commented Oct 20, 2024

This is definitely a documentation update and perhaps a bug or feature request (box and subclasses of box should be by reference instead of copy).

For the documentation, a clear section covering copying vs references would have really helped me.

Here is my proposed documentation update (as I could not figure out how to provide pull request for the wiki:

How Box Handles Conversions

When data is brought into a Box, the values are copied. In particular, when you import a dict or a list, changes to the original dict or list will not be reflected in the Box. In some future version of Box, the references to the values may be preserved, but at the moment, this is not possible.

For any other type, passing "box_intact_types" with a tuple listing the types to preserve will create a reference in the Box instead of a copy. In some future version of Box, subclasses of Box will automatically be considered a "box_intact_type".

The examples below illustrate this:

Box does not create a connection to the original dictionary

from box import Box
from copy import deepcopy

original = {"key1": "value1", "key2": "value2", "key3": "value3"}
original_ref = original
original_copy = deepcopy(original)
box = Box(original)

print(f"""     original["key1"] ==> {original["key1"]}""")
# expect "value1"

# change the value in the original
original["key1"] = "new value"

print(f"""     original["key1"] ==> {original["key1"]}""")
# expect "newvalue"
print(f""" original_ref["key1"] ==> {original_ref["key1"]}""")
# expect "newvalue"
print(f"""original_copy["key1"] ==> {original_copy["key1"]}""")
# expect "value1"
print(f"""             box.key1 ==> {box.key1}""")
# expect "value1"

Produces the following output:

      original["key1"] ==> value1
     original["key1"] ==> new value
 original_ref["key1"] ==> new value
original_copy["key1"] ==> value1
             box.key1 ==> value1

Box does not create a connection to imported Boxes

from box import Box

box1 = Box({"key1": "value1", "key2": "value2", "key3": "value3"})
box2 = Box({"key4": "value4", "key5": "value5", "key6": "value6"})

box1.box2 = box2

box1.box2.key1 = "newvalue"

print(f"""         id(box2)  ==> {id(box2)}""")
print(f"""     id(box1.box2) ==> {id(box1.box2)}""")
print(f"""box1.box2 == box2  ==> {box1.box2 == box2}""")

print(f"""        mybox.key1 ==> {box1.key1} """)
print(f"""   box1.mybox.key1 ==> {box1.box2.key1} """)

Produces the following output:

         id(box2)  ==> 4404576032
     id(box1.box2) ==> 4406568000
box1.box2 == box2  ==> False
        mybox.key1 ==> value1
   box1.mybox.key1 ==> newvalue

Box does not create a connection to subclasses of Box

class MyBox(Box):
    pass

original= {"key1" : "value1", "key2": "value2", "key3": "value3"}

mybox = MyBox(original)

box = Box()

box.mybox = mybox

print(f"""         id(mybox)  ==> {id(mybox)}""")
print(f"""      id(box.mybox) ==> {id(box.mybox)}""")

mybox.key1 = "value4"

print(f"""         mybox.key1 ==> {mybox.key1}""")
print(f"""     box.mybox.key1 ==> {box.mybox.key1} """)
print(f"""box.mybox == mybox  ==> {box.mybox == mybox}""")

produces the following output:

         id(mybox)  ==> 4622158976
      id(box.mybox) ==> 4622157456
         mybox.key1 ==> value4
     box.mybox.key1 ==> value1
box.mybox == mybox  ==> False

Use box_intact_types to create a connection to subclasses of Box

class MyBox(Box):
    pass

original= {"key1" : "value1", "key2": "value2", "key3": "value3"}

mybox = MyBox(original)

box = Box(box_intact_types=(MyBox,))

box.mybox = mybox

print(f"""         id(mybox)  ==> {id(mybox)}""")
print(f"""      id(box.mybox) ==> {id(box.mybox)}""")

mybox.key1 = "value4"

print(f"""         mybox.key1 ==> {mybox.key1}""")
print(f"""     box.mybox.key1 ==> {box.mybox.key1} """)
print(f"""box.mybox == mybox  ==> {box.mybox == mybox}""")

Produces the following output:

         id(mybox)  ==> 4404364384
      id(box.mybox) ==> 4404364384
         mybox.key1 ==> value4
     box.mybox.key1 ==> value4
box.mybox == mybox  ==> True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant