Re: [Tutor] lists, name semantics

2015-04-19 Thread Dave Angel

On 04/19/2015 12:07 AM, boB Stepp wrote:

.
Before Peter changed one of these

changeable objects, he had:

a = [1, [x, y], 3]
b = a[:]

Now BOTH a[1] and b[1] now identify the location of the inner list
object, [x, y] . Apparently, Python, in its ever efficient memory
management  fashion, when it creates the new object/piece of data
a[:], it sees no need to duplicate the inner list object, [x, y],
but instead creates another identifier/pointer/reference to this
object's location. But since this inner list object is mutable, when
you change y to hello! in b, you also change it in a because both
a[1][1] and b[1][1] reference/point to the exact same storage location
where this element of the inner list is actually stored.

I hope this is helpful, and, if there are any misstepps, that when
they are revealed both of our understandings will be enhanced!



Some of your knowledge of other languages is leaking into your 
explanation.  When we talk of the language Python, we need to 
distinguish between how CPython happens to be implemented, how other 
Python implementations happen to be created, and how C++ (for example) 
implements similar things.  Some of the above use pointers, some do not. 
 The language Python does not.


So especially when talking of inner lists, we need to clarify a few things.

An object has an identity, not a location.  That identity can be checked 
with the 'is' operator, or the id() function.  But it exists all the time.


Variables, as you say, do not contain an object, they reference it.  And 
the formal term for that is binding.  A name is bound to an object, to 
one object, at a time.


Now some objects have attributes, which is to say names, and those 
attributes are bound to other objects.  So if we define a class, and 
have an instance of that class, and the instance has attributes, we can 
do something like:

obj.inst_name

and get the particular attribute.

Still other objects have unnamed bindings.  The canonical example is a 
list.  A list object has a bunch of bindings to other objects.  Even 
though each  binding doesn't have a specific name, it nevertheless 
exists.  And in this case we use integers to specify which of those 
bindings we want to follow.  And we use a special syntax (the square 
bracket) to indicate which of these we want.


So let's take the simplest example:

mylist = [a, b]

the name mylist is bound to a list object, which has two numbered 
bindings, called 0 and 1.  That object's  [0] binding is to a separate 
object a.  And the [1] binding is to a separate object b


There is another shorthand called a slice, which looks like [start, len, 
step] which lets us construct a *new* list from our list.  And using 
defaults for all three terms lets us copy the list.  But let's look at 
what the copy means:


newlist = mylist[:]
--  mylist[0, 2, 1]

This constructs a new list from the present one, where the zeroth 
location is bound to whatever object the first list's zeroth location 
was bound to.  And so on for the oneth location, the twoth, etc.


Only one new list object is built, and no new objects are made for it. 
It just gets new bindings to the same things the first list had.


At this point, it should be clear what a shallow copy means.  If the 
original list's oneth item was a binding to another list object, *that* 
list object does NOT get copied.


I don't like the term inner list,  but I don't know if it's incorrect. 
 It's just misleading, since to the slice operation, the fact that it's 
a list is irrelevant.  It's just an object whose binding is to be copied.


--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread Dave Angel

On 04/19/2015 03:08 PM, boB Stepp wrote:

On Sun, Apr 19, 2015 at 6:47 AM, Dave Angel da...@davea.name wrote:

On 04/19/2015 12:07 AM, boB Stepp wrote:


[...]


I hope this is helpful, and, if there are any misstepps, that when
they are revealed both of our understandings will be enhanced!



Some of your knowledge of other languages is leaking into your explanation.
When we talk of the language Python, we need to distinguish between how
CPython happens to be implemented, how other Python implementations happen
to be created, and how C++ (for example) implements similar things.  Some of
the above use pointers, some do not.  The language Python does not.


I actually was being deliberately  *imprecise* in my use of technical
terminology.  But I see below that there are some nuances I need to
learn...


So especially when talking of inner lists, we need to clarify a few things.

An object has an identity, not a location.  That identity can be checked
with the 'is' operator, or the id() function.  But it exists all the time.


But the object, in order to exist, must be stored in RAM somewhere,
doesn't it?


Or in a swap file, a disk file, or some other media.


Or is the real point that we are adding an abstraction
layer so we don't even have to think about where objects are
physically stored in RAM?


Somebody keeps track, but the address is not necessarily constant, and 
not necessarily stored in any references.  The references (bindings) are 
abstract, and the details are unimportant to the user.  For example, the 
jython system does not use addresses at all.  And an object gets moved 
around from time to time without its references knowing it.



So I am the object referenced by boB and
we don't care what my precise (x, y, z) coordinates are relative to
the planet Earth. If we need to find me or modify me we use my label,
boB, to access me?


No, we use one of your many labels to find you.  And if no labels exist, 
you quietly cease to exist (garbage collection).  But understand that a 
label in this sense need not be some alpha string.  It might be a slot 
in some collection, like the way I described list.



Variables, as you say, do not contain an object, they reference it.  And the
formal term for that is binding.  A name is bound to an object, to one
object, at a time.

Now some objects have attributes, which is to say names, and those
attributes are bound to other objects.  So if we define a class, and have an
instance of that class, and the instance has attributes, we can do something
like:
 obj.inst_name

and get the particular attribute.

Still other objects have unnamed bindings.  The canonical example is a list.
A list object has a bunch of bindings to other objects.  Even though each
binding doesn't have a specific name, it nevertheless exists.  And in this
case we use integers to specify which of those bindings we want to follow.
And we use a special syntax (the square bracket) to indicate which of these
we want.


