Python高级编程

星号的用法

  1. *** 的用法

    • 函数定义

      def foo(*args, **kwargs):
          pass
      
    • 参数传递

      def foo(x, y, z, a, b):
          print(x)
          print(y)
          print(z)
          print(a)
          print(b)
      lst = [1, 2, 3]
      dic = {'a': 22, 'b': 77}
      foo(*lst, **dic)
      
    • import 语法,默认是调用的all里面的内容,如果all里面没有也是调用不了的

      from xyz import *
      
      __all__ = ('a', 'e', '_d')
      
      a = 123
      b = 456
      c = 'asdfghjkl'
      _d = [1,2,3,4,5,6]
      e = (9,8,7,6,5,4)
      
    • 强制命名参数,*后面的那个形参必须使用关键字命名,不能使用位置命名

      def foo(a, *, b, c=123):
          pass
      
1
2
3
4
5
a = 123
b = 456
def bar(a,*,b,c=123):
print(a,b,c)
bar(a,b=333,c=0)
  • 解包语法: a, b, *ignored, c = [1, 2, 3, 4, 5, 6, 7]
1
2
3
4
5
6
L = [1,2,3,4,5,6,7,8,9,0]
# 将列表中的第一个值赋给a,第二个值赋给b,最后一个值赋给c,其他的都是给ignored
a,b,*ignored,c = L
print(a)
print(b)
print(c)

赋值和引用

  1. Python 的赋值和引用

    • ==, is: == 判断的是值, is 判断的是内存地址 (即对象的id)
    • 小整数对象: [-5, 256],缓存
    • copy, deepcopy 的区别

      • copy: 只拷贝表层元素
      • deepcopy: 在内存中重新创建所有子元素

        Untitled-1-2018424192358

    • 函数的形式参数为可变的时候,调用的时候不会重新被置空,而是在原来的基础上操作

      def extendList(val, lst=[]):
          lst.append(val)
          return lst
      
      list1 = extendList(10)
      list2 = extendList(123, [])
      list3 = extendList('a')
      
1
2
3
4
结果:
list1= [10, 'a']
list2= [10, 'a']
list3= [123]
- 浅复制和深复制

        from copy import copy, deepcopy
        from pickle import dumps, loads

        a = ['x', 'y', 'z']
        b = [a] * 3
        c = copy(b)
        d = deepcopy(b)
        # 第二个参数指的是调用了第几种算法,性能有区别,底层是定义好的
        e = loads(dumps(b, 4))

        b[1].append(999)
        c[1].append(999)
        d[1].append(999)
        e[1].append(999)

Untitled-1-201842419308

1
2
3
4
5
6
结果
a= ['x', 'y', 'z', 999, 999]
b= [['x', 'y', 'z', 999, 999], ['x', 'y', 'z', 999, 999], ['x', 'y', 'z', 999, 999]]
c= [['x', 'y', 'z', 999, 999], ['x', 'y', 'z', 999, 999], ['x', 'y', 'z', 999, 999]]
d= [['x', 'y', 'z', 999], ['x', 'y', 'z', 999], ['x', 'y', 'z', 999]]
e= [['x', 'y', 'z', 999], ['x', 'y', 'z', 999], ['x', 'y', 'z', 999]]
  • 自定义 deepcopy: my_deepcopy = lambda item: loads(dumps(item, 4)),使用自定义的这个深复制比Python自带的这个deepcopy效率要高,虽然说,Python的底层也是这个原理实现的,一般对性能要求高的时候,可以采用自定义的这个。
  • Python的可变类型:列表,字典(这里的可变不可变指的是内存中)
  • python的不可变类型:数字,字符串,元组

