csv中的Python方法 [英] Python methods from csv

查看:76
本文介绍了csv中的Python方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个分配,在其中我使用.csv中的行创建城市的实例",然后在方法中使用这些实例来计算距离和人口变化.创建实例工作正常(使用下面的步骤1-4),直到我尝试调用printDistance:

I am working on an assignment where I create "instances" of cities using rows in a .csv, then use these instances in methods to calculate distance and population change. Creating the instances works fine (using steps 1-4 below), until I try to call printDistance:

##Step 1. Open and read CityPop.csv
with open('CityPop.csv', 'r', newline='') as f:
try:
    reader = csv.DictReader(f)
    ##Step 2. Create "City" class
    class City:
        ##Step 3. Use _init method to assign attribute values
        def __init__(self, row, header):
            self.__dict__ = dict(zip(header, row))

            ##Step 4. Create "Cities" list
            data = list(csv.reader(open('CityPop.csv')))
            instances = [City(i, data[0]) for i in data[1:]]

            ##Step 5. Create printDistance method within "Cities" class  
            def printDistance(self, othercity, instances):
                dist=math.acos((math.sin(math.radians(self.lat)))*(math.sin(math.radians(othercity.lat)))+(math.cos(math.radians(self.lat)))*(math.cos(math.radians(othercity.lat)))*(math.cos(math.radians(self.lon-othercity.lon)))) * 6300 (self.lat, self.lon, othercity.lat, othercity.lon)

当我在其中输入instances [0] .printDistance(instances 1 )时,外壳,出现错误:

When I enter instances[0].printDistance(instances1) in the shell, I get the error:

 `NameError: name 'instances' is not defined`

这是缩进问题吗?我应该从代码内部而不是外壳内部调用函数吗?

Is this an indentation problem? Should I be calling the function from within the code, not the shell?

推荐答案

这并不是缩进问题,而是更多的通用代码结构问题.您要嵌套很多:

This is not so much an indentation problem, but more of a general code structure problem. You're nesting a lot:

  • 所有实际工作都在很长的线上(有错误)
  • 在功能内(正确)printDistance
  • 在构造函数内__init__
  • 在类定义内(正确)City
  • try块内
  • with块内
  • All the actual work on an incredibly long line (with errors)
  • Inside of function (correctly) printDistance
  • Inside of a constructor __init__
  • Inside of a class definition (correctly) City
  • Inside of a try block
  • Inside of a with block

我认为这是您要尝试做的事情:

I think this is what you are trying to do:

  • 创建一个城市类别,该城市可以打印自身与其他城市的距离
  • 从.csv中生成以某种方式同时具有距离和人口的这些City对象的列表(您可能应该提供数据示例)
  • 以容错和干净的方式执行此操作(因此trywith)
  • create a class City, which can print the distance of itself to other cities
  • generate a list of these City objects from a .csv that somehow has both distances and population (you should probably provide an example of data)
  • do so in a fault-tolerant and clean way (hence the try and the with)

instances无法正常工作的原因是,与您想像的不同,它可能没有正确创建,或者至少没有在正确的上下文中创建.而且由于所有嵌套,它肯定不会在CLI上提供给您.

The reason your instances isn't working is because, unlike you think, it's probably not being created correctly, or at least not in the correct context. And it certainly won't be available to you on the CLI due to all of the nesting.

您的代码中有许多明显的错误:

There's a number of blatant bugs in your code:

  • 最后一行末尾的(self.lat, self.lon, othercity.lat, othercity.lon)是什么?
  • 为什么要打开文件以读取两次?您甚至都没有使用第一个reader
  • 您直接将.csv中的列标题分配为对象属性,但拼写错误了它们的用法(lat代替latitudelon代替longitude)
  • What's the (self.lat, self.lon, othercity.lat, othercity.lon) at the end of the last line?
  • Why are you opening the file for reading twice? You're not even using the first reader
  • You are bluntly assigning column headers from a .csv as object attributes, but are misspelling their use (lat instead of latitude and lon instead of longitude)

它看起来有点像是在不同地方找到的许多代码,它们被粘贴到一个块中-这是清理后的样子:

It looks a bit like a lot of code found in various places got pasted together into one clump - this is what it looks like when cleaned up:

import csv
import math


