![](/style/images/good.png)
![](/style/images/bad.png)
Peculiar Self-References
source link: https://susam.in/blog/peculiar-self-references.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Peculiar Self-References
Peculiar Results
Here is a tiny Python example that creates a self-referential list and demonstrates the self-reference:
>>> a = a[0] = [0] >>> a [[...]] >>> a[0] [[...]] >>> a[0][0] [[...]] >>> a is a[0] True
The output shows that a[0]
refers to a
itself which makes it a self-referential list. Why does this simple
code create a self-referential list? Should it not have failed
with NameError
because a
is not yet
defined while assigning the list [0]
to a[0]
?
Here is another similar example that creates a self-referential list too:
>>> a = a[0] = [0, 0] >>> a [[...], 0]
Here is a similar example for dictionary:
>>> a = a[0] = {} >>> a {0: {...}}
Note that 0
is used as a dictionary key in the above
example. Here is another very simple example that uses a string key:
>>> a = a['k'] = {} >≫> a {'k': {...}}
The Language Reference
My first guess was that the statement
a = a[0] = [0]
behaves like
new = [0]
a = new
a[0] = new
which would indeed create a self-referential list.
Section 7.2 (Assignment statements) of The Python Language Reference confirms this behaviour. Quoting the relevant part from this section here:
Assignment statements are used to (re)bind names to values and to modify attributes or items of mutable objects:
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression) target_list ::= target ("," target)* [","] target ::= identifier | "(" [target_list] ")" | "[" [target_list] "]" | attributeref | subscription | slicing | "*" target
(See section Primaries for the syntax definitions for attributeref, subscription, and slicing.)
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
We see that the assignment statement is defined as follows:
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
Thus the statement
a = a[0] = [0]
has two target_list
elements (a
and a[0]
) and a starred_expression
element
([0]
). As a result, the same list on the
right-hand-side is assigned to both a
and a[0]
, from left to right, i.e., the
list [0]
is first assigned to a
,
then a[0]
is set to the same list. As a
result, a[0]
is set to a
itself.
The behaviour of the statement
a = a[0] = {}
can be explained in a similar way. The dictionary object on the
right-hand-side is first assigned to a
. Then a
key 0
is inserted within the same dictionary.
Finally the value of a[0]
is set to the same
dictionary. In other words, a[0]
is set
to a
itself.
More Experiments
The evaluation of the expression list on the right hand side first
and then assigning the result to each target list from left to right
explains the behaviour we observed in the previous sections. This
left-to-right assignment is quite uncommon among mainstream
programming languages. For example, in C, C++, Java, and JavaScript
the simple assignment operator (=
) has right-to-left
associativity. The left-to-right assignment in Python can be further
demonstrated with some intentional errors. Here is an example:
>>> a[0] = a = [0] Traceback (most recent call last): File "", line 1, in NameError: name 'a' is not defined
In this example, when the assignment to a[0]
to occurs,
the variable named a
is not defined yet, so it leads
to NameError
.
Here is another example:
>>> a = a[0] = 0 Traceback (most recent call last): File "", line 1, in TypeError: 'int' object does not support item assignment
In this example, 0
is first assigned to a
.
Then a[0]
needs to be evaluated before 0
can be assigned to it but this evaluation fails
because a
is an int
, a type that does not
support
subscription
(also known as indexing), so it fails with TypeError
.
© 2006–2021 Susam Pal
Recommend
-
176
Files Permalink Latest commit message Commit time
-
39
In front-end development, there are often times when I know that I don’t know something. I might know enough to know what CSS to search for, but I have absolutely no idea how to use it or what the right syntax is. Somehow...
-
30
README.md
-
2
Vim Peculiar Not just normal commands. Video introduction: Go to YouTube The idea behind the plugin is to provide shortcuts when working wit...
-
4
A Very Peculiar HistorySkip to main content Special offers and product promotions
-
3
OffHeap 66. Faster LTS releases? And A new Java license you say? How…peculiar
-
4
Show Us Your Odd Inputs And Peculiar Peripherals!
-
2
Year in review — Video games in 2022: Massive mergers and peculiar portables 2022 also saw the death of Stadia and the birth of gaming labor unions.
-
2
Knowing is half the battle - investigating a peculiar golang memory leak (1/2)Discover the powerful functionalities of pprof, where it can come in handy during times of bugs and memory leaks and how it may or may not impact...
-
3
KiZamaDo17's blog Very Peculiar...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK