Python核心技术与实战

https://time.geekbang.org/column/article/94972

 

基础篇 (14讲)

01 | 如何逐步突破,成为Python高手?

02 | Jupyter Notebook为什么是现代Python的必学技术?

03 | 列表和元组,到底用哪一个?


l = [1, 2, 'hello', 'world'] # 列表中同时含有int和string类型的元素
l
[1, 2, 'hello', 'world']

tup = ('jason', 22) # 元组中同时含有int和string类型的元素
tup
('jason', 22)

 思考题

1. 想创建一个空的列表,我们可以用下面的 A、B 两种方式,请问它们在效率上有什么区别吗?我们应该优先考虑使用哪种呢?可以说说你的理由。

# 创建空列表

# option A:empty_list = list()

# option B:empty_list = [] 

第二种效率更高,通过[]关键字可以直接调用底层C代码创建一个列表,而第一种方式还需要初始化一个list实例才能创建一个列表

2. 你在平时的学习工作中,是在什么场景下使用列表或者元组呢?欢迎留言和我分享。

列表:当需要根据请求参数返回查询对象的集合时,返回的对象数量是可变的,此时需要使用的是list

元组:当定义关系型数据库对象model时,需要在Meta类中定义返回数据对象的字段名集合,一般是不会改变的,所以使用元组

04 | 字典、集合,你真的了解吗?

05 | 深入浅出字符串

06 | Python “黑箱”:输入与输出

07 | 修炼基本功:条件与循环

08 | 异常处理:如何提高程序的稳定性?

09 | 不可或缺的自定义函数

10 | 简约不简单的匿名函数

11 | 面向对象(上):从生活中的类比说起

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

13 | 搭建积木:Python 模块化

14 | 答疑(一):列表和元组的内部实现是怎样的?

进阶篇 (11讲)

15 | Python对象的比较、拷贝

16 | 值传递,引用传递or其他,Python里参数是如何传递的?

17 | 强大的装饰器

基本用法


def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

@my_decorator # 等同于 greet = my_decorator(greet)
def greet():
    print('hello world')

greet()

有参数需要传递给装饰器怎么办?一个简单的办法,是可以在对应的装饰器函数 wrapper() 上,加上相应的参数,比如:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper

 带有自定义参数的装饰器

def repeat(num):
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(num):
                print('wrapper of decorator')
                func(*args, **kwargs)
        return wrapper
    return my_decorator


@repeat(4)
def greet(message):
    print(message)

greet('hello world')

# 输出:
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world

类装饰器

类装饰器主要依赖于函数__call__(),每当你调用一个类的示例时,函数__call__()就会被执行一次。

class Count:
    def __init__(self, func): #执行Count(*args,**kwargs)时调用
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):#执行Count(*args,**kwargs)()时调用
        self.num_calls += 1
        print('num of calls is: {}'.format(self.num_calls))
        return self.func(*args, **kwargs)

@Count
def example():
    print("hello world")

example()

# 输出
num of calls is: 1
hello world

example()

# 输出
num of calls is: 2
hello world

...

18 | metaclass,是潘多拉魔盒还是阿拉丁神灯?

事实上,meta-class 的 meta 这个词根,起源于希腊语词汇 meta,包含下面两种意思:

“Beyond”,例如技术词汇 metadata,意思是描述数据的超越数据;

“Change”,例如技术词汇 metamorphosis,意思是改变的形态。

metaclass,一如其名,实际上同时包含了“超越类”和“变形类”的含义,完全不是“基本类”的意思。所以,要深入理解 metaclass,我们就要围绕它的超越变形特性。

 

metaclass 的超越变形特性有什么用?

YAML是一个家喻户晓的 Python 工具,可以方便地序列化 / 逆序列化结构数据。

YAMLObject 的一个超越变形能力,就是它的任意子类支持序列化和反序列化(serialization & deserialization)。比如说下面这段代码:


class Monster(yaml.YAMLObject):
  yaml_tag = u'!Monster'
  def __init__(self, name, hp, ac, attacks):
    self.name = name
    self.hp = hp
    self.ac = ac
    self.attacks = attacks
  def __repr__(self):
    return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
       self.__class__.__name__, self.name, self.hp, self.ac,      
       self.attacks)

yaml.load_all("""
--- !Monster
name: Cave spider
hp: [2,6]    # 2d6
ac: 16
attacks: [BITE, HURT]
""")

Monster(name='Cave spider', hp=[2, 6], ac=16, attacks=['BITE', 'HURT'])

print yaml.dump(Monster(
    name='Cave lizard', hp=[3,6], ac=16, attacks=['BITE','HURT']))

# 输出
!Monster
ac: 16
attacks: [BITE, HURT]
hp: [3, 6]
name: Cave lizard

 调用统一的 yaml.load(),就能把任意一个 yaml 序列载入成一个 Python Object;

而调用统一的 yaml.dump(),就能把一个 YAMLObject 子类序列化。

对于 load() 和 dump() 的使用者来说,他们完全不需要提前知道任何类型信息,这让超动态配置编程成了可能。在我的实战经验中,许多大型项目都需要应用这种超动态配置的理念。

对于 YAML 的使用者,这一点也很方便,你只要简单地继承 yaml.YAMLObject,就能让你的 Python Object 具有序列化和逆序列化能力。是不是相比普通 Python 类,有一点“变态”,有一点“超越”?

 

Python 底层语言设计层面是如何实现 metaclass 的?刚才我们提到,metaclass 能够拦截 Python 类的定义。它是怎么做到的?要理解 metaclass 的底层原理,你需要深入理解 Python 类型模型。下面,我将分三点来说明。

第一,所有的 Python 的用户定义类,都是 type 这个类的实例。可能会让你惊讶,事实上,类本身不过是一个名为 type 类的实例。在 Python 的类型世界里,type 这个类就是造物的上帝。这可以在代码中验证:# Python 3和Python 2类似class MyClass:  passinstance = MyClass()type(instance)# 输出type(MyClass)# 输出你可以看到,instance 是 MyClass 的实例,而 MyClass 不过是“上帝”type 的实例。第二,用户自定义类,只不过是 type 类的__call__运算符重载。

 

第二,用户自定义类,只不过是 type 类的__call__运算符重载。当我们定义一个类的语句结束时,真正发生的情况,是 Python 调用 type 的__call__运算符。简单来说,当你定义一个类时,写成下面这样时:

 

第三,metaclass 是 type 的子类,通过替换 type 的__call__运算符重载机制,“超越变形”正常的类。其实,理解了以上几点,我们就会明白,正是 Python 的类创建机制,给了 metaclass 大展身手的机会。一旦你把一个类型 MyClass 的 metaclass 设置成 MyMeta,MyClass 就不再由原生的 type 创建,而是会调用 MyMeta 的__call__运算符重载。

 

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核心技术与实战)