Python核心技术与实战
景霄
Facebook资深工程师
立即订阅
13891 人已学习
课程目录
已完结 46 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 从工程的角度深入理解Python
免费
基础篇 (14讲)
01 | 如何逐步突破,成为Python高手?
02 | Jupyter Notebook为什么是现代Python的必学技术?
03 | 列表和元组,到底用哪一个?
04 | 字典、集合,你真的了解吗?
05 | 深入浅出字符串
06 | Python “黑箱”:输入与输出
07 | 修炼基本功:条件与循环
08 | 异常处理:如何提高程序的稳定性?
09 | 不可或缺的自定义函数
10 | 简约不简单的匿名函数
11 | 面向对象(上):从生活中的类比说起
12 | 面向对象(下):如何实现一个搜索引擎?
13 | 搭建积木:Python 模块化
14 | 答疑(一):列表和元组的内部实现是怎样的?
进阶篇 (11讲)
15 | Python对象的比较、拷贝
16 | 值传递,引用传递or其他,Python里参数是如何传递的?
17 | 强大的装饰器
18 | metaclass,是潘多拉魔盒还是阿拉丁神灯?
19 | 深入理解迭代器和生成器
20 | 揭秘 Python 协程
21 | Python并发编程之Futures
22 | 并发编程之Asyncio
23 | 你真的懂Python GIL(全局解释器锁)吗?
24 | 带你解析 Python 垃圾回收机制
25 | 答疑(二):GIL与多线程是什么关系呢?
规范篇 (7讲)
26 | 活都来不及干了,还有空注意代码风格?!
27 | 学会合理分解代码,提高代码可读性
28 | 如何合理利用assert?
29 | 巧用上下文管理器和With语句精简代码
30 | 真的有必要写单元测试吗?
31 | pdb & cProfile:调试和性能分析的法宝
32 | 答疑(三):如何选择合适的异常处理方式?
量化交易实战篇 (8讲)
33 | 带你初探量化世界
免费
34 | RESTful & Socket: 搭建交易执行层核心
35 | RESTful & Socket: 行情数据对接和抓取
36 | Pandas & Numpy: 策略与回测系统
免费
37 | Kafka & ZMQ:自动化交易流水线
38 | MySQL:日志和数据存储系统
39 | Django:搭建监控平台
40 | 总结:Python中的数据结构与算法全景
技术见闻与分享 (4讲)
41 | 硅谷一线互联网公司的工作体验
42 | 细数技术研发的注意事项
加餐 | 带你上手SWIG:一份清晰好用的SWIG编程实践指南
43 | Q&A:聊一聊职业发展和选择
结束语 (1讲)
结束语 | 技术之外的几点成长建议
Python核心技术与实战
登录|注册

12 | 面向对象(下):如何实现一个搜索引擎?

景霄 2019-06-05
你好,我是景霄。这节课,我们来实现一个 Python 的搜索引擎(search engine)。
承接上文,今天这节课的主要目的是,带你模拟敏捷开发过程中的迭代开发流程,巩固面向对象的程序设计思想。
我们将从最简单最直接的搜索做起,一步步优化,这其中,我不会涉及到过多的超纲算法,但不可避免会介绍一些现代搜索引擎中的基础概念,例如语料(corpus)、倒序索引(inverted index)等。
如果你对这方面本身有些了解,自然可以轻松理解;即使你之前完全没接触过搜索引擎,也不用过分担心,我会力求简洁清晰,降低学习难度。同时,我希望你把更多的精力放在面向对象的建模思路上。

“高大上”的搜索引擎

