How with open works? - python-3.x

Today I was trying to open a file and build some list from the data of the file. I am using the with statement. But I have the following doubt:
If I write the following code:
def Preset_wheel_filler(self):
"""
Complete the Preset_wheel and also apply preset values when one
preset is selected.
"""
with open('Preset.txt', 'r') as PresetFile:
Presets = [line.split()[1:] for line in PresetFile if 'name:'
in line.split()]
with open('Preset.txt', 'r') as PresetFile:
channel_list = ['1', '2', '3', '4', '5', '6', '7', '8']
Preset_values = [line.split() for line in PresetFile for
y in channel_list if y in line.split()]
print(len(Preset_values))
The length of the last list created is 16. (Which is correct)
Now, if I rearrange the code like this:
def Preset_wheel_filler(self):
"""
Complete the Preset_wheel and also apply preset values when one
preset is selected.
"""
with open('Preset.txt', 'r') as PresetFile:
Presets = [line.split()[1:] for line in PresetFile if 'name:'
in line.split()]
channel_list = ['1', '2', '3', '4', '5', '6', '7', '8']
Preset_values = [line.split() for line in PresetFile for
y in channel_list if y in line.split()]
print(len(Preset_values))
The printed length is 0.
My question is: Why should I write the with open statement twice?
Thanks in advance.

Files are stream based. Once you read all the data in the file its position pointer is at the end and nothing can be read anymore. You "could" seek to 0 to fix that, but - you have the full line in the first go, simply parse both things from it.
PresetFile.seek(0) # goes back to the beginning of the file.
See https://docs.python.org/3/tutorial/inputoutput.html#methods-of-file-objects
for details on how to use seek and maybee peek into https://docs.python.org/3/library/functions.html#open
again.

Related

Concat multiple CSV rows into 1 in python