迭代器,生成器

  1. 迭代器, 生成器

    class Range:
        def __init__(self, start, end, step):
            self.start = start - step
            self.end = end
            self.step = step
    
        def __iter__(self):
            return self
    
        def __next__(self):
            current = self.start + self.step
            if current < self.end:
                self.start = current
                return current
            else:
                raise StopIteration()
    
    • iterator: 任何实现了 __iter____next__ (python2中是 next()) 方法的对象都是迭代器.

      • __iter__返回迭代器自身
      • __next__ 返回容器中的下一个值
      • 如果容器中没有更多元素, 则抛出StopIteration异常
    • generator: 生成器其实是一种特殊的迭代器, 不需要自定义 __iter____next__

      • 生成器函数 (yield)
      • 生成器表达式
    • 练习1: 定义一个随机数迭代器, 随机范围为 [1, 50], 最大迭代次数 30

      import random
      
      class RandomIter:
          def __init__(self, start, end, times):
              self.start = start
              self.end = end
              self.max_times = times
              self.count = 0
      
          def __iter__(self):
              return self
      
          def __next__(self):
              self.count += 1
              if self.count <= self.max_times:
                  return random.randint(self.start, self.end)
              else:
                  raise StopIteration()
      
    • 练习2: 自定义一个迭代器, 实现斐波那契数列

      class Fib:
          def __init__(self, max_value):
              self.prev = 0
              self.curr = 1
              self.max_value = max_value
      
          def __iter__(self):
              return self
      
          def __next__(self):
              if self.curr < self.max_value:
                  res = self.curr
                  self.prev, self.curr = self.curr, self.prev + self.curr
                  return res
              else:
                  raise StopIteration()
      
    • 练习3: 自定义一个生成器函数, 实现斐波那契数列

      def fib(max_value):
          prev = 0
          curr = 1
          while curr < max_value:
              yield curr
              prev, curr = curr, curr + prev
      
    • 迭代器、生成器有什么好处?

      • 节省内存
      • 惰性求值
    • itertools

      • 无限迭代
        • count(start=0, step=1)等同于(start + step * i for i in count())
        • cycle(iterable)
        • repeat(object [,times])创建一个迭代器,重复生成object,times(如果已提供)指定重复计数,如果未提供times,将无止尽返回该对象。
      • 有限迭代
        • chain(*iterables)将多个迭代器作为参数, 但只返回单个迭代器, 它产生所有参数迭代器的内容, 就好像他们是来自于一个单一的序列# chain('ABC', 'DEF') --> A B C D E F
      • 排列组合
        • product(*iterables, repeat=1) 笛卡尔积
        • permutations(iterable[, r-length]) 全排列
        • combinations(iterable, r-length) 组合
    • 各种推导式

      • 列表: [i for i in range(5)]
      • 字典: {i: i + 3 for i in range(5)}
      • 集合: {i for i in range(5)}

装饰器

  1. 装饰器

    • 最简装饰器,原理中使用了闭包

      def deco(func):
          def wrap(*args, **kwargs):
              return func(*args, **kwargs)
          return wrap
      
      @deco
      def foo(a, b):
          return a ** b
      
    • 原理

      • 手动执行装饰的过程
      • 对比被装饰前后的 foo.__name__foo.__doc__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def check(func):
def wrap(x, y):
return func(x, y)
return wrap


def bar(x, y):
'''this is bar'''
return x * y


# 手动执行装饰的过程
wrap = check(bar) # 装饰
print(bar, id(bar))
bar = wrap # 替换原函数
print(bar, id(bar))
bar(3, 7) # 执行装饰后的函数

结果:

1
2
<function bar at 0x0000023AE62D3158> 2451993080152
<function check.<locals>.wrap at 0x0000023AE62D31E0> 2451993080288

注意:locals指的是局部变量

查看装饰过程中的变化:

1
2
3
4
5
6
def foo():
'''i am foo'''
pass

print(foo.__name__)
print(foo.__doc__)

结果:

1
2
foo
i am foo

加上装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def deco(func):
'''i am deco'''
# @wraps(func)
def wrap(*args, **kwargs):
'''i am wrap'''
return func(*args, **kwargs)
return wrap

@deco
def foo():
'''i am foo'''
pass

print(foo.__name__)
print(foo.__doc__)

结果:

1
2
wrap
i am wrap

装饰器内使用装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from functools import wraps
def deco(func):
'''i am deco'''
@wraps(func)
def wrap(*args, **kwargs):
'''i am wrap'''
return func(*args, **kwargs)
return wrap