Ah, unnamed bindings was the concept I was talking around. I
realized these were there and were referenced by the square bracket
syntax, but I did not know what to call the concept.

[...]


At this point, it should be clear what a shallow copy means.  If the
original list's oneth item was a binding to another list object, *that* list
object does NOT get copied.

I don't like the term inner list,  but I don't know if it's incorrect.
It's just misleading, since to the slice operation, the fact that it's a
list is irrelevant.  It's just an object whose binding is to be copied.


So the real point here is that there are two distinct copying
mechanisms, deep and shallow. The inner list could just have been
any other type of object, though if it had been an immutable type it
would not have made Peter's original interesting point.


The distinction between deep and shallow was already made, by better 
people than I.  I was trying to explain it in terms of a working model 
that would let you predict what will happen in each circumstance.  A 
slice only copies the bindings in the list, it doesn't care what they 
are bound to.  It's shallow because it's shallow.




--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread Joel Goldstick
On Sun, Apr 19, 2015 at 6:23 PM, boB Stepp robertvst...@gmail.com wrote:
 On Sun, Apr 19, 2015 at 4:05 PM, Dave Angel da...@davea.name wrote:
 On 04/19/2015 03:08 PM, boB Stepp wrote:


 Or is the real point that we are adding an abstraction
 layer so we don't even have to think about where objects are
 physically stored in RAM?


 Somebody keeps track, but the address is not necessarily constant, and not
 necessarily stored in any references.  The references (bindings) are
 abstract, and the details are unimportant to the user.  For example, the
 jython system does not use addresses at all.  And an object gets moved
 around from time to time without its references knowing it.

 The last sentence in this paragraph has me intrigued. Why would an
 object, once it has been created, be moved? What practical benefit
 does doing this give?

 boB

I'm guessing memory management.  You want to have large contiguous
blocks of memory available for large objects.  If a small object is
surrounded by available memory, you might want to move it to some
smaller empty spot.
 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 https://mail.python.org/mailman/listinfo/tutor



-- 
Joel Goldstick
http://joelgoldstick.com
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread Laura Creighton
In a message of Sun, 19 Apr 2015 17:23:13 -0500, boB Stepp writes:
On Sun, Apr 19, 2015 at 4:05 PM, Dave Angel da...@davea.name wrote:
 abstract, and the details are unimportant to the user.  For example, the
 jython system does not use addresses at all.  And an object gets moved
 around from time to time without its references knowing it.

The last sentence in this paragraph has me intrigued. Why would an
object, once it has been created, be moved? What practical benefit
does doing this give?

boB

One great reason is called 'garbage collection'.
We find all the objects we are using, stuff them someplace in
memory, and free up all the space they left.  Now we are free
to lay down a whole lot of other things, in  contiguous order.

When you want to go access an array, for instance, it matters'
a whole lot if you can actually say:

for x
for y
tell_me (x,y)

rather than a lot of 'oops, I would love to tell you but when
I went to an address I got told, out space, go look over hear instead.


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread boB Stepp
On Sun, Apr 19, 2015 at 12:24 AM, Cameron Simpson c...@zip.com.au wrote:
 On 19Apr2015 15:09, Cameron Simpson c...@zip.com.au wrote:

 On 18Apr2015 23:26, boB Stepp robertvst...@gmail.com wrote:

 On Sat, Apr 18, 2015 at 11:08 PM, Cameron Simpson c...@zip.com.au wrote:

[...]

 Two problems often exist with deep copy operations that don’t exist
 with shallow copy operations:

 Recursive objects (compound objects that, directly or indirectly,
 contain a reference to themselves) may cause a recursive loop.
 Because deep copy copies everything it may copy too much, e.g.,
 administrative data structures that should be shared even between
 copies.

 If I am understanding things correctly, should not that last sentence
 read instead:

 ...structures that should *not* be shared even between copies. ???


 No, the text is correct.


 Um, my explaination was incomplete.

[...]

 The second sentence Because deep copy copies everything it may copy too
 much, e.g., administrative data structures that should be shared even
 between copies is an issuewhich is addressed lower down when mentioning the
 __copy_ and __deepcopy__ methods. And it is not necessarily obvious.

 Suppose you've got a data structure of objects, which should broadly be
 copied.  However, _internally_, these objects may use some external
 facility. Further, suppose that facility can't be copied; perhaps it is a
 reference to a databse or something built around something like that. Like
 this:

  G - A
- B
- _open_database

 When you deepcopy that data sctructure you want to copy everything, but
 _not_ copy the external facility object. So for the above example, after the
 deepcopy you want this:

  Gcopy - Acopy
- Bcopy
- _open_database

 i.e. the same reference to the database, but copies of A and B.

Ah! This example clarifies things for me. This provides a specific
context for  the phrase, ...that should be shared even between
copies... That now makes sense.

 If you give G's class a .__deepcopy__ method, then that will be called by
 deepcopy() to make a copy of G by calling G.__deepcopy__(memodict). And
 G's class will define its __deepcopy__ method to copy A and B but not
 _open_database.

 Most classes do not need this and deepcopy() just copies everything.

 Does this clarify things?

Very much! Thanks!

-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread boB Stepp
On Sun, Apr 19, 2015 at 6:47 AM, Dave Angel da...@davea.name wrote:
 On 04/19/2015 12:07 AM, boB Stepp wrote:

