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核心技术与实战
登录|注册

05 | 深入浅出字符串

景霄 2019-05-20
你好,我是景霄。
Python 的程序中充满了字符串(string),在平常阅读代码时也屡见不鲜。字符串同样是 Python 中很常见的一种数据类型,比如日志的打印、程序中函数的注释、数据库的访问、变量的基本操作等等,都用到了字符串。
当然,我相信你本身对字符串已经有所了解。今天这节课,我主要带你回顾一下字符串的常用操作,并对其中的一些小 tricks 详细地加以解释。

字符串基础

什么是字符串呢?字符串是由独立字符组成的一个序列,通常包含在单引号('')双引号("")或者三引号之中(''' '''""" """,两者一样),比如下面几种写法。
name = 'jason'
city = 'beijing'
text = "welcome to jike shijian"
这里定义了 name、city 和 text 三个变量,都是字符串类型。我们知道,Python 中单引号、双引号和三引号的字符串是一模一样的,没有区别,比如下面这个例子中的 s1、s2、s3 完全一样。
s1 = 'hello'
s2 = "hello"
s3 = """hello"""
s1 == s2 == s3
True
Python 同时支持这三种表达方式,很重要的一个原因就是,这样方便你在字符串中,内嵌带引号的字符串。比如:
"I'm a student"
Python 的三引号字符串,则主要应用于多行字符串的情境,比如函数的注释等等。
def calculate_similarity(item1, item2):
"""
Calculate similarity between two items
Args:
item1: 1st item
item2: 2nd item
Returns:
similarity score between item1 and item2
"""
同时,Python 也支持转义字符。所谓的转义字符,就是用反斜杠开头的字符串,来表示一些特定意义的字符。我把常见的的转义字符,总结成了下面这张表格。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Python核心技术与实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(87)

  • Jingxiao 置顶
    关于思考题,如果字符串拼接的次数较少,比如range(100),那么方法一更优,因为时间复杂度精确的来说第一种是O(n),第二种是O(2n),如果拼接的次数较多,比如range(1000000),方法二稍快一些,虽然方法二会遍历两次,但是join的速度其实很快,列表append和join的开销要比字符串+=小一些。
    2019-05-20
    1
    49
  • 不瘦到140不改名
    思考题:个人提一个更加pythonic,更加高效的办法
    s = " ".join(map(str, range(0, 10000)))

    作者回复: 👍

    2019-05-20
    127
  • 刘朋
    # 测试 1000 条数据,方式一
    import time
    start_time = time.perf_counter()
    s = ''
    for n in range(0, 1000):
        s += str(n)
    end_time = time.perf_counter()
    print('Time elapse: {}'.format(end_time - start_time))
    返回结果: Time elapse: 0.0004374515265226364

    # 测试 1000 条数据,方式二
    import time
    start_time = time.perf_counter()
    s = []
    for n in range(0, 1000):
        s.append(str(n))
    ''.join(s)
    end_time = time.perf_counter()
    print('Time elapse: {}'.format(end_time - start_time))
    返回结果: Time elapse: 0.0004917513579130173

    # 测试 1000 条数据,方式三
    import time
    start_time = time.perf_counter()
    s = ''.join(map(str, range(0, 1000)))
    end_time = time.perf_counter()
    print('Time elapse: {}'.format(end_time - start_time))
    返回结果:Time elapse: 0.00021015387028455734

    分别测试一百万和一千万条数据,结果如下:
    100万:
    方式一:Time elapse: 0.3384760869666934
    方式二:Time elapse: 0.34538754168897867
    方式三:Time elapse: 0.2445415174588561

    1000万:
    方式一:Time elapse: 4.24716751743108
    方式二:Time elapse: 3.1754934675991535
    方式三:Time elapse: 2.2939002392813563

    综上,方式三性能最优,其次是在超过1000万条数据以上时,方式二优于方式一,相反,方式一优于方式二。
    2019-05-20
    105
  • 大牛凯
    最新的f""用法了解一下?
    2019-05-20
    2
    27
  • Python高效编程
    新版本的 f-string性能更好,但容易把环境变量写进字符串。
    2019-05-20
    15
  • Geek_morty137
    %format形式在东西多了以后比较费事,结构冗长,会导致错误,比如不能正确显示元组或字典。幸运的是,未来有更光明的日子。
    str.format格式相对好一些,但参数多了或者处理更长字符串时还是冗长。
    f-string这种方式可以更加简化表达过程。还支持大小写(f.或者F.)

    作者回复: 👍

    2019-05-20
    14
  • ssikiki
    使用加法操作符'+='的字符串拼接方法。因为它是一个例外 ... 可是
    x = 'a'
    id(x) # 4345659208
    x += 'b'
    id(x) # 4376614424
    做完+=操作后, x的内存地址变了, 说明新生成了字符串,请问老师这为什么说是例外?
    2019-05-21
    2
    11
  • 夜路破晓
    想问下目前有没有建群,因为想通过多了解些,比如读完这篇关于字符串的介绍,我想跟小伙伴们讨论下关于新版本f-string。
    作为一个刚入门半年的新手来说,其实采用格式化方式其实区别不大,但就我个人而言,在学习理解的过程中,新版本更加高效易懂。
    2019-05-21
    8
  • 路伴友行
    哦,+= 每次都会扩容,而 [] 不会每次扩容
    2019-05-20
    7
  • 铁皮
    import time


    start_time = time.perf_counter()
    s = ''
    for n in range(0, 100000):
        s += str(n)
    end_time = time.perf_counter()

    print('time elapse: {}'.format(end_time - start_time))

    start_time = time.perf_counter()
    l = []
    for n in range(0, 100000):
        l.append(str(n))

    l = ' '.join(l)
    end_time = time.perf_counter()
    print('join time elapse: {}'.format(end_time - start_time))


    start_time = time.perf_counter()
    s = " ".join(map(str, range(0, 100000)))
    end_time = time.perf_counter()
    print('map time elapse: {}'.format(end_time - start_time))

    结果:
    time elapse: 0.12365277000000008
    join time elapse: 0.10721922699999997
    map time elapse: 0.053512809999999966

    看有人留言说s = " ".join(map(str, range(0, 100000))) 更高效。确实是
    2019-05-20
    7
  • Wing·三金
    直观上看似乎第二种方法的复杂度高一倍,但实际运行了下,第二种方法效率略高,当调高到50万的时候第二种的效率比第一种高出两倍以上。

    作者回复: 哈哈,对的。
    如果字符串拼接的次数较少时,用+=更快,但是如果次数很大时,join稍快一些

    2019-05-20
    5
  • Destroy、
    第一个更优。另外python3.6以后还有一个新的字符串格式化用法更高效。。print('no data available for person with id: {id}, name: {name}')
    2019-05-20
    1
    4
  • 黑铁打野王
    既然是提升,能不能讲一下Python解释器对于String类型内存分配的知识?

    作者回复: 你好!这方面的内容你有兴趣可以自己去了解一下(google或者源码)。我的想法是专栏的内容还是实用为主,这种知识属于比较偏的了,工程当中用的很少,所以这里可能会省略

    2019-05-20
    3
  • charily
    代码1复杂度:O(1)×n,即O(n);代码2复杂度:O(1)×n+ O(1)×n=o(2n),因此代码1效率更高?

    作者回复: 试试同时比较range(1000)和range(10000000)两种情况的结果

    2019-05-20
    3
  • farFlight
    这两个操作实际上时间相差无几,我把循环次数提高到一百万次还是伯仲之间。
    另外请问老师python中对字符串采用 is 对比的问题。
    比如代码:
    a = 'string'
    b = 'string'
    a is b
    将返回True

    a = 'string'
    a += '1'
    b = 'string1'
    a is b
    则返回False
    这个怎么解释比较好呢?为何第一个例子中a,b会指向同一个object呢?

    作者回复: 第一个例子中,'string'这个字符串对象只创建了一次,并同时被变量a和b指向,因此a is b返回True。

    第二个例子中刚开始初始化的时候a和b的id就是不一样的,a is b就是False啊

    2019-05-20
    3
  • Geek_1ea0d3
    .split()方法的例子那里,如果splitor是'//',不应该是按照单斜线/来分割嘛?
    2019-05-26
    2
  • carpe_diem
    第一种更优,虽然在时间复杂度上,两种方式都是O(n),但是第一种方法的空间复杂度优于第二种方式,第一种方法的空间复杂度为O(1),第二种方法的空间复杂度为O(n)。另外,第一种写法显然也更简洁一些

    作者回复: 你同时测试一下
    range(0, 100)

    range(0, 1000000)的情况比较一下,看看两者的结果有什么不同?

    2019-05-20
    2
  • 以马内利
    案例里
    l = []
    for n in range(0, 100000):
        l.append(str(n))
    l = ' '.join(l) 
    在这个案例里只考虑到了列表append 操作时间复杂度,join时是不是也应该先统计字符串的长度,也就是O(n),那整体的时间复杂度为什么不是O(2n)?
    2019-07-08
    1
  • Aspirin
    ''.join(map(str, range(N)))最高效是不是因为map取代了str(n)的遍历,所以差距是在map上。回归到字符串本身,则是join()比+=快。
    2019-05-29
    1
  • hysyeah
    老师好,我对于下面这段话有些疑问。
    自从 Python2.5 开始,每次处理字符串的拼接操作时(str1 += str2),Python 首先会检测 str1 还有没有其他的引用。如果没有的话,就会尝试原地扩充字符串 buffer 的大小,而不是重新分配一块内存来创建新的字符串并拷贝。


    我看python的源码对ci此并没有原地扩充的操作,而是每次都会新建一个string 对象。能详细解释下吗?谢谢。
    2019-05-25
    1
收起评论
87
返回
顶部