# 语法糖
@deco
def foo():
'''i am foo'''
pass

print(foo.__name__)
print(foo.__doc__)

结果:

1
2
foo
i am foo

  • 简单过程

    fn = deco(func)
    foo = fn
    foo(*args, **kwargs)
    
  • 多个装饰器调用过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
print('**************定义多个装饰器**********************')
def deco1(func):
print('enter deco1')
def wrap1(*args, **kwargs):
print('enter wrap1')
print('Func is: %s' % func.__name__)
result = func(*args, **kwargs)
print('exit wrap1')
return result
print('exit deco1')
return wrap1


def deco2(func):
print('enter deco2')
def wrap2(*args, **kwargs):
print('enter wrap2')
print('Func is: %s' % func.__name__)
result = func(*args, **kwargs)
print('exit wrap2')
return result
print('exit deco2')
return wrap2


def deco3(func):
print('enter deco3')
def wrap3(*args, **kwargs):
print('enter wrap3')
print('Func is: %s' % func.__name__)
result = func(*args, **kwargs)
print('exit wrap3')
return result
print('exit deco3')
return wrap3

@deco1
@deco2
@deco3
def foo(x, y):
return x ** y
print('**************使用多个装饰器**********************')
res = foo(3, 2)
print(res)

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
**************定义多个装饰器**********************
enter deco3
exit deco3
enter deco2
exit deco2
enter deco1
exit deco1
**************使用多个装饰器**********************
enter wrap1
Func is: wrap2
enter wrap2
Func is: wrap3
enter wrap3
Func is: foo
exit wrap3
exit wrap2
exit wrap1
9

  • 装饰器定义的时候,就近原则独立完成装饰器的定义,
  • 装饰器使用的时候,从距离函数远的开始,一层一层的进入,然后再一层一层的出去

  • 装饰器的过程拆解

    deco1(
              deco2(
                  deco3(foo)
              )
          )(3, 4)
    
1
2
3
4
5
6
7
8
9
10
11
def bar(x, y):
return x ** y


wrap3 = deco3(bar)
wrap2 = deco2(wrap3)
wrap1 = deco1(wrap2)
bar = wrap1
print('------ define -------')
res = bar(3, 3)
print(res)
  • 带参数的装饰器

    def deco(n):
        def wrap1(func):
            def wrap2(*args, **kwargs):
                return func(*args, **kwargs)
            return wrap2
        return wrap1
     #调用过程
     wrap1 = deco(n)
     wrap2 = wrap1(foo)
     foo = wrap2
     foo()
     #单行形式
     check_result(30)(bar)(4,8)
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def check_result(n):
# 确保被装饰函数返回值大于等于n
# deco才是真正的装饰器
def deco(func):
def wrap(*args,**kwargs):
result = func(*args,**kwargs)
if result < n:
return n
else:
return result
return wrap
return deco


@check_result(30)
def foo(x,y):
return x*y

print(foo(3,9))
print(foo(3,11))

结果:

1
2
30
33

  • 装饰器类和 __call__,能够执行的都是因为有__call__,函数被调用的过程,其实就是__call__被调用的过程,callable()可调用的

    class Deco:
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            return self.func(*args, **kwargs)
    
    @Deco
    def foo(x, y):
        return x ** y
    
    # 过程拆解
    fn = Deco(foo)
    foo = fn
    foo(12, 34)
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CheckResult:
def __init__(self,func):
self.func = func


def __call__(self, *args, **kwargs):
result = self.func(*args, **kwargs)
if result > 50:
return result
else:
return 50

@CheckResult
def foo(x,y):
return x*y

print(foo,isinstance(foo,CheckResult)) ## True
print(foo(3,9)) ##50