[...]

 I hope this is helpful, and, if there are any misstepps, that when
 they are revealed both of our understandings will be enhanced!


 Some of your knowledge of other languages is leaking into your explanation.
 When we talk of the language Python, we need to distinguish between how
 CPython happens to be implemented, how other Python implementations happen
 to be created, and how C++ (for example) implements similar things.  Some of
 the above use pointers, some do not.  The language Python does not.

I actually was being deliberately  *imprecise* in my use of technical
terminology.  But I see below that there are some nuances I need to
learn...

 So especially when talking of inner lists, we need to clarify a few things.

 An object has an identity, not a location.  That identity can be checked
 with the 'is' operator, or the id() function.  But it exists all the time.

But the object, in order to exist, must be stored in RAM somewhere,
doesn't it? Or is the real point that we are adding an abstraction
layer so we don't even have to think about where objects are
physically stored in RAM? So I am the object referenced by boB and
we don't care what my precise (x, y, z) coordinates are relative to
the planet Earth. If we need to find me or modify me we use my label,
boB, to access me?

 Variables, as you say, do not contain an object, they reference it.  And the
 formal term for that is binding.  A name is bound to an object, to one
 object, at a time.

 Now some objects have attributes, which is to say names, and those
 attributes are bound to other objects.  So if we define a class, and have an
 instance of that class, and the instance has attributes, we can do something
 like:
 obj.inst_name

 and get the particular attribute.

 Still other objects have unnamed bindings.  The canonical example is a list.
 A list object has a bunch of bindings to other objects.  Even though each
 binding doesn't have a specific name, it nevertheless exists.  And in this
 case we use integers to specify which of those bindings we want to follow.
 And we use a special syntax (the square bracket) to indicate which of these
 we want.

Ah, unnamed bindings was the concept I was talking around. I
realized these were there and were referenced by the square bracket
syntax, but I did not know what to call the concept.

[...]

 At this point, it should be clear what a shallow copy means.  If the
 original list's oneth item was a binding to another list object, *that* list
 object does NOT get copied.

 I don't like the term inner list,  but I don't know if it's incorrect.
 It's just misleading, since to the slice operation, the fact that it's a
 list is irrelevant.  It's just an object whose binding is to be copied.

So the real point here is that there are two distinct copying
mechanisms, deep and shallow. The inner list could just have been
any other type of object, though if it had been an immutable type it
would not have made Peter's original interesting point.

-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread Dave Angel

On 04/19/2015 06:28 PM, Joel Goldstick wrote:

On Sun, Apr 19, 2015 at 6:23 PM, boB Stepp robertvst...@gmail.com wrote:

On Sun, Apr 19, 2015 at 4:05 PM, Dave Angel da...@davea.name wrote:

On 04/19/2015 03:08 PM, boB Stepp wrote:





Or is the real point that we are adding an abstraction
layer so we don't even have to think about where objects are
physically stored in RAM?



Somebody keeps track, but the address is not necessarily constant, and not
necessarily stored in any references.  The references (bindings) are
abstract, and the details are unimportant to the user.  For example, the
jython system does not use addresses at all.  And an object gets moved
around from time to time without its references knowing it.


The last sentence in this paragraph has me intrigued. Why would an
object, once it has been created, be moved? What practical benefit
does doing this give?

boB


I'm guessing memory management.  You want to have large contiguous
blocks of memory available for large objects.  If a small object is
surrounded by available memory, you might want to move it to some
smaller empty spot.


Good answer.  The java jvm garbage collector is free to move blocks 
around to defrag the free space.


FWIW, I'm told the ID value used is a simple integer, that indexes a 
list containing the actual addresses.


So in this case, the binding value is an integer, not an address.

--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread Laura Creighton
In a message of Sun, 19 Apr 2015 19:19:27 -0400, Dave Angel writes:
Good answer.  The java jvm garbage collector is free to move blocks 
around to defrag the free space.

Correct.

FWIW, I'm told the ID value used is a simple integer, that indexes a 
list containing the actual addresses.

Also correct for the majority of cases.  You would have to be
an expert in GC to care about when this is not correct, which is
what I happen to be,  but only a pedant would object to what you said.

So in this case, the binding value is an integer, not an address.

Utterly wrong.  The binding value has to be an address.  All addresses
are integers.  I have no clue what you meant by this.  Please resubmit
and try again.  That some of the adresses are indirectly referred to
through a list means _nothing_.

Very puzzled, your brain is thinking wrong thoughts, but mostly
I can guess what is meant, here I cannot at all,

Sorry about that,
Laura

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread Laura Creighton
In a message of Sun, 19 Apr 2015 17:23:13 -0500, boB Stepp writes:
The last sentence in this paragraph has me intrigued. Why would an
object, once it has been created, be moved? What practical benefit
does doing this give?

boB

If you have more than enough memory in your system, you never do
this because there is never any need.  But if you would like to
lay down an array of x by y for the fastest access, you  would like
it to fit perfectly in memory.  Which can mean that the best you
can do is pick up a bunch of smaller objects, move them someplace
(anyplace) else, and then let your bigger object fit in memory
in contiguous space.

See 'garbage collection' for more useful ideas.

Laura

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread Alan Gauld

On 20/04/15 00:29, Laura Creighton wrote:


So in this case, the binding value is an integer, not an address.


Utterly wrong.  The binding value has to be an address.


I think it depends on how you define 'binding' value.
In Python binding is the connection between a name and an object.
So in a handle type system the binding between a name and object
is the objects handle, which is usually an integer. But the
address of the object is the thing the VM uses to fetch the actual 
object based on the handle. So we have two bindings at work.

