《Python编程从入门到实践》第17章练习答案(含2020版17-3)

练习17-1:其他语言

见17-3的被测试程序java_repos.py

练习17-2:最活跃的讨论

本题需要注意ID:26735905没有评论数,需要跳过

from operator import itemgetter
# 函数itemgetter用于根据‘conmments’对字典列表submission_dicts排序
from plotly.graph_objs import Bar
from plotly import offline

import requests
import json

# 执行API调用并存储响应
url_s = 'https://hacker-news.firebaseio.com/v0/topstories.json'
r_s = requests.get(url_s)   # r_s是一个ID按阅读量排位的列表,后文r是具体某个ID文章的信息
print(f"Status code: {r_s.status_code}")

# 处理每篇文章的信息
submission_ids = r_s.json()

submission_dicts = []
for submission_id in submission_ids[:30]:
    # 对于每篇文章,都执行一个API调用
    url = f"https://hacker-news.firebaseio.com/v0/item/{submission_id}.json"
    r = requests.get(url)
    print(f"id: {submission_id}\tstatus: {r.status_code}")
    response_dict = r.json()

    # 对于每篇文章,都创建一个字典
    try:  # 在try代码块中尝试执行可能出错的代码
        subsmission_dict = {
            'title': response_dict['title'],
            'hn_link': f'https://news.ycombinator.com/item?id={submission_id}',
            'comments': response_dict['descendants'],
            'owner': response_dict['by'],
            'type': response_dict['type']
        }  
    except KeyError:  # 26735905没有评论数,需要这样跳过
        print(f"{submission_id} cannot find request word!")
        continue    
    submission_dicts.append(subsmission_dict)

submission_dicts = sorted(submission_dicts, key=itemgetter('comments'), reverse=True)
""" 
函数itemgetter()用于根据‘conmments’对字典列表submission_dicts排序
我们向itemgetter()函数传递了键‘comments’,因此它从每个字典中提取与键‘comments’关联的值。
而后函数sorted()将根据这个值对列表进行排序,reverse=True为降序排列,评论数多的在前面
"""

# 为画图进行信息的预处理
repo_links, stars, labels = [], [], []
for subsmission_dict in submission_dicts:
    repo_name = subsmission_dict['title']
    repo_url = subsmission_dict['hn_link']
    repo_link = f"<a href='{repo_url}'>{repo_name}</a>"
    # 创建一个指向项目的链接,为此使用了HTML标记<a>,其格式为<a href='URL'>link_text</a>>
    print(repo_url)
    repo_links.append(repo_link)
    stars.append(subsmission_dict['comments'])
    owner = subsmission_dict['owner']
    description = subsmission_dict['type']
    label = f"By: {owner}<br />Type: {description}"  # <br />为换行符
    labels.append(label)

# 可视化
data = [{
    'type': 'bar',
    'x': repo_links,
    'y': stars,
    'hovertext': labels,  # 工具提示
    'marker': {  # 条形设计
        'color': 'rgb(60,100,150)',  # 条形指定为蓝色
        'line': {'width': 1.5, 'color': 'rgb(25,25,25)'}   # 1.5像素宽的深灰色轮廓
    },
    'opacity': 0.6  # 不透明度
}]

my_layout = {
    'title': 'GitHub最受欢迎的Python项目',
    'xaxis': {
        'title': 'Repository',
        'titlefont': {'size': 20},  # 轴标题字号
        'tickfont': {'size': 10}  # 刻度标签字号
    },
    'yaxis': {
        'title': 'Stars',
        'titlefont': {'size': 24},  # 标签字号
        'tickfont': {'size': 14}  # 刻度标签字号
    }
}
fig = {'data': data, 'layout': my_layout}
offline.plot(fig, filename='17-2.html')

在这里插入图片描述

练习17-3 测试 python_repos.py

这里不小心用了17-1的程序,把这题从python做成了java,不过不打紧,基本就这个词不同

注意事项:

  1. 必须将程序进行重构才能进行测试
  2. 主函数放在if中,这样直接运行时一切正常,而在测试程序中导入时不会直接运行

修改后的被测试程序java_repos.py如下:

import requests
from plotly.graph_objs import Bar
from plotly import offline


def get_response(web):
    """存储一个问题, 并为存储答案建立列表"""
    url = web  # 这个有点多余,改def时懒得调整
    headers = {'Accept': 'application/vnd.github.v4+json'}
    # 通过指定headers显式地要求使用第4版本的GitHub API, 返回json格式信息
    r = requests.get(url, headers=headers)
    return r