I am trying to contact the CSV rows. I tried to convert the CSV rows to list by pandas but it gets 'nan' values appended as some files are empty.
Also, I tried using zip but it concats column values.
with open(i) as f:
lines = f.readlines()
res = ""
for i, j in zip(lines[0].strip().split(','), lines[1].strip().split(',')):
res += "{} {},".format(i, j)
print(res.rstrip(','))
for line in lines[2:]:
print(line)
I have data as below,
Input data:-
Input CSV Data
Expected Output:-
Output CSV Data
The number of rows are more than 3,only sample is given here.
Suggest a way which will achieve the above task without creating a new file. Please point to any specific function or sample code.
This assumes your first line contains the correct amount of columns. It will read the whole file, ignore empty data ( ",,,,,," ) and accumulate enough data points to fill one row, then switch to the next row:
Write test file:
with open ("f.txt","w")as f:
f.write("""Circle,Year,1,2,3,4,5,6,7,8,9,10,11,12
abc,2018,,,,,,,,,,,,
2.2,8.0,6.5,9,88,,,,,,,,,,
55,66,77,88,,,,,,,,,,
5,3.2,7
def,2017,,,,,,,,,,,,
2.2,8.0,6.5,9,88,,,,,,,,,,
55,66,77,88,,,,,,,,,,
5,3.2,7
""")
Process test file:
data = [] # all data
temp = [] # data storage until enough found , then put into data
with open("f.txt","r") as r:
# get header and its lenght
title = r.readline().rstrip().split(",")
lenTitel = len(title)
data.append(title)
# process all remaining lines of the file
for l in r:
t = l.rstrip().split(",") # read one lines data
temp.extend( (x for x in t if x) ) # this eliminates all empty ,, pieces even in between
# if enough data accumulated, put as sublist into data, keep rest
if len (temp) > lenTitel:
data.append( temp[:lenTitel] )
temp = temp [lenTitel:]
if temp:
data.append(temp)
print(data)
Output:
[['Circle', 'Year', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
['abc', '2018', '2.2', '8.0', '6.5', '9', '88', '55', '66', '77', '88', '5', '3.2', '7'],
['def', '2017', '2.2', '8.0', '6.5', '9', '88', '55', '66', '77', '88', '5', '3.2', '7']]
Remarks:
your file cant have leading newlines, else the size of the title is incorrect.
newlines in between do not harm
you cannot have "empty" cells - they get eliminated
As long as nothing weird is going on in the files, something like this should work:
with open(i) as f:
result = []
for line in f:
result += line.strip().split(',')
print(result)

Python 3.6 - How to search through a 2D list and return true or false if an item matches user input

I am using EDX to start learning python and I am stuck in a project that requires me to create a tic tac toe game.
I believe I have managed to complete most of the functions but when I tried to run the function that checks whether a position is available to be marked as X or O, I always get a false reading. It returns true only for the 7 and not for the rest of the items.
board = [['7', '8', '9'], ['4', '5', '6'], ['1', '2', '3']]
location = input(" Turn, select a number (1, 9): ")
def available(location, board):
for row in board:
for col in row:
if col==location:
return True
else:
return False
print(available(location,board))
I decided to separate the function from the rest of the code. The code above should be able to search the 2D list and if it finds the number that the user has entered to return true or false. When it does that another function is executed to change that number to X or O depending the player. I tried to run the function without the function and with print instead of return and works fine.
board = [['7', '8', '9'], ['4', '5', '6'], ['1', '2', '3']]
location = input(" Turn, select a number (1, 9): ")
for row in board:
for col in row:
if col==location:
print("True")
else:
print("False")
Any idea what I am doing wrong?
Let's look at your if else statement.
When the input number is not 7, we do not return true, instead we go to the else and immediately return false without checking the rest of the numbers.
The solution is to remove the else, and just return false only after iterating through every cell.
When you change the returns to prints this bug disappears because you are no longer returning, and therefore execution doesn't stop early.
def available(location, board):
for row in board:
for col in row:
if col==location:
return True
return False
The key insight here is that returning from a function, exits the function.
To overcome the problem you identified, you could for instance flatten your list by using a list comprehension and check for the existence of location in it:
board = [['7', '8', '9'], ['4', '5', '6'], ['1', '2', '3']]
location = input(" Turn, select a number (1, 9): ")
def available(location, board):
#collect all elements from all sublists in a list
allfields = [i for j in board for i in j]
#location element of this list?
if location in allfields:
return True
return False
print(available(location,board))
You can use any for a more Pythonic version.
def available(location, board):
return any(any(i == location for i in row) for row in board)

LPTHW 48: nosetest says AttributeError: 'str' object has no attribute ' ' while output seems correct?

I'm working on LPTHW and I'm trying to understand my error.
This is my code:
class lexicon:
def __init__(self, words):
self.words = words
def scan(self):
direction = ['north', 'south', 'east', 'west']
verb = ['go', 'stop', 'kill', 'eat']
stop = ['the', 'in', 'of', 'from', 'at', 'it']
noun = ['door', 'bear', 'princess', 'cabinet']
number = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
thewords = self.words.split()
output = []
for i in thewords:
if i in direction:
output.append(('direction', i ))
print(output)
lexicon('north').scan()
I've put in the print statement to check if the output is correct. The actual output:
[('direction', 'north')]
I'm trying to get my nose test script running with this:
from nose.tools import *
from ex48 import lexicon
def test_directions():
assert_equal(lexicon.scan("north"), [('direction', 'north')])
But when I execute it:
thewords = self.words.split()
AttributeError: 'str' object has no attribute 'words'
The output of the script seems to match what the nose script expects, a tupil with those values. But the error seems to say that I gave it a string and it wants something else? I've searched on the error message but I can't wrap my head around what it's trying to tell me here.
Can somebody explain what I'm doing wrong here?

Matrix input from a text file(python 3)

Im trying to find a way to be able to input a matrix from a text file;
for example, a text file would contain
1 2 3
4 5 6
7 8 9
And it would make a matrix with those numbers and put it in matrix = [[1,2,3],[4,5,6],[7,8,9]]
And then this has to be compatible with the way I print the matrix:
print('\n'.join([' '.join(map(str, row)) for row in matrix]))
So far,I tried this
chemin = input('entrez le chemin du fichier')
path = input('enter file location')
f = open ( path , 'r')
matrix = [ map(int,line.split(','))) for line in f if line.strip() != "" ]
All it does is return me a map object and return an error when I try to print the matrix.
What am I doing wrong? Matrix should contain the matrix read from the text file and not map object,and I dont want to use external library such as numpy
Thanks
You can use list comprehension as such:
myfile.txt:
1 2 3
4 5 6
7 8 9
>>> matrix = open('myfile.txt').read()
>>> matrix = [item.split() for item in matrix.split('\n')[:-1]]
>>> matrix
[['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]
>>>
You can also create a function for this:
>>> def matrix(file):
... contents = open(file).read()
... return [item.split() for item in contents.split('\n')[:-1]]
...
>>> matrix('myfile.txt')
[['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]
>>>
is working with both python2(e.g. Python 2.7.10) and python3(e.g. Python 3.6.4)
rows=3
cols=3
with open('in.txt') as f:
data = []
for i in range(0, rows):
data.append(list(map(int, f.readline().split()[:cols])))
print (data)

Why may this construction be not working?

I receive, that first iteration 1 is not a number.
numbers = ['1', 'apple', '2', '3', '4', '5']
print ('Your numbers are...')
for f in numbers:
if f.isalpha():
print ('This is not a number!') # (It actually isn't.)
break
print (f)
else:
print ('Here are your numbers!')
You're seeing this...
Your numbers are...
Then you hit the first iteration, f = '1' and print (f):
1
Then you get to the second iteration, f = 'apple' and print ('This is not a number!')...
This is not a number!
This is to be expected.
Your output would be clearer with this program:
#!/usr/bin/env python3
numbers = ['1', 'apple', '2', '3', '4', '5']
print ('Your numbers are...')
for f in numbers:
if f.isalpha():
print('{} is not a number!'.format(f))
break
else:
print('Here are your numbers: {}'.format(numbers))

Resources