0

So I ran into an issue.. I'm attempting to open a text file and read it line by line either normally or in reverse based on a variable's value. Python keeps throwing a AttributeError: __enter__ error; but I was mostly just trying to see if this is even possible.

Example code:

def function(rev):
    #    - open file in reverse format                        - open file normally
    with reversed(list(open("test.txt"))) if rev == True else open("test.txt") as dict:
        for line in dict:
            print (line)
            pass
        pass
    pass

function(True)

Result:

    ...
    with reversed(list(open("test.txt"))) if rev == True else open("test.txt") as dict:
AttributeError: __enter__

How can I do this without having to create a standard if statement for both possibilities & 2 different with-as loops for the same procedure?

BlackVikingPro
  • 27
  • 1
  • 2
  • 8
  • 1
    A list has no context manager interface and can not be used in a `with` block. Also in Python readability counts more than writing one-liners. – Klaus D. Oct 12 '19 at 04:09
  • 1
    I don't understand what you're trying to do. Why do you want to do this without a standard if statement? It is so much cleaner if you just say `if rev == True`, then read it in reverse. Else, don't. Akin to this answer, but with an if statement: https://stackoverflow.com/questions/2301789/read-a-file-in-reverse-order-using-python – Scott Skiles Oct 12 '19 at 04:10
  • Because there's a lot of code that uses the `line` variable the exact same way regardless of the order it comes in. Just eliminates having to copy/paste & creating more lines in the script. – BlackVikingPro Oct 12 '19 at 04:13

2 Answers2

1

There is some crazy business going on with context managers in Python. Try using a simple for statement instead, and regular for loops.

read_option.py

def my_function(rev):

    if rev == True:
        read_pattern = reversed(list(open("test.txt").readlines()))
    else:
        read_pattern = list(open("test.txt"))

    for line in read_pattern:
        print (line)

my_function(True)

If you really want a with statement, you might need to implement the __enter__ method in a class of your own. See this answer for more details: Python Error: AttributeError: __enter__

Example test.txt

abcd
efgh
ijlk

Output

(py36) [~]$ python3 read_option.py
ijlk

efgh

abcd
Scott Skiles
  • 3,647
  • 6
  • 40
  • 64
1

Don't do that in the with statement, your expression will generate two different objects (a list or a file object, list doesn't have context manager interface, file object does, this is why the error raised)

Just do it in two lines, and open first:

def function(rev):
    with open("test.txt") as fp:
        data = reversed(list(fp)) if rev == True else fp:
        for line in data:
            print(line)
function(True)
Scott Skiles
  • 3,647
  • 6
  • 40
  • 64
Xiao Tan
  • 376
  • 3
  • 12
  • This is a good alternative to the first answer, instead of having multiple lines including what I need, this does it in a single line. Thanks :) – BlackVikingPro Oct 12 '19 at 04:43