Attribute Error: 'list' object has no attribute 'split'
Asked Answered
S

4

28

I am trying read a file and split a cell in each line by a comma and then display only the first and the second cells which contain information regarding the latitude and the longitude. This is the file:

time,latitude,longitude,type
2015-03-20T10:20:35.890Z,38.8221664,-122.7649994,earthquake
2015-03-20T10:18:13.070Z,33.2073333,-116.6891667,earthquake
2015-03-20T10:15:09.000Z,62.242,-150.8769,earthquake

My program:

def getQuakeData():
    filename = input("Please enter the quake file: ")
    readfile = open(filename, "r")
    readlines = readfile.readlines()

    Type = readlines.split(",")
    x = Type[1]
    y = Type[2]
    for points in Type:
        print(x,y)
getQuakeData()

When I try to execute this program, it gives me an error

AttributeError: 'list' object has no attribute 'split'

Please help me!

Spic answered 5/5, 2015 at 0:30 Comment(5)
Because list has no split() only string objects have splitDipetalous
readlines() returns a list. You have to use split() on each string in that list.Sabinasabine
Read the error closely. You are trying split readlines, which is a list. That cannot be done.Stein
Why are you using readlines in the first place? If you just want the first line as one string, that's readline. If you want the whole file as one giant string, that's read. If you want a list or other iterable of lines, you can use readlines for that, but you can also just use the file itself, so it's still not useful.Ivette
As a side note, you might want to consider using the csv module here. Especially if there's actually a header line; then you could use for row in csv.DictReader(readfile): and then your values are row['latitude'] and row['longitude'] instead of row[1] and row[2], which might be more readable.Ivette
I
36

I think you've actually got a wider confusion here.

The initial error is that you're trying to call split on the whole list of lines, and you can't split a list of strings, only a string. So, you need to split each line, not the whole thing.

And then you're doing for points in Type, and expecting each such points to give you a new x and y. But that isn't going to happen. Types is just two values, x and y, so first points will be x, and then points will be y, and then you'll be done. So, again, you need to loop over each line and get the x and y values from each line, not loop over a single Types from a single line.

So, everything has to go inside a loop over every line in the file, and do the split into x and y once for each line. Like this:

def getQuakeData():
    filename = input("Please enter the quake file: ")
    readfile = open(filename, "r")

    for line in readfile:
        Type = line.split(",")
        x = Type[1]
        y = Type[2]
        print(x,y)

getQuakeData()

As a side note, you really should close the file, ideally with a with statement, but I'll get to that at the end.


Interestingly, the problem here isn't that you're being too much of a newbie, but that you're trying to solve the problem in the same abstract way an expert would, and just don't know the details yet. This is completely doable; you just have to be explicit about mapping the functionality, rather than just doing it implicitly. Something like this:

def getQuakeData():
    filename = input("Please enter the quake file: ")
    readfile = open(filename, "r")
    readlines = readfile.readlines()
    Types = [line.split(",") for line in readlines]
    xs = [Type[1] for Type in Types]
    ys = [Type[2] for Type in Types]
    for x, y in zip(xs, ys):
        print(x,y)

getQuakeData()

Or, a better way to write that might be:

def getQuakeData():
    filename = input("Please enter the quake file: ")
    # Use with to make sure the file gets closed
    with open(filename, "r") as readfile:
        # no need for readlines; the file is already an iterable of lines
        # also, using generator expressions means no extra copies
        types = (line.split(",") for line in readfile)
        # iterate tuples, instead of two separate iterables, so no need for zip
        xys = ((type[1], type[2]) for type in types)
        for x, y in xys:
            print(x,y)

getQuakeData()

Finally, you may want to take a look at NumPy and Pandas, libraries which do give you a way to implicitly map functionality over a whole array or frame of data almost the same way you were trying to.

Ivette answered 5/5, 2015 at 0:35 Comment(0)
N
2

The problem is that readlines is a list of strings, each of which is a line of filename. Perhaps you meant:

for line in readlines:
    Type = line.split(",")
    x = Type[1]
    y = Type[2]
    print(x,y)
Narda answered 5/5, 2015 at 0:34 Comment(0)
Y
0

what i did was a quick fix by converting readlines to string but i do not recommencement it but it works and i dont know if there are limitations or not

def getQuakeData():
    filename = input("Please enter the quake file: ")
    readfile = open(filename, "r")
    readlines = str(readfile.readlines())

    Type = readlines.split(",")
    x = Type[1]
    y = Type[2]
    for points in Type:
        print(x,y)
getQuakeData()
Yellowthroat answered 4/6, 2020 at 8:51 Comment(0)
T
0

If you got here because you got this (or similar) error: AttributeError: 'list' object has no attribute ..., then that means you tried to call a method that is not defined on a list object.1 A very common reason to get this error is that you're inadvertently working on a list object which doesn't define a method you are trying to call on it. Make sure to check for types beforehand.

Some common examples (numpy arrays with non-specified dtype, output of an API call, (unexpected) list of Python objects etc.):

# arr is an array of Python lists without a specific numeric dtype
arr = np.array([[1,2,3], [4,5]], dtype=object)
arr[0].mean()                                    # AttributeError


# j is a list of dicts, so cannot call a dict method
j = [{'key1': 'val1', 'key2': 'val2'}]
j.get('key1')                                    # AttributeError

In many cases, you can simply printing the data type, e.g. print(type(my_data)) would reveal unexpected input type. Moreover, perhaps use a try-except block to capture the unexpected data type.


With that being said, for OP's actual problem, the data seems to be a csv file, so either using the standard csv module or pandas seem are much cleaner options.

import csv
with open(filename, 'r') as file:
    for line in csv.reader(file):
        x, y = line[1], line[2]
        print(x, y)

even seeing as the first line seems to the header of the file, we can even use csv.DictReader:

with open(filename, 'r') as file:
    for line in csv.DictReader(file):
        x, y = line['latitude'], line['longitude']
        print(x, y)

Using pandas, it's a single function call.

# pip install pandas
import pandas as pd
df = pd.read_csv(filename)

1 Not counting dunder methods, Python lists define append, clear, copy, count, extend, index, insert, pop, remove, reverse and sort methods (which you can verify using dir([])); split is not among them.

Trichomonad answered 7/3 at 0:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.