The one the user sees between the name and the object (which
is the handle) and the one the VM uses between the handle
and the actual object, which is its address at that
particular moment in time. Its the VMs job to keep track
of how that second binding changes but the users view
of binding (the handle) never changes.


 All addresses are integers.


Usually, but not always. In segmented architectures they
are tuples of integers, and in clustered Virtual Memory
implementations they may be vectors. But in modern
machines they usually resolve to an integer.


I have no clue what you meant by this.  Please resubmit
and try again.  That some of the adresses are indirectly referred to
through a list means _nothing_.


It means a huge amount to the user(programmer), especially
if he/she erroneously tries to use a handle as an address.

And of course there is a third layer of abstraction here
because often times the address that compiler and VM writers
think of as the physical address is nothing of the sort
its just a bit of virtual space created by the OS
which then does another binding to the real RAM chips
(or magnetic tape, or optical drive or ferrite core or
whatever technology is providing the physical storage)

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-19 Thread boB Stepp
On Sun, Apr 19, 2015 at 4:05 PM, Dave Angel da...@davea.name wrote:
 On 04/19/2015 03:08 PM, boB Stepp wrote:


 Or is the real point that we are adding an abstraction
 layer so we don't even have to think about where objects are
 physically stored in RAM?


 Somebody keeps track, but the address is not necessarily constant, and not
 necessarily stored in any references.  The references (bindings) are
 abstract, and the details are unimportant to the user.  For example, the
 jython system does not use addresses at all.  And an object gets moved
 around from time to time without its references knowing it.

The last sentence in this paragraph has me intrigued. Why would an
object, once it has been created, be moved? What practical benefit
does doing this give?

boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Bill Allen
Everyone that responded,

Thanks very much for the excellent explanations!  The distinction between a
reference to an object and a seperate copy of the object is quite clear now.

--Bill
On Apr 18, 2015 1:44 AM, Alan Gauld alan.ga...@btinternet.com wrote:

 On 18/04/15 04:16, Bill Allen wrote:

 If I have a list defined as my_list = ['a','b','c'], what is the is
 differnce between refering to it as my_list or my_list[:]?   These seem
 equivalent to me.  Is that the case?  Is there any nuance I am missing
 here?   Situations where one form should be used as opposed to the other?


 Others have already given some good explanations.
 I'll add a slightly different take.

 Your confusion starts with your first statement:

  I have a list defined as my_list = ['a','b','c']

 What you should be saying is

 I have a list defined as ['a', 'b', 'c']

 Thats the list object that you are working with. The object is completely
 separate from the name that you choose to associate
 with it.

 You then bound that list to a name: my_list.
 You could bind it to any number of names but
 there would still only be one object:

 foo = my_list
 bar = foo
 baz = my_list

 Now I have 4 names all referring to the same list object.

 The next source of confusion comes from another mist-statement:

  differnce between refering to it as my_list or my_list[:]

 The [:] at the end is an operator that returns a copy of the list.
 So when you use it you are NOT referring to the original list
 at all. You are creating a new copy.

 So if we now take one of our previous names, say foo, and do:

 foo = my_list[:]

 foo no longer refers to your original list ['a','b','c']
 but to a completely new copy of that list.

 If you modify my_list the changes will show up when you look
 at bar and baz as well. But foo will be unchanged

 my_list[0] = 'z'
 print baz   - prints ['z','b','c'] - the same list as my_list
 print foo   - prints ['a','b','c'] - a different list object

 Understanding the separation of names from objects in Python is essential
 to understanding how it works. It is different to many
 other languages in this respect.

 And understanding the difference between identity and value is also
 important. Two completely different objects can have the same value
 and so appear the same but they are in fact entirely different.
 Think about two drivers who both buy the exact same model of car.
 They may look identical, but they are two separate cars.

 HTH
 --
 Alan G
 Author of the Learn to Program web site
 http://www.alan-g.me.uk/
 http://www.amazon.com/author/alan_gauld
 Follow my photo-blog on Flickr at:
 http://www.flickr.com/photos/alangauldphotos


 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 https://mail.python.org/mailman/listinfo/tutor

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Peter Otten
Bill Allen wrote:

 Everyone that responded,
 
 Thanks very much for the excellent explanations!  The distinction between
 a reference to an object and a seperate copy of the object is quite clear
 now.

You can test your newfound knowledge by predicting the output of the 
following script:


a = [1, [x, y], 3]
b = a[:]

a[1][1] = hello!

print(a) # [1, ['x', 'hello!'], 3]
print(b) # what will that print?

Think twice before you answer. What is copied, what is referenced?

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Bill Allen
print(b) will print the original copy of a which b now references which is
[1, [x, y], 3]
On Apr 18, 2015 7:50 AM, Peter Otten __pete...@web.de wrote:

 Bill Allen wrote:

  Everyone that responded,
 
  Thanks very much for the excellent explanations!  The distinction between
  a reference to an object and a seperate copy of the object is quite clear
  now.

 You can test your newfound knowledge by predicting the output of the
 following script:


 a = [1, [x, y], 3]
 b = a[:]

 a[1][1] = hello!

 print(a) # [1, ['x', 'hello!'], 3]
 print(b) # what will that print?

 Think twice before you answer. What is copied, what is referenced?

 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 https://mail.python.org/mailman/listinfo/tutor

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread boB Stepp
On Sat, Apr 18, 2015 at 3:28 PM, Bill Allen walle...@gmail.com wrote:
 On Apr 18, 2015 7:50 AM, Peter Otten __pete...@web.de wrote:

 Bill Allen wrote:

  Everyone that responded,
 
  Thanks very much for the excellent explanations!  The distinction between
  a reference to an object and a seperate copy of the object is quite clear
  now.

 You can test your newfound knowledge by predicting the output of the
 following script:


 a = [1, [x, y], 3]
 b = a[:]

 a[1][1] = hello!

 print(a) # [1, ['x', 'hello!'], 3]
 print(b) # what will that print?

 Think twice before you answer. What is copied, what is referenced?

 print(b) will print the original copy of a which b now references which is
 [1, [x, y], 3]