# 过程拆分
# inner = CheckResult(foo)
# foo = inner
# foo(x,y)
  • 使用场景

    * 参数、结果检查
    * 缓存、计数
    * 日志、统计
    * 权限管理
    * 重试
    * 其他
    
  • 写一个 timer 装饰器, 计算出被装饰函数调用一次花多长时间, 并把时间打印出来

    import time
    from functools import wraps
    
    def timer(func):
        @wraps(func)  # 修正 docstring
        def wrap(*args, **kwargs):
            time0 = time.time()
            result = func(*args, **kwargs)
            time1 = time.time()
            print(time1 - time0)
            return result
        return wrap
    
  • 写一个 Retry 装饰器,重试

    import time
    
    class retry(object):
        def __init__(self, max_retries=3, wait=0, exceptions=(Exception,)):
            self.max_retries = max_retries
            self.exceptions = exceptions
            self.wait = wait
    
        def __call__(self, f):
            def wrapper(*args, **kwargs):
                for i in range(self.max_retries + 1):
                    try:
                        result = f(*args, **kwargs)
                    except self.exceptions:
                        time.sleep(self.wait)
                        continue
                    else:
                        return result
            return wrapper
    

闭包

  • 引用了自由变量的函数即是一个闭包,这个被引用的自由变量和这个函数一同存在,即使已经离开了创造他的环境也不例外,装饰器本身就是一个闭包,但是闭包不一定就是装饰器

  • 说出下面函数返回值

    def foo():
        l = []
        def bar(i):
            l.append(i)
            return l
        return bar
    
    f1 = foo()
    f2 = foo()
    
    # 说出下列语句执行结果
    f1(1)
    f1(2)
    f2(3)
    
    • 作用域

      • global 声明全局变量
      • nonlocal 声明非本层的局部变量
      • globals() 查看全局变量
      • locals() 查看局部变量
      • vars() 查看变量,不传参数相当于locals(),传入对象后,会得到object.__dict__

        local namespace
            |
            V
        global namespace
            |
            V
        builtin namespace 内置的命名空间
        
    • 更深入一点: __closure__,装饰器中原本的那个函数改变了,那么要想找到原来的那个函数,就需要和这个属性,

    • Python中dis.dis(bar)可以查看Python解释器中的语句

方法

  1. method, classmethodstaticmethod

    • method: 通过实例调用时, 可以引用类内部的任何属性和方法

    • classmethod: 无需实例化, 可以调用类属性和类方法, 无法取到普通的成员属性和方法

    • staticmethod: 无论用类调用还是用实例调用, 都无法取到类内部的属性和方法, 完全独立的一个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Test(object):
# 类属性
x = 123

def __init__(self):
self.y = 456

# 实例方法
def bar1(self):
print('i am a method')

@classmethod
def bar2(cls):
print('i am a classmethod')

@staticmethod
def bar3():
print('i am a staticmethod')

def foo1(self): # self当前对象
print(self.x)
print(self.y)
self.bar1()
self.bar2()
self.bar3()

# 类方法
@classmethod
def foo2(cls): # cls就是类本身
print(cls.x)
# print(cls.y) # 通过类取不到实例的属性
# cls.bar1() # 类调用不到实例方法,cls.bar1(cls())
Test.bar2()
Test.bar3()

@staticmethod
def foo3(obj):
print(obj.x)
print(obj.y)
obj.bar1()
obj.bar2()
obj.bar3()


t = Test()

t.bar1() # 对象调用实例方法
Test.bar1(t) # 通过类的方式调用实例方法

t.foo1()
# i am a method
# i am a method
# 123
# 456
# i am a method
# i am a classmethod
# i am a staticmethod
t.foo2()
t.foo3(t)

继承

  1. 继承、多继承、多态、Mixin、super

    • 继承
    • 多态,一个对象有多种形态

      class Animal:
          pass
      
      class Cat(Animal):
          pass
      
      class Tom(Cat):
          pass
      
      tom = Tom()
      isinstance(tom, Cat)
      isinstance(tom, Animal)
      
    • 多继承

      • Cls.mro()
      • 菱形继承问题

        # 继承关系示意
        #
        #      A.foo()
        #    /   \
        #   B     C.foo()
        #    \   /
        #      D
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Animal:
def foo(self):
print('aaaa')
class Cat(Animal):
def foo(self):
print('aaaa')

