我正在进行一项任务,我使用.csv中的行创建城市的“实例”,然后在方法中使用这些实例来计算距离和人口变化。创建实例工作正常(使用下面的步骤1-4),直到我尝试调用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)
当我在shell中输入实例[0] .printDistance(instances1)时,我收到错误:
`NameError: name 'instances' is not defined`
这是缩进问题吗?我应该从代码中调用函数,而不是shell吗?
嵌套函数不能包含self作为参数,因为它们不是成员函数。类不能将实例变量传递给它们。你实际上将同一个自我从父函数传递给子函数。
此外,您不能嵌套构造函数,这仅用于启动目的。确实创建一个单独的方法。
并尝试在构造函数中创建实例变量,这就是init for!
self.instances = [self.getInstance(i, data[0]) for i in data[1:]]
还为实例化创建单独的函数
@classmethod
def getInstance(cls,d1,d2):
return cls(d1,d2)
这不是一个缩进问题,而是更多的一般代码结构问题。你筑巢了很多:
printDistance
__init__
里面City
内try
块内with
块内我想这就是你要做的事情:
try
和with
)你的instances
不起作用的原因是因为,与你想象的不同,它可能没有正确创建,或者至少不是在正确的上下文中。由于所有嵌套,它肯定无法在CLI上使用。
您的代码中存在许多明显的错误:
(self.lat, self.lon, othercity.lat, othercity.lon)
?reader
.csv
的列标题指定为对象属性,但是拼错了它们的使用(lat
而不是latitude
和lon
而不是longitude
)它看起来有点像在各个地方找到的很多代码粘贴在一起成为一个丛 - 这就是清理时的样子:
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
的一种方法,它在City
的cities
的每个实例上被调用(这是我改名为instances
)。
现在,如果你真的在尝试,这更有意义:
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.')
注意清理过的计算,捕获可能发生的错误(with
在try
块中)和一个正确的构造函数,用正确的类型分配它需要的东西,同时读者决定哪些字段在哪里。
最后,作为奖励:没有人应该写这样的距离计算。存在大量的库,可以更好地完成这项工作,例如GeoPy。所有你需要做的是pip install geopy
得到它然后你可以使用这个:
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)进行计算,并且数学错误的几率大大降低。如果必须使用简单的球体,那么库也具有相应的功能。