Uh, oh! You should have checked your work in the interpreter before
replying! Peter is being very tricky!! (At least for me...) Look again
at that list inside of a list and...

boB

P.S.: Watch out for top-posting. That tends to get peopled riled. I
moved your response back into the normal flow of the interleaved
conversation.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Bill Allen
On Apr 18, 2015 4:11 PM, boB Stepp robertvst...@gmail.com wrote:

 On Sat, Apr 18, 2015 at 3:28 PM, Bill Allen walle...@gmail.com wrote:
  On Apr 18, 2015 7:50 AM, Peter Otten __pete...@web.de wrote:
 
  Bill Allen wrote:
 
   Everyone that responded,
  
   Thanks very much for the excellent explanations!  The distinction
between
   a reference to an object and a seperate copy of the object is quite
clear
   now.
 
  You can test your newfound knowledge by predicting the output of the
  following script:
 
 
  a = [1, [x, y], 3]
  b = a[:]
 
  a[1][1] = hello!
 
  print(a) # [1, ['x', 'hello!'], 3]
  print(b) # what will that print?
 
  Think twice before you answer. What is copied, what is referenced?

  print(b) will print the original copy of a which b now references which
is
  [1, [x, y], 3]

 Uh, oh! You should have checked your work in the interpreter before
 replying! Peter is being very tricky!! (At least for me...) Look again
 at that list inside of a list and...

 boB

 P.S.: Watch out for top-posting. That tends to get peopled riled. I
 moved your response back into the normal flow of the interleaved

boB,

Ok, just tried it out.  In this example b=a and b=a[:] seem to yield the
same results even after the change to a, which I do not understand.  Should
not b be a copy of a and not reflect the change?

--bill
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread boB Stepp
On Sat, Apr 18, 2015 at 10:03 PM, Bill Allen walle...@gmail.com wrote:

 On Apr 18, 2015 4:11 PM, boB Stepp robertvst...@gmail.com wrote:

 On Sat, Apr 18, 2015 at 3:28 PM, Bill Allen walle...@gmail.com wrote:
  On Apr 18, 2015 7:50 AM, Peter Otten __pete...@web.de wrote:
 
  Bill Allen wrote:

[...]

  You can test your newfound knowledge by predicting the output of the
  following script:
 
 
  a = [1, [x, y], 3]
  b = a[:]
 
  a[1][1] = hello!
 
  print(a) # [1, ['x', 'hello!'], 3]
  print(b) # what will that print?
 
  Think twice before you answer. What is copied, what is referenced?

  print(b) will print the original copy of a which b now references which
  is
  [1, [x, y], 3]

 Uh, oh! You should have checked your work in the interpreter before
 replying! Peter is being very tricky!! (At least for me...) Look again
 at that list inside of a list and...

[...]

 Ok, just tried it out.  In this example b=a and b=a[:] seem to yield the
 same results even after the change to a, which I do not understand.  Should
 not b be a copy of a and not reflect the change?

Like you, I am on the path to learning Python, so I may or may not get
all the technical details correct, but here goes (I'm certain that if
I take any misstepps --pun intended!--that the ever-helpful crew of
professionals will set us both straight):

So far the emphasis on your original question has been on the
differences between 'references to objects' and the actual 'objects'.
I think that for the purpose of your question you can think about
'objects' as some sort of data stored someplace, though this is not
technically correct. When an item of data is stored, it is more
efficient to store it once and then from that point on use identifiers
(Which we are used to thinking of in most instances as 'variables'.)
to point to the storage location of that particular item of data. So
when you originally said something like:

my_list = ['a', 'b', 'c']

The ['a', 'b', 'c'] is the item of data stored and my_list is the
identifier identifying *where* this particular item of data is stored.
If you then do things like say:

some_other_identifier = my_list

then you just created a new identifier which gives the same location
information to exactly the same piece of data. However, fortunately
(Or, unfortunately, depending on your point of view.) you picked a
type of data -- a list -- that is *mutable*. Like mutations in
genetics, this just means that this item of data is capable of being
changed in place, i.e., where it is actually stored in memory. So if
Peter had said instead something like (Using the above statements.):

some_other_identifier[1] = 'Hello!'

I think you understand now that the originally *identified* list would
now be ['a', 'Hello!', 'c'] .

But Peter's actual example had a list inside of a list and BOTH of
these are objects (In our discussion, items of data.) and BOTH of
these have this property of being *mutable*. So he stuck an object
inside of another object, so to speak. And this inner object has
identifiers associated with it, too! Before Peter changed one of these
changeable objects, he had:

a = [1, [x, y], 3]
b = a[:]

Now BOTH a[1] and b[1] now identify the location of the inner list
object, [x, y] . Apparently, Python, in its ever efficient memory
management  fashion, when it creates the new object/piece of data
a[:], it sees no need to duplicate the inner list object, [x, y],
but instead creates another identifier/pointer/reference to this
object's location. But since this inner list object is mutable, when
you change y to hello! in b, you also change it in a because both
a[1][1] and b[1][1] reference/point to the exact same storage location
where this element of the inner list is actually stored.