def get_repo_dicts(r):
    # 使用requests调用API;调用get()并将URL传递给它,再将响应对象赋给变量r
    print(f"Status code: {r.status_code}")
    # 响应对象包含一个名为status_code的属性, 指出请求是否成功(状态码200表示请求成功)

    # 将api响应赋给一个变量
    response_dict = r.json()
    # 使用json()方法将这些信息转换为Python字典,并将结果存储在response_dict中
    print(f"Total repositories: {response_dict['total_count']}")

    # 探索有关仓库的信息
    repo_dicts = response_dict['items']
    return repo_dicts


def get_names_plot_dicts(repo_dicts):
    repo_links, stars, labels = [], [], []
    for repo_dict in repo_dicts:
        repo_name = repo_dict['name']
        repo_url = repo_dict['html_url']
        repo_link = f"<a href='{repo_url}'>{repo_name}</a>"
        # 创建一个指向项目的链接,为此使用了HTML标记<a>,其格式为<a href='URL'>link_text</a>>
        print(repo_url)
        repo_links.append(repo_link)

        stars.append(repo_dict['stargazers_count'])

        owner = repo_dict['owner']['login']
        description = repo_dict['description']
        label = f"By: {owner}<br />Type: {description}"  # <br />为换行符
        labels.append(label)
    return repo_links, stars, labels


def make_visualization(repo_links, stars, labels):
    # 可视化
    data = [{
        'type': 'bar',
        'x': repo_links,
        'y': stars,
        'hovertext': labels,  # 工具提示
        'marker': {  # 条形设计
            'color': 'rgb(60,100,150)',  # 条形指定为蓝色
            'line': {'width': 1.5, 'color': 'rgb(25,25,25)'}   # 1.5像素宽的深灰色轮廓
        },
        'opacity': 0.6  # 不透明度
    }]

    my_layout = {
        'title': 'GitHub最受欢迎的Python项目',
        'xaxis': {
            'title': 'Repository',
            'titlefont': {'size': 24},  # 轴标题字号
            'tickfont': {'size': 14}  # 刻度标签字号
        },
        'yaxis': {
            'title': 'Stars',
            'titlefont': {'size': 24},  # 标签字号
            'tickfont': {'size': 14}  # 刻度标签字号
        }
    }
    fig = {'data': data, 'layout': my_layout}
    offline.plot(fig, filename='Java_repos.html')


if __name__ == '__main__':  # 主函数放在if中,这样导入时不会直接运行
    web = 'https://api.github.com/search/repositories?q=language:java&sort=stars'
    r = get_response(web)
    repo_dicts = get_repo_dicts(r)
    repo_links, stars, labels = get_names_plot_dicts(repo_dicts)
    make_visualization(repo_links, stars, labels)

测试程序text_java_repos.py如下:

import unittest
import java_repos as jr  # 不小心把这题从python做成了java,不打紧,基本就这个词不同


class TestJavaRepos(unittest.TestCase):
    """测试文件java_repos.py"""

    def setUp(self):
        """
        创建一个调查对象和一组答案, 供使用的测试方法使用
        """
        web = 'https://api.github.com/search/repositories?q=language:java&sort=stars'
        self.r = jr.get_response(web)
        self.response_dict = self.r.json()
        self.repo_dicts = jr.get_repo_dicts(self.r)
        self.repo_dict = self.repo_dicts[0]
        self.repo_links, self.stars, self.labels = \
            jr.get_names_plot_dicts(self.repo_dicts)

    def test_get_status_code(self):
        """测试API响应是否成功"""
        my_status_code = self.r.status_code
        self.assertEqual(str(my_status_code), "200")

    def test_get_repos_number(self):
        """测试仓库总数是否超过500000"""
        my_repos_number = self.response_dict['total_count']
        self.assertLess(500000, my_repos_number)

    def test_get_repos_returned_number(self):
        """测试返回条目数是否为30"""
        self.assertEqual(len(self.repo_dicts), 30)

    def test_repositories_keys(self):
        """测试一个仓库是否包含所需的键"""
        required_keys = ['name', 'owner', 'description',
                         'description', 'stargazers_count', 'html_url']
        for key in required_keys:
            self.assertTrue(key in self.repo_dict.keys())


if __name__ == '__main__':
    unittest.main()

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞翔的大玉米

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值