class City:
    def print_distance(self, other_city):
        print(f'{self.city} to {other_city.city}')
        # what a mess...
        print(math.acos(
            (math.sin(math.radians(float(self.latitude)))) * (math.sin(math.radians(float(other_city.latitude)))) + (
                math.cos(math.radians(float(self.latitude)))) * (math.cos(math.radians(float(other_city.latitude)))) * (
                math.cos(math.radians(float(self.longitude) - float(other_city.longitude))))) * 6300)

    def __init__(self, values, attribute_names):
        # this is *nasty* - much better to add the attributes explicitly, but left as original
        # also, note that you're reading strings and floats here, but they are all stored as str
        self.__dict__ = dict(zip(attribute_names, values))


with open('CityPop.csv', 'r', newline='') as f:
    try:
        reader = csv.reader(f)
        header = next(reader)
        cities = [City(row, header) for row in reader]

        for city_1 in cities:
            for city_2 in cities:
                city_1.print_distance(city_2)
    except Exception as e:
        print(f'Apparently were doing something with this error: {e}')

请注意,print_distance现在如何成为City的方法,该方法在cities中的每个City实例上被调用(这是我将instances重命名为)的方法.

Note how print_distance is now a method of City, which is called on each instance of City in cities (which is what I renamed instances to).

现在,如果您真的在尝试,这更有意义:

Now, if you are really trying, this makes more sense:

import csv
import math


class City:
    def print_distance(self, other_city):
        print(f'{self.name} to {other_city.name}')
        # not a lot better, but some at least
        print(
            math.acos(
                math.sin(math.radians(self.lat)) *
                math.sin(math.radians(other_city.lat))
                +
                math.cos(math.radians(self.lat)) *
                math.cos(math.radians(other_city.lat)) *
                math.cos(math.radians(self.lon - other_city.lon))
            ) * 6300
        )

    def __init__(self, lat, lon, name):
        self.lat = float(lat)
        self.lon = float(lon)
        self.name = str(name)


try:
    with open('CityPop.csv', 'r', newline='') as f:
        reader = csv.reader(f)
        header = next(reader)
        cities = [City(lat=row[1], lon=row[2], name=row[4]) for row in reader]

        for city_1 in cities:
            for city_2 in cities:
                city_1.print_distance(city_2)
except FileNotFoundError:
    print(f'Could not find the input file.')

请注意清理计算,捕捉可能发生的错误(try块中包含with)和适当的构造函数,以正确的类型分配所需的内容,而阅读器决定哪些字段去哪里.

Note the cleaned up computation, the catching of an error that could be expected to occur (with the with insides the try block) and a proper constructor that assigns what it needs with the correct type, while the reader decides which fields go where.

最后,作为奖励:没有人应该这样写距离计算.存在大量的库,例如GeoPy,它们在此方面做得更好.您需要做的就是pip install geopy来获取它,然后您可以使用它:

Finally, as a bonus: nobody should be writing distance calculations like this. Plenty libraries exist that do a much better job of this, like GeoPy. All you need to do is pip install geopy to get it and then you can use this:

import csv
import geopy.distance


class City:
    def calc_distance(self, other_city):
        return geopy.distance.geodesic(
            (self.lat, self.lon), 
            (other_city.lat, other_city.lon)
        ).km

    def __init__(self, lat, lon, name):
        self.lat = float(lat)
        self.lon = float(lon)
        self.name = str(name)


try:
    with open('CityPop.csv', 'r', newline='') as f:
        reader = csv.reader(f)
        header = next(reader)
        cities = [City(lat=row[1], lon=row[2], name=row[4]) for row in reader]

        for city_1 in cities:
            for city_2 in cities:
                print(city_1.calc_distance(city_2))
except FileNotFoundError:
    print(f'Could not find the input file.')

请注意,我也将print移出了该方法,因为在对象中进行计算并在其外部进行打印更有意义.所有这一切的好处是,现在计算使用了适当的测地线(WGS-84)进行了计算,并且大大降低了数学错误的几率.如果必须使用简单的球体,则该库也具有相应的功能.

Note that I moved the print out of the method as well, since it makes more sense to calculate in the object and print outside it. The nice thing about all this is that the calculation now uses a proper geodesic (WGS-84) to do the calculation and the odds of math errors are drastically reduced. If you must use a simple sphere, the library has functions for that as well.

这篇关于csv中的Python方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