class Dog(Animal):
def foo(self):
print('aaaa')

class New(Cat,Dog):
pass

new = New()
new.foo()
print(New.mro()) # 方法继承的顺序

结果:

1
2
aaaa
[<class '__main__.New'>, <class '__main__.Cat'>, <class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>]

  • Mixin,混入式继承,专门用来为其他类提供功能,只写他需要的功能,通过单纯的Mixin类完成功能的组合
  • Untitled-1-201842622313
  • Super,super是根据继承的顺序执行了,Cls.mro(),这个继承的顺序是根据C3算法得到的,通过距离优先算法去查找

手动执行构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class A:
def __init__(self):
print('enter A')
self.x = 111
print('exit A')

class B(A):
def __init__(self):
print('enter B')
A.__init__(self)
# super().__init__()
print('exit B')

class C(A):
def __init__(self):
print('enter C')
A.__init__(self)
# super().__init__()
print('exit C')
class D(B, C):
def __init__(self):
print('enter D')
B.__init__(self)
C.__init__(self)
# super().__init__()
print('exit D')

d = D()

执行结果:执行了2次A,如果是连接数据库的操作,或者文件操作的时候,就会出现问题

1
2
3
4
5
6
7
8
9
10
enter D
enter B
enter A
exit A
exit B
enter C
enter A
exit A
exit C
exit D

使用super改进:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class A:
def __init__(self):
print('enter A')
self.x = 111
print('exit A')


class B(A):
def __init__(self):
print('enter B')
# A.__init__(self)
super().__init__()
print('exit B')


class C(A):
def __init__(self):
print('enter C')
# A.__init__(self)
super().__init__()
print('exit C')


class D(B, C):
def __init__(self):
print('enter D')
# B.__init__(self)
# C.__init__(self)
super().__init__()
# super(D,self).__init__()
print('exit D')

d = D()

执行结果:

1
2
3
4
5
6
7
8
enter D
enter B
enter C
enter A
exit A
exit C
exit B
exit D

魔术方法

  • __str__控制对象格式化的输出,对应str(), __repr__有个repr(),一般配合着eval()还原字符串中的内容
  • reprstr这两个方法都是用于显示的,str是面向用户的,而repr面向程序员。

打印操作会首先尝试str和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示。

repr用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用str,会使用print和str。它通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。

当我们想所有环境下都统一显示的话,可以重构repr方法;当我们想在不同环境下支持不同的显示,例如终端用户显示使用str,而程序员在开发期间则使用底层的repr来显示,实际上str只是覆盖了repr以得到更友好的用户显示。

  • __init____new____new__()
    • __new__ 返回一个对象的实例, 实例不带有任何的属性,可以动态添加,__init__初始化,无返回值
    • __new__ 是一个类方法
    • __init__初始化的数据都保存在__dict__里面
    • 注意在和None进行判断的时候使用is效率更高
      • 单例模式