I hope this is helpful, and, if there are any misstepps, that when
they are revealed both of our understandings will be enhanced!

boB Stepp
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Cameron Simpson

On 18Apr2015 22:03, Bill Allen walle...@gmail.com wrote:

On Apr 18, 2015 4:11 PM, boB Stepp robertvst...@gmail.com wrote:

On Sat, Apr 18, 2015 at 3:28 PM, Bill Allen walle...@gmail.com wrote:
 On Apr 18, 2015 7:50 AM, Peter Otten __pete...@web.de wrote:
 You can test your newfound knowledge by predicting the output of the
 following script:

 a = [1, [x, y], 3]
 b = a[:]

 a[1][1] = hello!

 print(a) # [1, ['x', 'hello!'], 3]
 print(b) # what will that print?

 Think twice before you answer. What is copied, what is referenced?

 print(b) will print the original copy of a which b now references which

is

 [1, [x, y], 3]

Uh, oh! You should have checked your work in the interpreter before
replying! Peter is being very tricky!! (At least for me...) Look again
at that list inside of a list and... [...]


Ok, just tried it out.  In this example b=a and b=a[:] seem to yield the
same results even after the change to a, which I do not understand.  Should
not b be a copy of a and not reflect the change?


Because is it a _shallow_ copy. Doing this:

 b = a[:]

produces a new list, referenced by b, with the _same_ references in it as 
a. a[1] is a reference to this list:


 [x, y]

b[1] is a reference to the _same_ list. So a[:] makes what is called a 
shallow copy, a new list with references to the same deeper structure.


So this:

 a[1][1] = hello!

affects the original x-y list, and both a and b reference it, so printing 
either shows the change.


By contrast, this:

 a[1] = [x, hello]

_replaces_ the reference in a with a reference to a new, different, list.

Sometimes you want a deep copy, where b would have got a copy of the 
iriginal x-y list. See the copy module's deepcopy function, which supplies 
this for when it is needed:


 https://docs.python.org/3/library/copy.html#copy.deepcopy

Cheers,
Cameron Simpson c...@zip.com.au

Draw little boxes with arrows.  It helps.   - Michael J. Eager
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread boB Stepp
On Sat, Apr 18, 2015 at 11:08 PM, Cameron Simpson c...@zip.com.au wrote:

 Sometimes you want a deep copy, where b would have got a copy of the
 iriginal x-y list. See the copy module's deepcopy function, which
 supplies this for when it is needed:

  https://docs.python.org/3/library/copy.html#copy.deepcopy

In this reference, part of it states:

Two problems often exist with deep copy operations that don’t exist
with shallow copy operations:

Recursive objects (compound objects that, directly or indirectly,
contain a reference to themselves) may cause a recursive loop.
Because deep copy copies everything it may copy too much, e.g.,
administrative data structures that should be shared even between
copies.

If I am understanding things correctly, should not that last sentence
read instead:

...structures that should *not* be shared even between copies. ???

-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Cameron Simpson

On 18Apr2015 23:26, boB Stepp robertvst...@gmail.com wrote:

On Sat, Apr 18, 2015 at 11:08 PM, Cameron Simpson c...@zip.com.au wrote:

Sometimes you want a deep copy, where b would have got a copy of the
iriginal x-y list. See the copy module's deepcopy function, which
supplies this for when it is needed:

 https://docs.python.org/3/library/copy.html#copy.deepcopy


In this reference, part of it states:

Two problems often exist with deep copy operations that don’t exist
with shallow copy operations:

Recursive objects (compound objects that, directly or indirectly,
contain a reference to themselves) may cause a recursive loop.
Because deep copy copies everything it may copy too much, e.g.,
administrative data structures that should be shared even between
copies.

If I am understanding things correctly, should not that last sentence
read instead:

...structures that should *not* be shared even between copies. ???


No, the text is correct.

Suppose you have a graph of objects where some single object A is referenced in 
mulitple places:


 /-- O1 v
 G   A
 \-- O2 ^

If I make a deepcopy of G I want this:

 /-- O1copy v
 Gcopy   Acopy
 \-- O2copy ^

i.e. a _single_ copy Acopy of A, again referenced from 2 places in the 
copied graph.


Without deepcopy()'s object tracking you would get something like this:

 /-- O1copy  Acopy1
 Gcopy 
 \-- O2copy  Acopy2

i.e. two distinct copies of A. Changes to Acopy1 would not affect Acopy2.

Cheers,
Cameron Simpson c...@zip.com.au

They said it couldn't be done/they said nobody could do it/
But he tried the thing that couldn't be done!/He tried - and he couldn't do it.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Cameron Simpson

On 19Apr2015 15:09, Cameron Simpson c...@zip.com.au wrote:

On 18Apr2015 23:26, boB Stepp robertvst...@gmail.com wrote:

On Sat, Apr 18, 2015 at 11:08 PM, Cameron Simpson c...@zip.com.au wrote:

Sometimes you want a deep copy, where b would have got a copy of the
iriginal x-y list. See the copy module's deepcopy function, which
supplies this for when it is needed:

https://docs.python.org/3/library/copy.html#copy.deepcopy


In this reference, part of it states:

Two problems often exist with deep copy operations that don’t exist
with shallow copy operations:

Recursive objects (compound objects that, directly or indirectly,
contain a reference to themselves) may cause a recursive loop.
Because deep copy copies everything it may copy too much, e.g.,
administrative data structures that should be shared even between
copies.

If I am understanding things correctly, should not that last sentence
read instead:

