优达学城python项目P1:搜索和探索近地天体(NEOs)
項目1官方地址:https://github.com/udacity/nd303-c1-advanced-python-techniques-project-starter
1 概述
本項目概言之,實現一個命令行工具來檢查和查詢近地天體的數據集。
完成后,您將能夠檢查數據集中的近地天體的屬性,并使用以下任意組合的過濾器查詢近地天體的數據集:
- 發生在給定的日期。
- 在給定的開始日期或之后發生。
- 在給定的結束日期或之前發生。
- 以至少(或至多)X天文單位的距離接近地球。
- 以至少(或最多)Y千米每秒的相對速度接近地球。
- 直徑至少等于(或至少小于)Z公里。
- 被美國宇航局標記為有潛在危險(或沒有)。
學習目標
通過完成本項目,您將展示以下能力:
- 用Python表示結構化數據。
- 將結構化文件中的數據提取到Python中。
- 根據所需的行為在Python中轉換數據。
- 以結構化的方式將結果保存到文件中。
在此過程中,您必須能夠:
- 編寫Python函數來轉換數據和執行算法。
- 設計Python類來封裝有用的數據類型。
- 為復雜的實現提供接口抽象。
在這個過程中遇到bug是很正常的,所以很有可能,您還將獲得寶貴的調試技能的練習,無論是解釋堆棧跟蹤、跟蹤系統錯誤、處理和拋出適當的錯誤、使用pdb遍歷代碼、使用assert檢查先決條件,還是僅僅使用print顯示內部狀態。
?
具體任務
- 任務0:檢查數據。(數據/ neos.csv和數據/ cad.json)
- 任務1:構建模型來表示數據。(models.py)
- 任務2:將數據提取到自定義數據庫中(Extract.py和database.py)
- 任務3:創建過濾器來查詢數據庫以生成匹配的close - approach對象流,并限制結果大小。(filters.py和database.py)
- 任務4:將數據保存到文件中。(write.py)
?
技能大模塊:
- 單元測試Python3 unittest
- 類的測試
- 文件內容測試
- python版本測試
- 文件存在否測試
- 文件格式測試
- 。。。
- ?
?
?
2 項目結構
.
├── README.md # This file.
├── main.py
├── models.py # Task 1.
├── read.py # Task 2a.
├── database.py # Task 2b and Task 3b.
├── filters.py # Task 3a and Task 3c.
├── write.py # Task 4.
├── helpers.py
├── data├── neos.csv└── cad.json
?
Task 1:設計存儲數據的兩個類
from helpers import cd_to_datetime, datetime_to_strclass NearEarthObject:"""近地天體的基本信息類,處理neos.csv文件"""def __init__(self, **info):"""參數 info: 一個字典.例子:dict_info = {'designation':'編號GT520', 'time':'哈雷彗星', 'diameter':101, 'hazardous':'Y'}neo = NearEarthObject(**dict_info)"""self.designation = (str(info['designation']) if info['designation'] else '')self.name = str(info['name']) if info['name'] else Noneself.diameter = (float(info['diameter']) if info['diameter'] else float('nan'))self.hazardous = True if info['hazardous'] == 'Y' else Falseself.approaches = []#加了@property后,可以用調用屬性的形式來調用方法,后面不需要加()@propertydef fullname(self):return f"{self.designation} ({self.name or 'N/A'})"#print(類的實例名)時,會調用此方法。功能相當于此實例的“自我介紹”。def __str__(self):return (f"""{self.fullname} 是一個直徑為 """f"""{self.diameter:.3f}km 且 """f"""{'具有' if self.hazardous else '不具有'} 危險的近地天體。""")# print(類的實例名)時,當類中沒有__str__方法的時候,會去調用__repr__方法,所以一般類中需要定義repr方法# 也可以直接這樣調用__repr__方法:print(repr(類的實例名))# 如果沒有自定義__repr__方法和__str__方法,print(類的實例名)時輸出默認的__repr__方法:“類名+object at+內存地址”def __repr__(self):return (f"NearEarthObject(designation={self.designation!r}, name={self.name!r}, "f"diameter={self.diameter:.3f}, hazardous={self.hazardous!r})")class CloseApproach:"""臨近地球時的狀態類,處理cad.json文件"""def __init__(self, **info):"""參數 info: 一個字典."""self._designation = (str(info['designation']) if info['designation']else '')self.time = cd_to_datetime(info['time']) if info['time'] else Noneself.distance = float(info['distance']) if info['distance'] else 0.0self.velocity = float(info['velocity']) if info['velocity'] else 0.0# Create an attribute for the referenced NEO, originally None.self.neo = None@propertydef fullname(self):"""Return a representation of the full name of this NEO."""return f"{self._designation} ({self.neo.name or 'N/A'})"@propertydef time_str(self):return datetime_to_str(self.time)def __str__(self):return (f"""在 {self.time_str}時刻, '{self.fullname}' 將接近地球, """f"""最近距離為 {self.distance:.2f} au,速度為 """f"""{self.velocity:.2f} km/s.""")def __repr__(self):return (f"CloseApproach(time={self.time_str!r}, distance={self.distance:.2f}, "f"velocity={self.velocity:.2f}, neo={self.neo!r})")
NearEarthObject類的測試效果如下:
?
Task 2:從文件中提取數據放到Python類對象中
1 CSV和json文件數據提取函數
import csv
import jsonfrom models import NearEarthObject, CloseApproachdef load_neos(neo_csv_path):"""Read near-Earth object information from a CSV file.:param neo_csv_path: A path to a CSV file containing data about near-Earth objects.:return: A collection of `NearEarthObject`s."""# TODO: Load NEO data from the given CSV file.neos = []with open(neo_csv_path, 'r') as infile:reader = csv.DictReader(infile)for row in reader:neo = NearEarthObject(designation=row['pdes'],name=row['name'],diameter=row['diameter'],hazardous=row['pha'],)neos.append(neo)return neosdef load_approaches(cad_json_path):"""Read close approach data from a JSON file.:param neo_csv_path: A path to a JSON file containing data about close approaches.:return: A collection of `CloseApproach`es."""# TODO: Load close approach data from the given JSON file.approaches = []with open(cad_json_path) as infile:content = json.load(infile)data = content['data']fields = {}for key in content['fields']:fields[key] = content['fields'].index(key)for row in data:approach = CloseApproach(designation=row[fields['des']],time=row[fields['cd']],distance=row[fields['dist']],velocity=row[fields['v_rel']],)approaches.append(approach)return approaches
2?
class NEODatabase:"""一個包含near-Earth類及其近地時信息的數據庫.A `NEODatabase` contains a collection of NEOs and a collection of closeapproaches. It additionally maintains a few auxiliary data structures tohelp fetch NEOs by primary designation or by name and to help speed upquerying for close approaches that match criteria."""def __init__(self, neos, approaches):"""Create a new `NEODatabase`.As a precondition, this constructor assumes that the collections of NEOsand close approaches haven't yet been linked - that is, the`.approaches` attribute of each `NearEarthObject` resolves to an emptycollection, and the `.neo` attribute of each `CloseApproach` is None.However, each `CloseApproach` has an attribute (`._designation`) thatmatches the `.designation` attribute of the corresponding NEO. Thisconstructor modifies the supplied NEOs and close approaches to link themtogether - after it's done, the `.approaches` attribute of each NEO hasa collection of that NEO's close approaches, and the `.neo` attribute ofeach close approach references the appropriate NEO.:param neos: A collection of `NearEarthObject`s.:param approaches: A collection of `CloseApproach`es."""self._neos = neosself._approaches = approachesself._data = {}for approach in self._approaches:if approach._designation not in self._data:self._data[approach._designation] = {'approaches': [],'neo': None,}self._data[approach._designation]['approaches'].append(approach)for neo in self._neos:if neo.designation not in self._data:self._data[neo.designation] = {'approaches': [],'neo': None,}self._data[neo.designation]['neo'] = neoif neo.name not in self._data:self._data[neo.name] = neo.designationneo.approaches.extend(self._data[neo.designation]['approaches'])for approach in self._approaches:approach.neo = self._data[approach._designation]['neo']def get_neo_by_designation(self, designation):"""Find and return an NEO by its primary designation.If no match is found, return `None` instead.Each NEO in the data set has a unique primary designation, as a string.The matching is exact - check for spelling and capitalization if nomatch is found.:param designation: The primary designation of the NEO to search for.:return: The `NearEarthObject` with the desired primary designation, or `None`."""if designation in self._data:return self._data[designation]['neo']return Nonedef get_neo_by_name(self, name):"""Find and return an NEO by its name.If no match is found, return `None` instead.Not every NEO in the data set has a name. No NEOs are associated withthe empty string nor with the `None` singleton.The matching is exact - check for spelling and capitalization if nomatch is found.:param name: The name, as a string, of the NEO to search for.:return: The `NearEarthObject` with the desired name, or `None`."""if name in self._data:return self.get_neo_by_designation(self._data[name])return Nonedef query(self, filters=()):"""Query close approaches to generate those that match a collection of filters.This generates a stream of `CloseApproach` objects that match all of theprovided filters.If no arguments are provided, generate all known close approaches.The `CloseApproach` objects are generated in internal order, which isn'tguaranteed to be sorted meaninfully, although is often sorted by time.:param filters: A collection of filters capturing user-specified criteria.:return: A stream of matching `CloseApproach` objects."""if filters:for approach in self._approaches:if all(map(lambda f: f(approach), filters)):yield approachelse:for approach in self._approaches:yield approach
?
Task 3:設計數據庫條件查詢方法
?
?
Task 4:保存查詢結果
?
?
?
重要知識點:
- @property作用:可以用調用屬性的形式來調用方法(函數),后面不需要加()。
-
@classmethod作用:很多博客只是說@calssmethod的作用就是“可以不需要實例化,直接類名.方法名()來調用。這有利于組織代碼,把某些應該屬于某個類的函數給放到那個類里去,同時有利于命名空間的整潔”。很抽象,其實具體作用如下:
@classmethod的作用實際是可以在class內實例化class,一般使用在有工廠模式要求時。作用就是比如輸入的數據需要清洗一遍再實例化,可以把清洗函數定義在class內部并加上@classmethod裝飾器已達到減少代碼的目的。總結起來就是:@class method可以用來為一個類創建一些預處理的實例。https://blog.csdn.net/qq_23981335/article/details/103798741
-
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的优达学城python项目P1:搜索和探索近地天体(NEOs)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: deepsort原理快速弄懂——时效比最
- 下一篇: 原创:田径女运动员进军娱乐圈,吴艳妮录综