class A(object):
    '''单例模式'''
    obj = None
    def __new__(cls, *args, **kwargs):
        if cls.obj is None:
            cls.obj = object.__new__(cls)
        return cls.obj
  • 比较运算、数学运算

    • update()方法,在字典中使用,更新
    • 运算符重载

      • +: __add__(value)列表,元组(不同长度的不可以做加法),字符串,int,float类型都可以做加法,集合可以做& | -运算

      • -: __sub__(value)

      • *: __mul__(value)列表,字符串,元组可以相乘
      • /: __truediv__(value) (Python 3.x), __div__(value) (Python 2.x)
      • //: __floordiv__(value)向下取整,math库中的ceil()向上取整
      • %: __mod__(value)
      • &: __and__(value)
      • |: __or__(value)
  • 实现字典的 __add__ 方法, 作用相当于 d.update(other)

    class Dict(dict):
        def __add__(self, other):
            if isinstance(other, dict):
                new_dict = {}
                new_dict.update(self)
                new_dict.update(other)
                return new_dict
            else:
                raise TypeError('not a dict')
    
  • 比较运算符的重载
    • ==: __eq__(value)
    • !=: __ne__(value)
    • >: __gt__(value)
    • >=: __ge__(value)
    • <: __lt__(value)
    • <=: __le__(value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
实现数学上无穷大的概念
class Inf:
def __lt__(self, other):
return False

def __le__(self, other):
return False

def __ge__(self, other):
return True

def __gt__(self, other):
return True

def __eq__(self, other):
return False

def __ne__(self, other):
return True
  • 容器方法,列表,元组,字符串,字典,集合都是容器类型,注意所有的不可变的都可以作为字典的key,可变的不可以作为key,因为得不到一个具体的哈希值

    • __len__ -> len
    • __iter__ -> for
    • __contains__ -> in
    • __getitem__string, list, tuple, dict 有效,通过【】方括号取值的时候会默认执行,
    • __setitem__list, dict 有效
    • __missing__dict 有效, 字典的预留接口, dict 自身并没有实现

      class Dict(dict):
          def __missing__(self, key):
              self[key] = None  # 当检查到 Key 缺失时, 可以做任何默认行为
      
  • 可执行对象: __call__
  • with是一个关键字
    • __enter__ 进入 with 代码块前的准备操作
    • __exit__ 退出时的善后操作
    • 打开文件时,有colsed属性,可以查看文件是否关闭了
1
2
3
4
5
6
7
8
9
10
class A:
def __enter__(self):
print(111,)
def __exit__(self, exc_type, exc_val, exc_tb):
print(33333,exc_type, exc_val, exc_tb)

a = A()
with A() as a:
print(222,a)
# print(222,a[1233]) 报错

执行结果:

1
2
3
111
222 None
33333 None None None

如果执行错误的,结果就是这样的

1
2
111
33333 <class 'TypeError'> 'NoneType' object is not subscriptable <traceback object at 0x000001BAFB6C7888>

注意:有错误的时候,exit后面的三个参数就会分别打印出错误类型,详细的错误信息,traceback对象,回溯,跟踪错误

  • __setattr__, __getattribute__, __getattr__, __dict__对应于setattr(),getattr(),hasattr(),dict(),方法
  • __getattribute__对应着所有的点操作
  • 类的方法属性保存在类的__dict__
  • __getattr__用来处理取不到属性方法的

    • 常用来做属性监听,监听属性的变化,钩子

      class A:
          '''TestClass'''
          z = [7,8,9]
          def __init__(self):
              self.x = 123
              self.y = 'abc'
      
          def __setattr__(self, name, value):
              print('set %s to %s' % (name, value))
              object.__setattr__(self, name, value)
      
          def __getattribute__(self, name):
              print('get %s' % name)
              return object.__getattribute__(self, name)
      
          def __getattr__(self, name):
              print('not has %s' % name)
              return -1
      
          def foo(self, x, y):
              return x ** y
      
      # 对比
      a = A()
      print(A.__dict__)
      print(a.__dict__)
      
  • 槽: __slots__

    • 固定类所具有的属性
    • 实例不会分配 __dict__
    • 实例无法动态添加属性
    • 优化内存分配

      class A:
          __slots__ = ('x', 'y')
      

垃圾收集

  1. Garbage Collection (GC)
    • 引用计数
      • 优点: 简单、实时性高
      • Untitled-1-201842622349
      • 缺点: 消耗资源、循环引用无法处理
    • 标记-清除, 分代收集
lst1 = [3, 4]           # lst1->ref_count 1
lst2 = [8, 9]           # lst2->ref_count 1

# lst1 -> [3, 4, lst2]
lst1.append(lst2)       # lst2->ref_count 2

# lst2 -> [8, 9, lst1]
lst2.append(lst1)       # lst1->ref_count 2

del lst1                # lst1->ref_count 1
del lst2                # lst2->ref_count 1

Untitled-1-201842622053

产生垃圾

Untitled-1-201842622125

性能

动态语言性能上和静态语言无法抗衡,
静态语言:C, C++, GO C#,Java
动态语言:Python,JavaScript,Ruby,PHP,Lua 【脚本语言】

  1. Python 性能之困

    1. 计算密集型
      • CPU 长时间满负荷运行, 如图像处理、大数据运算、圆周率计算等
      • 计算密集型: 用 C 语言补充
      • Profile, timeit
    2. I/O 密集型: 网络 IO, 文件 IO, 设备 IO 等
      • 多任务处理: 进程 / 线程 / 协程
      • 阻塞 -> 非阻塞
      • 同步 -> 异步
    3. GIL 全局解释器锁
      • 它确保任何时候都只有一个Python线程执行。
        Untitled-1-2018426215848
    4. 什么是进程、线程、协程?
      • 进程: 资1. 源消耗大, 系统整体开销大, 数据通信不方便
      • 线程: 资源消耗小, 可共享数据。上下文开销大。按时间片强制切换, 不够灵活
      • 协程: 内存开销更小, 上下文切换开销更小。可根据事件切换, 更加有效的利用 CPU,stackless/greenlets/Gevent利用的第三方完成的协成,tornado、asyncio使用Python原生的代码实现的协成,Twisted使用的是回调机制
      • 进程、线程、协程调度的过程叫做上下文切换
    5. 什么是同步、异步、阻塞、非阻塞?
      • 同步, 异步: 客户端调用服务器接口时
      • 阻塞, 非阻塞: 服务端发生等待
      • 同步,是有顺序的,一个接一个的进行
      • 处理并发就是构建异步非阻塞程序
    6. 事件驱动 + 多路复用
      • 轮询: select, poll
      • 事件驱动: epoll 有效轮询
    7. greenlet / gevent | tornado / asyncio

      import asyncio
      
      async def foo(n):
          for i in range(10):
              print('wait %s s' % n)
              await asyncio.sleep(n)
          return i
      
      task1 = foo(1)
      task2 = foo(1.5)
      tasks = [asyncio.ensure_future(task1),
               asyncio.ensure_future(task2)]
      
      loop = asyncio.get_event_loop()
      loop.run_until_complete(asyncio.wait(tasks))
      
    8. 线程安全, 锁

      • 获得锁之后, 一定要释放, 避免死锁
      • 获得锁之后, 执行的语句, 只跟被锁资源有关
      • 区分普通锁 Lock, 可重入锁 RLock
      • 线程之间的数据交互尽量使用 Queue
    9. gevent
      • monkey.patch
      • gevent.sleep 非阻塞式等待
      • Queue 协程间数据交互, 避免竞争

技巧

  1. 一些技巧和误区

    1. 格式化打印
      • json.dumps(data, indent=4, sort_keys=True, ensure_ascii=False)
      • json 压缩: json.dumps(obj, separators=[',',':'])
      • pprint
    2. 确保能取到有效值
      • d.get(k, default)
      • d.setdefault
      • defaultdict
      • a or b 可以省去很多if判断,短路
      • x = a if foo() else b
    3. try…except… 的滥用
      • 不要把所有东西全都包住, 程序错误需要报出来
      • 使用 try...except 要指明具体错误, try 结构不是用来隐藏错误的, 而是用来有方向的处理错误的
    4. 利用 dict 做模式匹配

      def do1():
          print('i am do1')
      
      def do2():
          print('i am do2')
      
      def do3():
          print('i am do3')
      
      def do4():
          print('i am do4')
      
      mapping = {1: do1, 2: do2, 3: do3, 4: do4}
      mod = random.randint(1, 10)
      func = mapping.get(mod, do4)
      func()
      
    5. inf, -inf, nan

    6. venv, pyenv, 命名空间
      • venv: 创建虚拟环境, 做环境隔离, venv 目录直接放到项目的目录里
      • pyenv: 管理 Python 版本
    7. property: 把一个方法属性化

      class C(object):
          @property
          def x(self):
              "I am the 'x' property."
              return self._x
          @x.setter
          def x(self, value):
              self._x = value
          @x.deleter
          def x(self):
              del self._x
      
    8. else 子句: if, for, while, try

    9. collections 模块
      • defaultdict
      • OrderedDict
      • Counter 计数器
      • namedtuple 根据元组里面的内容定义类