Explanation of list reference

S

Steven D'Aprano

What were we talking about again?

Two distinct objects with the same id(). I demonstrated a situation where
your claim:

id(x) == id(y) implies x is y


fails. I explained *twice* how to rescue your claim. In each case you
deleted my explanation, apparently unread. I can only conclude that you
are not actually engaging in this discussion in good faith.

For anyone else reading, id(x) == id(y) implies that x is y only if x and
y exist at the same time, in the same process. Python can re-use IDs, and
you cannot compare IDs from multiple processes.
 
S

Steven D'Aprano

'Identity' is an abstraction. For immutable objects, it is essentially
irrelevant. For mutable objects, it is essential in the following sense.
A and B are the same object if mutating A necessarily mutates B and
different if they can be independently mutated.

That's not quite right. See the earlier example in this thread about
numpy arrays. Since mutator methods can have side-effects, and objects
can act as proxies or views to other methods, we can't make any
conclusion about identity from the fact that mutation affects two or more
objects.

[Aside: I think the numpy array API is poor, since it doesn't make clear
the distinction between arrays which are being used as views to another
array, and arrays which are being used as independent arrays.]
 
M

Marko Rauhamaa

Marko Rauhamaa said:
Conceptually, the "everything is a reference" and the "small"/"big"
distinction are equivalent (produce the same outcomes). The question
is, which model is easier for a beginner to grasp.

Case in point, if everything is a reference, how come:
SyntaxError: invalid syntax


Marko
 
I

Ian Kelly

Case in point, if everything is a reference, how come:

SyntaxError: invalid syntax

You need parentheses around the 1. Otherwise you confuse the lexer, which
thinks you're starting a float literal.
'1'
 
J

Jussi Piitulainen

Marko Rauhamaa said:
Case in point, if everything is a reference, how come:

SyntaxError: invalid syntax

That's just a clash with number syntax. Once succesfully parsed, there
is no such difference:
'1'

