This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: incorrect printing behavior with parenthesis symbols
Type: behavior Stage: resolved
Components: Versions: Python 3.8
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: eric.smith, rameshsahoo11, steven.daprano
Priority: normal Keywords:

Created on 2020-08-10 18:56 by rameshsahoo11, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (9)
msg375136 - (view) Author: Ramesh Sahoo (rameshsahoo11) Date: 2020-08-10 18:56
With for loop, I am able to print all elements in the list 'a'

a = ['a','a','b','b','c']
for i in a:
    print(i)

O/P: 

a
a
b
b
c

but with the following loop, python only prints 3 uniq elements instead of 5. 

stack = ['(', '(', '[', ']', ')']
for i in stack:
    print(i)

O/P: 
(
]
)


Is this is intended behavior?
msg375142 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2020-08-10 19:08
Here's what I see:

Python 3.6.9 (default, Jul 21 2019, 14:33:59)
[GCC 7.4.0] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> stack = ['(', '(', '[', ']', ')']
>>> for i in stack:
...     print(i)
...
(
(
[
]
)

That looks correct to me. What exact version of 3.6 are you using, and on what platform?
msg375148 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2020-08-10 19:59
Also, how are you running this? From the interactive shell (like I show in my previous message), or some other way?
msg375156 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-08-10 23:18
Python 3.6 has reached security-fix only stage:

https://www.python.org/dev/peps/pep-0494/#schedule-last-bugfix-release

so even if this is a bug, it won't be fixed in 3.6.

I cannot reproduce this in 3.7, and Eric cannot reproduce in 3.6.9, so I'm closing the issue. Please re-open if you can reproduce in 3.8 or better. (3.7 is also only accepting security fixes only.)

(Eric do you concur? If you disagree please feel free to re-open.)
msg375158 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2020-08-11 00:02
I agree, Steven.

This doesn't seem to be a problem with Python. It's more likely a problem with the user's shell, or some other environment integration problem. If it can be duplicated in 3.8 or later, we can investigate further.
msg375164 - (view) Author: Ramesh Sahoo (rameshsahoo11) Date: 2020-08-11 07:16
Hi all,

Thanks for your valuable response. I would like to inform you that I found this issue while playing with the following code. This is reproducible with Python 3.8. 

Please find the following details and let me know if I am doing something wrong. 


[Using for loop popping elements]

import sys
stack,braces = [],{'(':')','{':'}','[':']'}
stack = [s for s in "(([])"]
c = 0
print(f"Python version: {sys.version}")
print(f"Before for loop:\nbraces.keys = {braces.keys()}\nbraces.items = {braces.items()}\nstack = {stack}\n\n")

for i in stack:
    c += 1
    print(f"{'='*10} loop {c} {'='*10}")
    print("just after for loop stack =",stack)
    print(f"Just after for loop i =",i)
    print(f"Just after for loop: Is i'{i}' found in braces.keys:{i in braces.keys()}")

    if i in braces.keys():
        print(f"inside if i = {i}")
        print("inside if stack =",stack)
        print("inside if Popped =",stack.pop(stack.index(i)))
        print(f"inside if after popped stack = {stack}\n")
        continue

    else:
        print(f"in else: Is i'{i}' found in braces.keys:{i in braces.keys()}")
        print(f"in else stack = {stack}\n")


[Program Output]

$ python3 test1.py 

Python version: 3.8.0 (default, Nov 14 2019, 22:29:45) 
[GCC 5.4.0 20160609]

Before for loop:
braces.keys = dict_keys(['(', '{', '['])
braces.items = dict_items([('(', ')'), ('{', '}'), ('[', ']')])
stack = ['(', '(', '[', ']', ')']

========== loop 1 ==========
just after for loop stack = ['(', '(', '[', ']', ')']
Just after for loop i = (
Just after for loop: Is i'(' found in braces.keys:True
inside if i = (
inside if stack = ['(', '(', '[', ']', ')']
inside if Popped = (
inside if after popped stack = ['(', '[', ']', ')']

========== loop 2 ==========
just after for loop stack = ['(', '[', ']', ')']
Just after for loop i = [
Just after for loop: Is i'[' found in braces.keys:True
inside if i = [
inside if stack = ['(', '[', ']', ')']
inside if Popped = [
inside if after popped stack = ['(', ']', ')']

========== loop 3 ==========
just after for loop stack = ['(', ']', ')']
Just after for loop i = )
Just after for loop: Is i')' found in braces.keys:False
in else: Is i')' found in braces.keys:False
in else stack = ['(', ']', ')']


[Summary]

stack = ['(', '(', '[', ']', ')']
=> [loop 1] is correct where the right element "(" has been popped.

['(', '[', ']', ')']
=> [loop 2] "(" element should have been popped but "[" chosen to be popped. This seems to be incorrect.

=> There must be 5 iterations(3 in if block and 2 in else block) but loop completed with 3 iterations(2 in if and one in else).  


I am not sure if I am doing something wrong or it is a buggy behavior. 



[Popping elements manually gives correct behavior]

import sys
print(f"Python Version: {sys.version}")

stack,braces = [],{'(':')','{':'}','[':']'}
stack = [s for s in "(([])"]

print(f"Original:\nbraces.keys = {braces.keys()}\nbraces.items = {braces.items()}\nstack = {stack}\n\n")

# Popping '('
print(f"Popped {stack.pop(stack.index('('))}")
print(f"stack after popping '(' = {stack}")

# Popping '('
print(f"Popped {stack.pop(stack.index('('))}")
print(f"stack after popping '(' = {stack}")

# Popping '['
print(f"Popped {stack.pop(stack.index('['))}")
print(f"stack after popping '[' = {stack}")


[Program Output]
Python Version: 3.8.0 (default, Nov 14 2019, 22:29:45) 
[GCC 5.4.0 20160609]
Original:
braces.keys = dict_keys(['(', '{', '['])
braces.items = dict_items([('(', ')'), ('{', '}'), ('[', ']')])
stack = ['(', '(', '[', ']', ')']
Popped (
stack after popping '(' = ['(', '[', ']', ')']
Popped (
stack after popping '(' = ['[', ']', ')']
Popped [
stack after popping '[' = [']', ')']
msg375165 - (view) Author: Ramesh Sahoo (rameshsahoo11) Date: 2020-08-11 07:34
Additional note: 

The following program completes all 5 iterations.  

#!/usr/bin/python3
stack = [s for s in range(5)]
c = 0
for i in stack:
  c += 1
  print(f"{'='*10} loop {c} {'='*10}")
  if i == 0 or i == 1 or i == 2:
    print(f"{i}\n")
  else:
    print(f"{i}\n")


$ python3 test1.py 
========== loop 1 ==========
0

========== loop 2 ==========
1

========== loop 3 ==========
2

========== loop 4 ==========
3

========== loop 5 ==========
4
msg375168 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-08-11 09:59
On Tue, Aug 11, 2020 at 07:16:20AM +0000, Ramesh Sahoo wrote:

> for i in stack:
>         print("inside if Popped =",stack.pop(stack.index(i)))

You are mutating the list while you iterate over it. This is prone to 
cause trouble. Here's is a much smaller and simpler demonstration:

items = [1, 2, 3, 4, 5]
for index, value in enumerate(items):
    print(f"index: {index}, value: {value}, items: {items}")
    if value == 2:
        x = items.pop(index)
        print(f"after popping 2: {items}")

which has output:

index: 0, value: 1, items: [1, 2, 3, 4, 5]
index: 1, value: 2, items: [1, 2, 3, 4, 5]
after popping 2: [1, 3, 4, 5]
index: 2, value: 4, items: [1, 3, 4, 5]
index: 3, value: 5, items: [1, 3, 4, 5]

If you trace the code execution in your head, you will see that this is 
correct behaviour: Python is walking the list from position to position, 
but you removed one of the values so everything shifts and you end up 
skipping a value, because it moves before the loop can reach it.

The lesson here is:

Don't mutate a list that you are iterating over if you can avoid it. It 
you cannot avoid it, you can avoid problems by iterating in reverse, and 
only mutating the part of the list you have already processed.

But better to avoid mutation altogether.

So not a bug. Python is doing exactly what you told it to do.
msg375194 - (view) Author: Ramesh Sahoo (rameshsahoo11) Date: 2020-08-11 19:10
Thank Steven for correcting and guiding me.
History
Date User Action Args
2022-04-11 14:59:34adminsetgithub: 85690
2020-08-11 19:17:20Jeffrey.Kintschersetnosy: - Jeffrey.Kintscher
2020-08-11 19:10:27rameshsahoo11setmessages: + msg375194
2020-08-11 10:02:14eric.smithsetstatus: open -> closed
resolution: not a bug
2020-08-11 09:59:52steven.dapranosetmessages: + msg375168
2020-08-11 07:34:14rameshsahoo11setmessages: + msg375165
2020-08-11 07:16:35rameshsahoo11setresolution: works for me -> (no value)
2020-08-11 07:16:20rameshsahoo11setstatus: closed -> open

messages: + msg375164
versions: + Python 3.8, - Python 3.6
2020-08-11 00:02:19eric.smithsetmessages: + msg375158
2020-08-10 23:18:35steven.dapranosetstatus: open -> closed

nosy: + steven.daprano
messages: + msg375156

resolution: works for me
stage: resolved
2020-08-10 22:44:05Jeffrey.Kintschersetnosy: + Jeffrey.Kintscher
2020-08-10 19:59:33eric.smithsetmessages: + msg375148
2020-08-10 19:08:20eric.smithsetnosy: + eric.smith
messages: + msg375142
2020-08-10 18:56:50rameshsahoo11create