csv中的Python方法 [英] Python methods from csv
问题描述
我正在做一个分配,在其中我使用.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对象的列表(您可能应该提供数据示例)
- 以容错和干净的方式执行此操作(因此
try
和with
)
- 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 thewith
)
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
代替latitude
,lon
代替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 oflatitude
andlon
instead oflongitude
)
它看起来有点像是在不同地方找到的许多代码,它们被粘贴到一个块中-这是清理后的样子:
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屋!