(I'm not saying anything about anything being a reference, just that
your example didn't get analyzed to a level where there are things.)
 
I

Ian Kelly

You need parentheses around the 1. Otherwise you confuse the lexer, which
thinks you're starting a float literal.

'1'

Or if the parentheses bother you, you can also just toss in some whitespace:
'1'
 
S

Steven D'Aprano

Case in point, if everything is a reference, how come:

SyntaxError: invalid syntax

Because it is a syntax error, just like the parser tells you. When the
parser sees "1." it expects a floating point number, and "1.__str__()" is
not a legal float.

There are three simple ways to get the effect that you want:

py> x = 1; x.__str__() # don't use a literal
'1'
py> (1).__str__() # parenthesize the literal
'1'
py> 1 .__str__() # offset it from the dot with a space
'1'
 
C

Chris Angelico

There are three simple ways to get the effect that you want:

py> x = 1; x.__str__() # don't use a literal
'1'
py> (1).__str__() # parenthesize the literal
'1'
py> 1 .__str__() # offset it from the dot with a space
'1'
Four:
'1'

ChrisA
 
M

Marko Rauhamaa

Steven D'Aprano said:
id(x) == id(y) implies x is y

fails.

My from-the-hip formulation can obviously be inaccurate, but I was
hoping the point was clear.

The Python language specification feels the need to introduce the
nebulous concept of "object lifetime." I believe that concept can be
more confusing than useful. Compare that with Common Lisp, whose objects
are by definition eternal; there's no garbage collection. Practical
implementations do collect garbage, but that's an optimization that
doesn't affect the observed output of a program.

It is possible to define id() without making any references to the
object lifetime.

Let's, then, make a more satisfactory attempt at specifying id():

1. For any argument, the function

id

returns an integer.

2. For any pair of arguments, the function

lambda x, y: (id(x) == id(y)) == (x is y)

returns True.

That should cover all valid implementations and uses of id().


Marko
 
C

Chris Angelico

Fair enough.

The syntactic awkwardness, then, explains why numbers don't have an
evolved set of methods (unlike strings).

No; it's more that numbers are more often used with either operators
or polymorphic functions. Yes, you can add strings together with +,
but with numbers, you also subtract them, multiply them (okay, you can
multiply a string by a number, but that kinda counts one to each), and
divide them (some languages let you divide a string by a string, but
Python does that with the .split() method). There are only two types
of string, and arguably one of them is more an array of bytes than it
is a string; but with numbers, you have
int/float/complex/Fraction/Decimal, and rather than create methods
that have to be implemented by each, there are stand-alone functions
instead.

Strings get methods:' asdf '

Numbers get functions:7.1180162044653335

Sometimes the line is blurred:Help on built-in function trunc in module math:

trunc(x)
Truncates x to the nearest Integral toward 0. Uses the __trunc__
magic method.

Which could have been done as x.trunc() instead:
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
(1+0j).__trunc__
AttributeError: 'complex' object has no attribute '__trunc__'Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
math.trunc(1+0j)
TypeError: type complex doesn't define __trunc__ method

But in a lot of cases, it makes good sense to have a single function
that can take many types of number (since, after all, it's possible to
define a lot of functions in terms of the basic operators), whereas
doing them as methods would entail duplicating code.

Partly it's just a matter of expectations. People expect strings to
have more methods and numbers to use more operators, so a string
method is discoverable and an int method is less so. (When was the
last time *you* checked to see what methods an int has?)

ChrisA
 
S

Steven D'Aprano

Fair enough.

The syntactic awkwardness, then, explains why numbers don't have an
evolved set of methods (unlike strings).

But numbers do have an evolved set of methods.


py> [name for name in vars(int) if not name.startswith("_")]
['numerator', 'imag', 'to_bytes', 'from_bytes', 'bit_length', 'real',
'conjugate', 'denominator']

py> [name for name in vars(float) if not name.startswith("_")]
['fromhex', 'imag', 'as_integer_ratio', 'is_integer', 'hex', 'real',
'conjugate']

py> [name for name in vars(complex) if not name.startswith("_")]
['imag', 'real', 'conjugate']


To say nothing of these numbers:

py> from decimal import Decimal
py> [name for name in vars(Decimal) if not name.startswith("_")]
['canonical', 'exp', 'to_integral_value', 'logical_xor', 'imag',
'same_quantum', 'log10', 'max_mag', 'is_snan', 'to_eng_string', 'ln',
'is_normal', 'min', 'is_subnormal', 'to_integral_exact', 'is_nan',
'logb', 'is_qnan', 'logical_or', 'radix', 'real', 'max', 'normalize',
'as_tuple', 'is_canonical', 'is_zero', 'copy_negate', 'min_mag',
'next_plus', 'is_finite', 'number_class', 'scaleb', 'is_signed',
'compare_total', 'next_toward', 'adjusted', 'fma', 'rotate',
'logical_and', 'from_float', 'to_integral', 'next_minus',
'remainder_near', 'compare_signal', 'quantize', 'is_infinite',
'copy_sign', 'shift', 'compare_total_mag', 'copy_abs', 'compare',
'conjugate', 'logical_invert', 'sqrt']


That's more methods than strings have:

py> len([name for name in vars(Decimal) if not name.startswith("_")])
54
py> len([name for name in vars(str) if not name.startswith("_")])
44
 
R

Rustom Mody

Mark Lawrence:
Luckily, what we are now debating is mostly terminology and points of
view where the outcomes are unaffected.
However, as an example, it is important to know if you should write:
if x is not None:
...
if x != None:
...
is more robust.

Yes This is my main beef:
Not that both are possible but that the first is *recommended* and the second not.

Something like a C compiler manual advising:
You can write x*8 but its better to drop out into asm and write
shl $3, %eax
 
M

Marko Rauhamaa

Steven D'Aprano said:
The syntactic awkwardness, then, explains why numbers don't have an
evolved set of methods (unlike strings).

But numbers do have an evolved set of methods.
[...]
py> from decimal import Decimal
py> [name for name in vars(Decimal) if not name.startswith("_")]
['canonical', 'exp', 'to_integral_value', 'logical_xor', 'imag',
'same_quantum', 'log10', 'max_mag', 'is_snan', 'to_eng_string', 'ln',
'is_normal', 'min', 'is_subnormal', 'to_integral_exact', 'is_nan',
'logb', 'is_qnan', 'logical_or', 'radix', 'real', 'max', 'normalize',
'as_tuple', 'is_canonical', 'is_zero', 'copy_negate', 'min_mag',
'next_plus', 'is_finite', 'number_class', 'scaleb', 'is_signed',
'compare_total', 'next_toward', 'adjusted', 'fma', 'rotate',
'logical_and', 'from_float', 'to_integral', 'next_minus',
'remainder_near', 'compare_signal', 'quantize', 'is_infinite',
'copy_sign', 'shift', 'compare_total_mag', 'copy_abs', 'compare',
'conjugate', 'logical_invert', 'sqrt']

That's more like it!

Alas:
1.4142135623730951

Also, unfortunately:
AttributeError: 'int' object has no attribute 'hex'

There's still some evolving to do. The "smallness" of numbers is still
shining through.


Marko
 
N

Ned Batchelder

Yes This is my main beef:
Not that both are possible but that the first is *recommended* and the second not.

I'm not sure why you don't like the recommendation, or if you just want
people to be more explicit about why it is recommended. My main reason
for preferring "x is not None" is that if x's class defines __ne__
incorrectly, "x != None" can come out wrong. And yes, I have actually
debugged problems where that was the root cause.

If you use "x is not None", nothing about x's class can interfere with
the correct operation.
 
R

Rustom Mody

I'm not sure why you don't like the recommendation, or if you just want
people to be more explicit about why it is recommended. My main reason
for preferring "x is not None" is that if x's class defines __ne__
incorrectly, "x != None" can come out wrong. And yes, I have actually
debugged problems where that was the root cause.
If you use "x is not None", nothing about x's class can interfere with
the correct operation.

Ok
But for that Ive to use is
And as a teacher Ive to explain is
Might as well use C and get on with pointers

To me 'is' is a can of worms
Mostly I dont need to open that can
In the few instances when I need to open it, I am allowed (I hope!)
to say "Ugh!"
 
M

Marko Rauhamaa

Rustom Mody said:
But for that Ive to use is
And as a teacher Ive to explain is
Might as well use C and get on with pointers

To me 'is' is a can of worms

I'm not against "is," but it must be carefully defined and taught.

As far as "x is None" is concerned, a key piece of information is
presented on <URL: http://docs.python.org/3.2/library/constants.html>:

None
The sole value of the type NoneType.

Unfortunately the page is a bit confusing. It says:

A small number of constants live in the built-in namespace.

So an essential characteristic of the None object (uniqueness) is
mentioned in the middle of the discussion on the built-in namespace. The
index doesn't contain an entry on NoneType.

Thus, there might still be a nagging concern that a second NoneType
object x such that

x == None and x is not None

could crop up (from native code, perhaps).


Marko
 
M

Mark Lawrence

I'm not against "is," but it must be carefully defined and taught.

As far as "x is None" is concerned, a key piece of information is
presented on <URL: http://docs.python.org/3.2/library/constants.html>:

None
The sole value of the type NoneType.

Unfortunately the page is a bit confusing. It says:

A small number of constants live in the built-in namespace.

So an essential characteristic of the None object (uniqueness) is
mentioned in the middle of the discussion on the built-in namespace. The
index doesn't contain an entry on NoneType.

Thus, there might still be a nagging concern that a second NoneType
object x such that

x == None and x is not None

could crop up (from native code, perhaps).


Marko

Patches are always welcome :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,231
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top