...structures that should *not* be shared even between copies. ???


No, the text is correct.


Um, my explaination was incomplete.

The first sentence quoted explains why it is necessary for deepcopy keep track 
of copied objects in order to correctly duplicate objects just once instead of 
twice or more, let alone in an unbounded way if there is a loop (A-B-C-A).  
It does this with a memo dictionary of already copied objects so it can know 
them when it sees them again.


The second sentence Because deep copy copies everything it may copy too much, 
e.g., administrative data structures that should be shared even between copies 
is an issuewhich is addressed lower down when mentioning the __copy_ and 
__deepcopy__ methods. And it is not necessarily obvious.


Suppose you've got a data structure of objects, which should broadly be copied.  
However, _internally_, these objects may use some external facility. Further, 
suppose that facility can't be copied; perhaps it is a reference to a databse 
or something built around something like that. Like this:


 G - A
   - B
   - _open_database

When you deepcopy that data sctructure you want to copy everything, but _not_ 
copy the external facility object. So for the above example, after the deepcopy 
you want this:


 Gcopy - Acopy
   - Bcopy
   - _open_database

i.e. the same reference to the database, but copies of A and B.

If you give G's class a .__deepcopy__ method, then that will be called by 
deepcopy() to make a copy of G by calling G.__deepcopy__(memodict). And G's 
class will define its __deepcopy__ method to copy A and B but not 
_open_database.


Most classes do not need this and deepcopy() just copies everything.

Does this clarify things?

Cheers,
Cameron Simpson c...@zip.com.au

No wonder these courtroom dramas are so popular. Half the population are
lawyers, judges, or some other kind of criminal.- Jake Vest 1986
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-18 Thread Alan Gauld

On 18/04/15 04:16, Bill Allen wrote:

If I have a list defined as my_list = ['a','b','c'], what is the is
differnce between refering to it as my_list or my_list[:]?   These seem
equivalent to me.  Is that the case?  Is there any nuance I am missing
here?   Situations where one form should be used as opposed to the other?


Others have already given some good explanations.
I'll add a slightly different take.

Your confusion starts with your first statement:

 I have a list defined as my_list = ['a','b','c']

What you should be saying is

I have a list defined as ['a', 'b', 'c']

Thats the list object that you are working with. The object is 
completely separate from the name that you choose to associate

with it.

You then bound that list to a name: my_list.
You could bind it to any number of names but
there would still only be one object:

foo = my_list
bar = foo
baz = my_list

Now I have 4 names all referring to the same list object.

The next source of confusion comes from another mist-statement:

 differnce between refering to it as my_list or my_list[:]

The [:] at the end is an operator that returns a copy of the list.
So when you use it you are NOT referring to the original list
at all. You are creating a new copy.

So if we now take one of our previous names, say foo, and do:

foo = my_list[:]

foo no longer refers to your original list ['a','b','c']
but to a completely new copy of that list.

If you modify my_list the changes will show up when you look
at bar and baz as well. But foo will be unchanged

my_list[0] = 'z'
print baz   - prints ['z','b','c'] - the same list as my_list
print foo   - prints ['a','b','c'] - a different list object

Understanding the separation of names from objects in Python is 
essential to understanding how it works. It is different to many

other languages in this respect.

And understanding the difference between identity and value is also 
important. Two completely different objects can have the same value

and so appear the same but they are in fact entirely different.
Think about two drivers who both buy the exact same model of car.
They may look identical, but they are two separate cars.

HTH
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-17 Thread Ben Finney
Ben Finney ben+pyt...@benfinney.id.au writes:

 Bill Allen walle...@gmail.com writes:

  If I have a list defined as my_list = ['a','b','c'], what is the is
  differnce between refering to it as my_list or my_list[:]?

 ‘my_list’ is a reference to the object you've already described (the
 existing object ‘['a', 'b', 'c']’).

 ‘my_list[:]’ is an operation that takes the original object and
 creates a new one by slicing. In this case, the new object happens to
 be equal to (but probably not identical to) the original, because of
 the slice you specified.

To demonstrate how identity differs from equality, use the appropriate
comparison operators::

$ python3

 foo = ['a', 'b', 'c']

 bar = foo # Bind the name ‘bar’ to the same object.
 bar   # Show me the object referred to by ‘bar’.
['a', 'b', 'c']
 bar == foo# Is the object ‘bar’ equal to the object ‘foo’?
True
 bar is foo# Is ‘bar’ referring to the same object as ‘foo’?
True

 baz = foo[:]  # Slice ‘foo’, creating a new list; bind ‘baz’ to that.
 baz   # Show me the object referred to by ‘baz’.
['a', 'b', 'c']
 baz == foo# Is the object ‘baz’ equal to the object ‘foo’?
True
 baz is foo# Is ‘baz’ referring to the same object as ‘foo’?
False

References which compare identical *are the same* object, guaranteed.
Object identity almost always implies equality.

(“almost always” because some object types have unusual behaviour like
“the object is not equal to itself”. Don't fret about that though, these
exceptions are clearly defined when you find them.)


References which compare equal *may under some conditions* be identical.
This is *not* ever a promise, though, and you should never rely on it,
not even in the same session of a program.

Some of Python's internal optimisations depend on the fact that object
equality *does not* imply object identity. If you happen to notice some
operations producing the same object at one point in time, but the
documentation doesn't promise it, then treat that as an unpredictable
implementation detail and don't rely on it in your code.