引擎一词尤如其名,听起来非常酷炫。搜索引擎,则是新世纪初期互联网发展最重要的入口之一,依托搜索引擎,中国和美国分别诞生了百度、谷歌等巨型公司。
搜索引擎极大地方便了互联网生活,也成为上网必不可少的刚需工具。依托搜索引擎发展起来的互联网广告,则成了硅谷和中国巨头的核心商业模式;而搜索本身,也在持续进步着, Facebook 和微信也一直有意向在自家社交产品架设搜索平台。
关于搜索引擎的价值我不必多说了,今天我们主要来看一下搜索引擎的核心构成。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Python核心技术与实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(60)

  • Jingxiao 置顶
    思考题答案:
    John Si 的评论说的很对,如果想要强行访问父类的私有类型,做法是 self._ParentClass__var,这是非常不推荐的 hacky method。以下是示范代码:
    class A:
        __a = 1

    class B(A):
        pass

    b = B()
    print(b._A__a)
    2019-06-09
    4
  • 益达
    看不懂不睡觉
    2019-06-05
    3
    36
  • Wing·三金
    思考题:子类继承父类私有变量的方法
    - 通过定义 get/set 函数来间接操作私有变量
    - 通过 实例名._父类名__私有变量名 来直接调用,所以事实上 python 并不直接私有变量

    # 主要知识点

    - 搜索引擎的四个组成部分
    - 迭代开发的流程
    - 类的继承与父类函数的强行调用
    - 词袋模型 + 逆序索引 + 合并有序数组 = 优化检索速度 + 考虑单词顺序与间隔
    - pylru 的基本用法
    - 多重继承的初始化规则

    # 搜索引擎

    - 搜索器:相当于爬虫
    - 索引器:为每个文件/网页建立唯一的索引
    - 检索器:高效地检索并返回匹配的文件/网页
    - 用户接口:输入框和结果返回界面

    # 迭代开发的流程

    - 构建一个通用的基本框架
    - 从最简单的情况考虑起,搭建一个能运行的极简版本
    - 按照实际需要不断对具体的实现过程进行优化:如在本讲的例子中,先考虑了单个搜索词 + 小搜索量的情况,构建了 ver 1;然后考虑了多个搜索词,构建了词袋的 ver 2;再考虑了大搜索量,构建了词袋 + 逆序索引的 ver 3(提了 搜索词排序与间隔 情况下的处理思路);最后考虑了负载与重复性搜索问题,构建了使用 LRU 缓存策略的 ver 4
    - 如果回过头来看最初的框架,还能发现 add_corpus 的方法并不适用于文件较大的情况,结合前面第六讲的内容可以做些改进;以及 main 函数直接用了 for 循环来找所有的文件,实际使用时用的是诸如 os.walk 的方法
    2019-06-05
    29
  • 这篇文章就值回票价了。
    2019-06-07
    18
  • 小侠龙旋风
    和面向对象无关的关键词整理:
    1.一个搜索引擎由搜索器、索引器、检索器和用户接口四个部分组成。
    2.Bag of Words Model,词袋模型。
    3.Inverted Index Model,倒序索引。
    4.语料corpus分词,齐夫定律。
    5.合并 K 个有序数组。
    6.LRU缓存。
    难点消化:4,5,6
    思考题:
    Python并没有真正的私有化支持,但可用下划线得到伪私有:
    (1)_xxx "单下划线 " 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量,需通过类提供的接口进行访问;
    (2)__xxx 类中的私有变量/方法名,只有类对象自己能访问,连子类对象也不能访问到这个数据。
    (3)__xxx__ 魔法函数,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 __init__() 代表类的构造函数。

    作者回复: 👍

    2019-06-08
    1
    11
  • John Si
    关于思考题,子类不能继承父类私有属性,只可透过self._Parent__varname去读取该私有属性的值,或在父类创建方法返回私有属性的值,然后子类调用父类方法去取得该私有属性的值

    class Animal():
        
        def __init__(self, sex, height, weight):
            self.__sex = sex
            self.height = height
            self.weight = weight
            
        def say_hello(self):
            raise 'say hello not implemented'
            
        def get_sex(self):
            print('Achieve sex information for parent method: {}'.format(self.__sex))
            
    class Person(Animal):
        
        def __init__(self,name,age):
            super().__init__('M',172,70)
            self.name = name
            self.age = age
            
        def say_hello(self):
            print('Hello, {}, age: {}, weight:{}'.format(self.name, self.age, self.weight))
            print('Sex: {}'.format(self._Animal__sex))
            

    john = Person('John',35)
    john.say_hello()
    john.get_sex()

    ========================
    Hello, John, age: 35, weight:70
    Sex: M
    Achieve sex information for parent method: M

    2019-06-05
    6
  • 我是传奇
    图不错
    2019-06-05
    5
  • Danpier
    BOWInvertedIndexEngine search函数后半部分少了缩进,第40行开始
    2019-06-05
    1
    5
  • fly
    是search()又被重载了,不是query()
    2019-06-06
    4
  • 闲人
    BOWInvertedIndexEngine类的search函数中:
    query_words_index = list()
    for query_word in query_words:
        query_words_index.append(0)
    这一段没看明白:
    query_words_index是一个全为0的列表?
    有什么作用?
    2019-06-20
    3
    3
  • tux
    运行文中代码,始终在运行状态!

    修改了一处:
    class SearchEngineBase(object):
    ...
        def add_corpus(self, file_path):
            with open('文件的目录' + file_path, 'r') as fin: #修改了此处
                text = fin.read()
                print('text:', text) #能打印出内容


    不修改代码,报FileNotFoundError。去查资料,应该用全路径。 总有个想先看到反馈结果的 强迫症。
    2019-06-05
    3
  • chuan_chen
    感觉这篇好难。。。
    2019-09-04
    2
  • 海生
    可不可以讲解一些开源的框架什么的,python 这边深度学习框架很多。这些框架的代码很优秀,也是语言的核心技术运用最多的地方。
    2019-06-05
    2
  • farFlight
    按照我之前的理解,Python是没有严格的private变量的。子类确实无法直接访问父类"self.__var"变量,但是可以通过"self._Superclass__var"访问。要想比较好地访问或者修改这些变量,可以像JAVA一样写getter和setter吧?
    另外我有两个问题:
    1. 一些手册中说python的多重继承非常混乱不可靠,尤其涉及很多重载的时候,因此需要避免,或者采用composition的方式。实际工程中是否会有这样的考虑呢?
    2. 以搜索引擎为例,如何规划各个类以及函数的功能,是否是 设计模式 方面的知识呢?
    2019-06-05
    2
  • 🇨🇳
    您好,请问继承object和不继承用法区别是什么呢?概念上还是有点模糊
    2019-08-23
    1
  • WANG
    老师,您好,有个疑问,您在讲 BOW Model时,
    class BOWInvertedIndexEngine(SearchEngineBase):
    def __init__(self):
            super(BOWInvertedIndexEngine, self).__init__()
            self.inverted_index = {}


        def search(self, query):
            query_words = list(self.parse_text_to_words(query))
            query_words_index = list()
            for query_word in query_words:
                query_words_index.append(0)


     query_words_index.append(0) 为啥要添加 0, 应该是 query_word 吧?
    2019-06-20
    3
    1
  • 风居住的街
    Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx
    2019-06-17
    1
  • 程序员人生
    今天内容有点多。对于课后留题,在没有写代码测试时候,觉得是不能继承的。
    但是在写了以下代码后,好像私有变量是可以继承的,代码如下,请老师指点
    class A():

        _privateVar = "privateVariable"

        def getPrivateVar(self):
            return self._privateVar

    class B(A):
        def printVar(self):
            print(self._privateVar)
            print(self.getPrivateVar())
            self._privateVar = "modify"
            print(self._privateVar)

    b = B()

    b.printVar()

    运行结果:
    privateVariable
    privateVariable
    modify
    2019-06-05
    1
  • tux
    运行文中代码,始终在运行状态 --> 因为:query = input() 需要输入内容。 这个自己让自己很尴尬呀
    def main(search_engine):
    ...
        while True:
            query = input()
    2019-06-05
    1
  • Paul Shan
    只看懂了面向对象的内容:
    定义好接口,在实践中不断迭代实现以满足现实的功能。接口的稳定性是给调用者以良好界面。实现的不断迭代是为了满足不断变化的需求。这种设计兼顾了稳定和灵活,是非常好的trade off。但在实践中把握接口的粒度近乎艺术,现实中大量代码不是缺乏良好的抽象,就是过度定义了一堆没用的接口,或者兼而有之。
    2019-11-15
收起评论
60
返回
顶部