Loading [MathJax]/jax/output/CommonHTML/config.js
社区首页 >问答首页 >总结过去一个月Reddit帖子的脚本

总结过去一个月Reddit帖子的脚本
EN

Code Review用户
提问于 2017-07-20 17:40:43
回答 1查看 219关注 0票数 4

这个脚本是用来做我在subreddit上运行的一个月事件中繁琐的工作。它搜索自上次发布以来与事件相关的所有帖子,并创建下个月的大部分帖子。

我最喜欢的是组织层面的批评。我的功能杂乱无章,很难跟踪我有什么,所以我想建议一个更好的做法。

在问题领域,Piece这个名字并不像看上去那么模糊。当然,如果你知道这一点,但仍然认为这是一个可怕的名字,我欢迎你的想法。

代码语言:javascript
代码运行次数:0
复制
import configparser
import datetime
import logging
import re

import pickle
from typing import Optional

import praw
import praw.models

DELIMITER = '---'  # type: str
REDDIT = None
JAM_MAINTAINER = 'G01denW01f11'


def init_reddit(config_pathname: str) -> praw.Reddit:
    """Create global Reddit object from config file"""
    config = configparser.ConfigParser()
    config.read(config_pathname)
    return praw.Reddit(client_id=config['RedditParams']['client_id'],
                       client_secret=config['RedditParams']['client_secret'],
                       user_agent=config['RedditParams']['user_agent'])


def get_reddit() -> praw.Reddit:
    """Get the global Reddit object. Create it if it hasn't been created"""
    global REDDIT
    if not REDDIT:
        REDDIT = init_reddit('config.ini')
    return REDDIT


class Piece(object):
    """A piece to be listed in the piano jam"""

    def __init__(self, composer: str = None, title: str = None, video_url: str = None, score_url: str = None,
                 category: str = None):
        self.composer = composer  # type: str
        self.title = title  # type: str
        self.video_url = video_url  # type: str
        self.score_url = score_url  # type: str
        self.category = category  # type: str

    def __eq__(self, other: 'Piece') -> bool:
        return self.composer == other.composer and self.title == other.title

    def __ne__(self, other: 'Piece') -> bool:
        return not self == other

    def __str__(self) -> str:
        return '{}: [{}]({}) | [Sheet Music]({})'.format(self.composer, self.title, self.video_url.replace(')', '\)'),
                                                         self.score_url.replace(')', '\)'))


class Submission(object):
    """A submission to the month's Jam"""

    def __init__(self, username: str = None, url: str = None, title: str = None, piece: Piece = None):
        self.username = username  # type: str
        self.url = url  # type: str
        self.title = title  # type: str
        self.piece = piece  # type: Piece

    def __eq__(self, other: 'Submission') -> bool:
        return self.username == other.username and self.piece == other.piece

    def __ne__(self, other: 'Submission') -> bool:
        return not self == other

    def __str__(self) -> str:
        return '{}\'s {} by [/u/{}]({})'.format(self.piece.composer, self.piece.title, self.username, self.url)

    def set_piece(self, pieces: [Piece]) -> None:
        """
        From a list of valid pieces, set the one that matches
        :param pieces: A list of pieces to choose from
        """
        self.piece = find_piece_matching_title(pieces, self.title)
        if not self.piece:
            logging.warning('Could not find piece for {} | {}'.format(self.title, self.url))


def find_piece_matching_title(pieces: [Piece], title: str) -> Optional[Piece]:
    """
    Use a simple heuristic to tell which piece a submission is from the title
    :param pieces: Pieces to choose from
    :param title: Submission title
    :return: Appropriate piece, if any
    """
    for piece in pieces:
        if biggest_word_in_line(piece.title).lower() in title.lower():
            return piece
    return None


def format_title(section_title: str) -> str:
    """
    Apply proper formatting to the title of a section
    :param section_title: The title of a section to be formatted
    :return: Formatted title
    """
    return '**{}**'.format(section_title)


class Jam(object):
    """A Piano Jam posting"""

    CATEGORIES = ['Jazz', 'Classical', 'Ragtime', 'Video Game / Anime / Film']  # type: [str]

    def __init__(self, outline_pathname: str = 'jam_outline.txt'):
        """
        Create a Piano Jam instance from a given outline file
        :param outline_pathname: pathname to file with default jam contents
        """
        self.filename = ''  # type: str
        self.submissions = []  # type: [Submission]
        self.pieces = []  # type: [Piece]
        with open(outline_pathname, 'r') as f:
            self.text = f.read()

    def __str__(self):
        submissions_str = ''
        for submission in self.submissions:
            submissions_str += str(submission) + '\n\n'
        pieces_str = ''
        for piece in self.pieces:
            pieces_str += str(piece) + '\n\n'
        return self.text.format(submissions_str, pieces_str)

    def add_submission(self, submission: Submission):
        """
        Add a submission to the Jam. Multiple submissions do not get added
        :param submission: Submission to the Piano Jam
        :return: None
        """
        for prior_submission in self.submissions:
            if submission.username == prior_submission.username and submission.piece == submission.piece:
                if submission.url != prior_submission.url:
                    logging.warning('User {0} attempted to submit a piece multiple times'.format(submission.username))
                return
        self.submissions.append(submission)

    def add_piece(self, piece: Piece):
        if piece not in self.pieces:
            self.pieces.append(piece)

    def save(self, filename: str='') -> None:
        if filename:
            self.filename = filename
        if not self.filename:
            raise ValueError('No filename to save to!')
        with open(self.filename, 'wb') as f:
            pickle.dump(self, f)

    @classmethod
    def load(cls, filename: str) -> 'Jam':
        with open(filename, 'rb') as f:
            jam = pickle.load(f)  # type: Jam
        if type(jam) != Jam:
            raise TypeError('Tried to load a Jam. Got {}'.format(type(jam)))
        assert jam.filename == filename
        return jam


def parse_piece(piece_text: str) -> Piece:
    """
    Construct a Piece from its string representation.
    Expected format: Composer: [Title](url) | [Sheet Music](sheetUrl)
    :param piece_text: Line from Piano Jam specifying a Piece to learn
    """
    piece = Piece()
    piece.composer = piece_text[:piece_text.index(':')]
    piece.title = re.findall(re.compile('\[(.*?)\]'), piece_text)[0]  # type: str
    urls = re.findall(re.compile('\((.*?)\)'), piece_text)
    piece.video_url = urls[0]  # type: str
    piece.score_url = urls[1]  # type: str
    return piece


def parse_pieces(section_text: str) -> [Piece]:
    """Parse all the pieces in a given section"""
    pieces = section_text.split('\n')[1:]  # First line is the category; discard
    return (parse_piece(piece_text) for piece_text in pieces if piece_text.strip() != '')


def get_pieces_from_jam(jam_text: str) -> [Piece]:
    """
    Parse all the pieces from a Jam, given the contents of a post
    :param jam_text: The contents of a Piano Jam posting
    :return: List of pieces to be used for the Jam
    """
    sections = jam_text.split(DELIMITER)
    sections = (section.strip() for section in sections)
    filtered_sections = []
    for section in sections:
        section = section.strip()
        for category in Jam.CATEGORIES:
            category = format_title(category)
            if section.startswith(category):
                filtered_sections.append(section)
                break
    pieces = []
    for section in filtered_sections:
        pieces.extend(parse_pieces(section))
    return pieces


def get_selections_from_url(url: str) -> [Piece]:
    """
    Parse all the pieces from a jam, given its url
    :param url: URL to a Piano Jam post
    :return: List of pieces to be used for the Jam
    """
    try:
        post = praw.models.Submission(get_reddit(), url=url)
    except KeyError:
        raise KeyError('Could not recognize url {0}'.format(url))
    return get_pieces_from_jam(post.selftext)


def search_for_submissions():
    """
    Search Reddit for posts with [Piano Jam] in title within past month
    :return: List of urls to posts
    """
    subreddit = get_reddit().subreddit('piano')
    results = subreddit.search('[Piano Jam]', sort='new', time_filter='month')
    return (result for result in results)


def filter_submissions(submissions: [praw.models.Submission], jam: praw.models.Submission):
    return [submission for submission in submissions
            if '[piano jam]' in submission.title.lower() and
            datetime.datetime.fromtimestamp(submission.created) >
            datetime.datetime.fromtimestamp(jam.created)]


def find_last_jam() -> praw.models.Submission:
    candidates = search_for_submissions()
    for candidate in candidates:
        if candidate.author == JAM_MAINTAINER and '[' not in candidate.title:
            return candidate
    raise ValueError('Could not find last Piano Jam')


def biggest_word_in_line(line: str) -> str:
    words = line.split()
    length = 0
    biggest_word = None
    for word in words:
        if len(word) > length:
            length = len(word)
            biggest_word = word
    assert biggest_word
    return biggest_word


def create_jam() -> [Submission]:
    """
    Find all Piano Jam submissions since the last posting
    Log a warning if there are submissions not in the previous Jam.
    Create Jam from submissions and pickle it for later use.
    """
    previous_jam = find_last_jam()
    entries = filter_submissions(search_for_submissions(), previous_jam)
    submissions = [Submission(entry.author, entry.shortlink, entry.title) for entry in entries]
    pieces = get_pieces_from_jam(previous_jam.selftext)
    new_jam = Jam()
    for submission in submissions:
        submission.set_piece(pieces)
        if submission.piece:
            new_jam.add_submission(submission)
    new_jam.save('current_jam.txt')
EN

回答 1

Code Review用户

回答已采纳

发布于 2017-07-21 10:28:46

  1. 没有修改全局对象的参数的函数是没有意义的。正因为如此,您的init_reddit函数比get_reddit函数更好。
  2. IMHO您应该重新考虑为什么您的函数中有更多的注释而不是代码。也许有一种更地道的方式来表达这一点。(见find_piece_matching_titleformat_title)
  3. 类很好;请考虑创建一个Reddit类,该类要么继承自praw.Reddit,要么将您的reddit实例作为成员变量。你可以把search_for_submissionsfilter_submissions放进去。
  4. 您的parse_pieceparse_piecesget_pieces_from_jam等函数应该是块或Jam对象的一部分。如果您使用对象来包含您的数据,那么让函数作为方法操作该数据是有意义的。

总的来说,我在您的代码中看到了大量顶级函数和对象,而没有清楚地说明它们应该如何协同工作。编写代码的困难部分不一定是编写单个片段,而是找出最简单(最不复杂)的交互方式。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/169811

复制
相关文章
CoffeeScript 简介
摘要总结:本文介绍了CoffeeScript这门编程语言,包括它的历史、特性、安装、概览以及进一步学习的资源。
乐百川
2018/01/09
9210
【前端】CoffeeScript
zhaokang555
2023/10/17
1310
【前端】CoffeeScript
CoffeeScript学习笔记
CoffeeScript编程语言构建于Javascript之上,它可编译成高效JavaScript。可以在Web浏览器上,或者结合Node.js一类的技术构建服务端应用程序。
大江小浪
2018/07/25
4050
CoffeeScript学习笔记
私有PaaS在乐视的实践
PaaS在云平台中的作用 * 打通接入层、应用层、服务层 * 承载了云平台95%以上的业务
字母哥博客
2020/09/23
5190
私有PaaS在乐视的实践
在 SwiftUI 视图中打开 URL 的若干方法
本文将介绍在 SwiftUI 视图中打开 URL 的若干种方式,其他的内容还包括如何自动识别文本中的内容并为其转换为可点击链接,以及如何自定义打开 URL 前后的行为等。
东坡肘子
2022/07/28
7.8K1
在 SwiftUI 视图中打开 URL 的若干方法
在图中添加多边形
在matplotlib中有一个子模块patches, 提供了绘制各种多边形的功能,常用的多边形及其画法如下
生信修炼手册
2020/09/23
6220
在图中添加多边形
Win10: 在截图中添加红框
文章背景: 在工作中,很多时候需要用到Win10原生的截图工具,然后在截图中添加红框进行强调。对于Win10系统,可以通过按Windows 徽标键‌+ Shift+ S,快速调出截图工具,但无法在截图中添加红框,需要借助画图工具进行实现。
Exploring
2023/08/17
13.3K0
Win10: 在截图中添加红框
【译】在列表视图中处理空值
本篇文章主要针对两类开发者。第一个是曾遇到过IllegalArgumentException: Path must not be empty问题的开发者。第二个则是当ListView使用了未被完整加载的图像,应用程序仍能正确运转的开发者们。
小鄧子
2018/08/20
1.2K0
面经 | 嵌入式软件开发(海康威视)
a. 嵌入式软件开发的笔试题中,c/c++、数据结构、操作系统、计算机网络等都会涉及到,对于操作系统方面的考察相较于其他岗位会更多一些。在程序题中,除了一些算法题,还会考察某个现有函数的实现,例如:memcpy。
用户3946442
2022/04/11
1.2K0
面经 | 嵌入式软件开发(海康威视)
在EasyUI的DataGrid中嵌入Combobox
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/details/46687767
DannyHoo
2018/09/13
3.8K0
在EasyUI的DataGrid中嵌入Combobox
C++在视图中显示缩略图
将任意形式文件已缩略图形式显示在视图中 //pWnd为当前客户区视图 CWnd* pWnd; pWnd=this; CDC* pDC=pWnd->GetDC(); HDC hDC = pDC->m_hDC; HWND hwnd=pWnd->GetSafeHwnd(); CImage image; //m_ViewRect 为当前客户区 CRect m_ViewRect; GetClientRect(&m_ViewRect); //strFilePath为影像绝度路径,包含文件名 image.Load(strFilePath);
用户7886150
2021/02/13
6790
在应用中嵌入Tomcat
很多 Java web 应用和服务,包括开源的和商业化的(比如 Alfresco, iRise, Confluence等),都倾向于将 Apache Tomcat Servlet 引擎整个嵌入到他们的分发包中。Atlatisan公司甚至只支持他们自己提供的嵌入式Tomcat 包,不再提供 WAR/EAR 形式的分发包。这些安装包包含了整个 Tomcat 引擎和配置文件,看起来确实有点大材小用。在大多数配置中,默认的配置文件甚至从来不会变动。真的有办法可以在代码中启动 Tomcat 并且只需要 tomcat 的 jar 文件作为依赖么?在下面的教程中,我们将会对 Jetty (Jetty 是一个为此目的而设计的一种嵌入式 servlet 引擎)进行测试,同时还会展示如何将 Jetty 迁移到 Tomcat 。
哲洛不闹
2018/09/18
2.3K0
在应用中嵌入Tomcat
类图中的关系
关联(Association)关系是类与类之间最常用的一种关系,它是一种结构化关系,用于表示一类对象与另一类对象之间有联系,如汽车和轮胎、师傅和徒弟、班级和学生等等。在UML类图中,用实线连接有关联关系的对象所对应的类,在使用Java、C#和C++等编程语言实现关联关系时,通常将一个类的对象作为另一个类的成员变量。在使用类图表示关联关系时可以在关联线上标注角色名,一般使用一个表示两者之间关系的动词或者名词表示角色名(有时该名词为实例对象名),关系的两端代表两种不同的角色,因此在一个关联关系中可以包含两个角色名,角色名不是必须的,可以根据需要增加,其目的是使类之间的关系更加明确。
后端码匠
2022/03/28
7280
类图中的关系
ICRA 2020 | 通过共享2D-3D嵌入空间在激光雷达地图中进行全局视觉定位
标题:Global visual localization in LiDAR-maps through shared 2D-3D embedding space
好好学SLAM
2021/05/28
8260
咖啡销售2.0
咖啡是美国乃至全世界消费最广泛的饮料之一。美国人每天消费4亿杯咖啡,使美国成为世界上最主要的咖啡消费国。
用户8128510
2021/01/28
7870
拼图中的数据科学
拼图筛选流程: 抓出一把拼图 注:一把的数量允许动态得调整 铺展在桌面上 并行对非字母信息筛选并处理 优质连块拼图 取出 形状是边界拼图 取出 字母向下 翻面 并行对字母信息筛选并处理 相似字母XY 收集 相似字母不再出现 取出 注:随机查找n次无结果 边界拼图 取出 已出现过的字母 取出 最后一组字母 相似字母X 收集X 相似字母不再出现 取出X 直接收集Y 取出Y 注:随机查找n次无结果 注释:仅支持两只手,左手字母靠前,右手字母靠后 注释:XY集合的选择靠特征,可选的组合有
杨丝儿
2022/03/01
4880
CoffeeScript和Sass提高Web开发效率
如果您是一位每天都要编写JavaScript和Css的Web前端开发人员,可能您已经开始感觉到JavaScript的关键字 var, function, {} 要被您每天敲击若干遍。是否可以省掉这些重
葡萄城控件
2018/01/10
8040
CoffeeScript和Sass提高Web开发效率
在 HTML 中嵌入 PHP 代码
PHP 天生对 Web 和 HTML 友好,在 PHP 诞生之初,主要用于在 Web 1.0 中构建个人主页,那个时候,PHP 代表的是 Personal Home Page,随着 Web 互联网的发展,在 Web 2.0 时代,PHP 进一步进化为 PHP:Hypertext Preprocessor,即超文本处理器,而 HTML 则是 HyperText Markup Language 的缩写,也就是超文本标记语言。
学院君
2020/05/28
6.3K0
10分钟带你读完《在星巴克要买大杯咖啡》
这是一本很有趣的关于生活中的经济学的小册子,日本人吉本佳生用一个个小故事为我们讲述了那些生活中隐藏的经济学知识。
100000798482
2018/08/20
1.5K0
10分钟带你读完《在星巴克要买大杯咖啡》
点击加载更多

相似问题

Node + Coffeescript + Zappa

10

无法安装Zappa的咖啡(MacOSX10.9)

13

zappa js @include coffeescript方法不工作

311

Coffeescript编译变体(coffeescript.org与咖啡-rails)

12

使用coffeescript (zappa)在nodejs / commonjs中重新导出模块(mongoose)

24
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档