-- 
 \   “The best in us does not require the worst in us: Our love of |
  `\ other human beings does not need to be nurtured by delusion.” |
_o__) —Sam Harris, at _Beyond Belief 2006_ |
Ben Finney

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-17 Thread Dave Angel

On 04/17/2015 11:51 PM, Ben Finney wrote:

Ben Finney ben+pyt...@benfinney.id.au writes:


Bill Allen walle...@gmail.com writes:


If I have a list defined as my_list = ['a','b','c'], what is the is
differnce between refering to it as my_list or my_list[:]?


‘my_list’ is a reference to the object you've already described (the
existing object ‘['a', 'b', 'c']’).

‘my_list[:]’ is an operation that takes the original object and
creates a new one by slicing. In this case, the new object happens to
be equal to (but probably not identical to) the original, because of
the slice you specified.


To demonstrate how identity differs from equality, use the appropriate
comparison operators::

 $ python3

  foo = ['a', 'b', 'c']

  bar = foo # Bind the name ‘bar’ to the same object.
  bar   # Show me the object referred to by ‘bar’.
 ['a', 'b', 'c']
  bar == foo# Is the object ‘bar’ equal to the object ‘foo’?
 True
  bar is foo# Is ‘bar’ referring to the same object as ‘foo’?
 True

  baz = foo[:]  # Slice ‘foo’, creating a new list; bind ‘baz’ to that.
  baz   # Show me the object referred to by ‘baz’.
 ['a', 'b', 'c']
  baz == foo# Is the object ‘baz’ equal to the object ‘foo’?
 True
  baz is foo# Is ‘baz’ referring to the same object as ‘foo’?
 False

References which compare identical *are the same* object, guaranteed.
Object identity almost always implies equality.

(“almost always” because some object types have unusual behaviour like
“the object is not equal to itself”. Don't fret about that though, these
exceptions are clearly defined when you find them.)


References which compare equal *may under some conditions* be identical.
This is *not* ever a promise, though, and you should never rely on it,
not even in the same session of a program.

Some of Python's internal optimisations depend on the fact that object
equality *does not* imply object identity. If you happen to notice some
operations producing the same object at one point in time, but the
documentation doesn't promise it, then treat that as an unpredictable
implementation detail and don't rely on it in your code.



Great description, if the OP really wants that level of detail.  But I 
think what he needs to know first is:


If you change foo, like   (untested)
foo[1] = new

then you'll see that bar also changes (since it's just another name for 
the exact same object).

 bar
['a', 'new', 'c']

But baz does not, since it's bound to a copy of the object.
 baz
['a', 'b', 'c'\
--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-17 Thread Ben Finney
Bill Allen walle...@gmail.com writes:

 If I have a list defined as my_list = ['a','b','c'], what is the is
 differnce between refering to it as my_list or my_list[:]?

‘my_list’ is a reference to the object you've already described (the
existing object ‘['a', 'b', 'c']’).

‘my_list[:]’ is an operation that takes the original object and creates
a new one by slicing. In this case, the new object happens to be equal
to (but probably not identical to) the original, because of the slice
you specified.

 Is there any nuance I am missing here? Situations where one form
 should be used as opposed to the other?

You need to understand, when writing code, whether you are intending to
refer to the original object, or to create a new one. Neither is better,
they are both common but different operations.

-- 
 \  “Our products just aren't engineered for security.” —Brian |
  `\ Valentine, senior vice-president of Microsoft Windows |
_o__)development, 2002 |
Ben Finney

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] lists, name semantics

2015-04-17 Thread Martin A. Brown


Good evening Bill,

If I have a list defined as my_list = ['a','b','c'], what is the 
is differnce between refering to it as my_list or my_list[:]? 
These seem equivalent to me.  Is that the case?  Is there any 
nuance I am missing here?  Situations where one form should be 
used as opposed to the other?


Yes, there is a difference.  It can (conceivably) by subtle, but it 
is simple.


Let's start with the following.  I will call the list by the 
variable name l.  So, Python ('the computer') has stored the list in 
memory.  After executing this command, if I want to retrieve that 
data, I can call it by the variable named 'l':


  l = ['a', 'b', 'c']

Now consider the following two statements.

  case A:k = l
  case B:m = l[:]

These perform two different operations.  The first simply says Hey, 
when I refer to variable k, I want it to behave exactly like I had 
used the variable named l.  The second says Please give me a COPY 
of everything contained in the variable named l and let me refer to 
that as the variable named m.


What is the nuance of difference?  Where are the data stored in 
memory?  Let's take case A:


   l = ['a', 'b', 'c']
   k = l
   k == l
  True
   k is l
  True

So, you see, not only are k and l refer to the same list contents, 
but they point to the same place in computer memory where the list 
is stored.  The variables named l and k are just different names for 
the same thing (data).


Now, let's see what happens when we use case B, copying the list 
(strictly speaking you are slicing the entire list, see Python 
documentation).


   m = l[:]
   m == l
  True
   m is l
  False

What's different here?  Well, the variables m and l have the same 
contents, and are therefore equal (this will compare all elements of 
the list for equality).  But, m and l are not the same thing (data)! 
Though they contain the same data, the list contents are stored in 
different places in computer memory.


This subtlety means that you probably do not want to say my_list[:] 
unless you really want to use up all the memory to store the same 
data twice.  You may wish to do that, but given your question about 
nuance, I would point out that this is no nuance but a significant 
feature which can surprise you later if you do not understand what 
is happening with the slicing notation.


Best of luck and enjoy a fried slice of Python!

-Martin

 [0] 
https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range

--
Martin A. Brown
http://linux-ip.net/
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor