Interview

Python

1 Namespace


>>> a = 5
>>> globals()
{'a': 5, ...}  a 指向5这个对象 

>>> a = "test"
>>> globals()
{'a': 'test', ...}  a 指向'test'这个对象

Python源码中, 有这样一句话: Names have no type, but objects do.

Python的名字实际上是一个字符串对象,

它和所指向的目标对象一起在名字空间中构成一项 {name: object} 关联。

这样Python就拥有了动态语言的动能

2 Pass A Variable


当一个参数传递给函数的时候, 相当于a (local) = a (global) 赋值操作

虽然它们不是同一个变量, 但它们任然指向同一个对象.

# immutable  For example string, tuple and number
a = 1

print(id(a))  # 10914368


def fun(a):
    print(id(a))  # 10914368
    a = 2         # 这里改变a (local) 指向的对象
    print(id(a))  # 10914400


fun(a)
print(id(a))  # 10914368

# mutable  For example list, dict and set
a = [] 
print(id(a))  # 140408380111368


def fun(a):
    print(id(a))  # 140408380111368
    a.append(1)   # 这里没有改变a (local) 指向的对象
    print(id(a))  # 140408380111368


fun(a)
print(id(a))  # 140408380111368

3 instance Variable and class Variable


class Person:
    name = "aaa"


p1 = Person()
p2 = Person()
p1.name = "bbb"         # 创建实例变量name 并指向新的对象
print(id(p1.name))      # 140078039596032
print(id(p2.name))      # 140078039563040 访问类变量
print(id(Person.name))  # 140078039563040 访问类变量


class Person:
    name = [] 


p1 = Person()
p2 = Person()
p1.name.append(1)       # 访问类变量
print(id(p1.name))      # 140078039616392 访问类变量
print(id(p2.name))      # 140078039616392 访问类变量
print(id(Person.name))  # 140078039616392 访问类变量

4 List Comprehension


a = [1, 2, 3, 4]

[x**2 for x in a]  # [1, 4, 9. 16]


表达式会按照从左至右的顺序来执行

matrix= [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

[x for row in matrix for x in row] 
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

[[x**2 for x in row] for row in matrix]
# [[1, 4, 9], [16, 25, 36], [49, 64, 81]]

[[x for x in row if x % 3 ==0] for row in matrix if sum(row) >= 10]


这个例子已经有点复杂。

在列表推导中,最好不要使用两个以上的表达式。
可以使用两个条件、两个循环或一个条件搭配一个循环。

如果很复杂,应该用 if  for 语句写成辅助函数。

matrix= [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

[[x for x in row if x % 3 == 0] for row in matrix if sum(row) >= 10]
# [[6], [9]]


函数式编程代替列表推导


a = [1, 2, 3, 4]

b = map(lambda x: x**2, a)  # 惰性生成
list(b)  # [1, 4, 9, 16]

a = [1, 2, 3, 4]

b = filter(lambda x: x % 2 == 0, a)  # 惰性生成
list(b)  # [2, 4]

5 Generator


通常生成器是通过调用一个或多个yield表达式构成的函数生成的

def t(): 
    yield 5


t()  # <generator object ...>

l = [x for x range(5)]  # [0, 1, 2, 3, 4]

g = (x for x in range(5))  # <generator object ...>

注意:
    由生成器表达式所返回的那个迭代器是有状态的,
	用过一轮之后,就不要反复使用了

g = (x for x in range(5))
print(list(g))  # [0, 1, 2, 3, 4]
print(list(g))  # []

对于列表生成式,当输入的数据比较少时,不会出问题。

但如果输入的数据非常多,那么可能会消耗大量内存,并导致程序崩溃。

这时候考虑生成器。

g = (len(x) for x in open('t.txt'))

6 Dict Comprehension


keys = ["name", "age"]
values = ["Tom", 18]
d = {key: value for(key, value) in zip(keys, values)}
print(d)

# {'name': 'Tom', 'age': 18}

7 Single Underscore and Double Underscore


class T(object):

    def __init__(self, name, age):
        self._name = name 
        self.__age = age


t = T("Tom", 18)
print(t._name)
print(t._T__age)
print(t.__age)

__foo__: 一种约定, Python内部的名字,用来区别其他用户自定义的命名,以防冲突.

_foo: 一种约定,用来指定变量私有. 可以被继承.

__foo: 是真正的私有变量, 不能被继承, 用来区别其它类相同的命名, 
       但也可以通过_classname__foo来访问,
       we are all consenting adults here 
       一般不会通过这种方法来操作变量.

8 format


name = "John"
print("I'm {0}".format(name))
# I'm John
print("I'm {name}".format(name=name))
# I'm John
names = ["John", "Tom"]
print("I'm {0[0]}".format(names))
# I'm John

# ^、<、>分别是居中、左对齐、右对齐,后面带宽度
# :号后面带填充的字符,只能是一个字符,不指定的话默认是用空格填充

num = 3
print("{0:0^5}".format(num))
# 00300
print("{0:0<5}".format(num))
# 30000
print("{0:0>5}".format(num))
# 00003
print('{:,}'.format(1234567890))
# 1,234,567,890

9 args and kwargs


它们的顺序必须是

* 位置参数 > 默认参数 > 可变参数 >  命名关键字参数 > 关键字参数


位置参数


def t(name):    # name 就是一个位置参数
    print(name)

默认参数


def t(name, age=18):  # age 就是一个默认参数
    print(name, age)

t("John")     # John 18
t("Tom", 16)  # Tom 16


默认参数最好用不可变类型


# 在每个人加一个成绩

def t(name, scores=[]):
    scores.append(90)
    print(name, scores)

t("John", [80])
t("Tom", [76])

t("Marsh")
t("Jim")

# John [80, 90]
# Tom [76, 90]
# Marsh [90]
# Jim [90, 90]  # 出现错误



由于 scores 参数的默认值只会在模块加载时计算一次,
所以凡是以默认形式来调用 t 函数的代码,都将共享同一份数组。
这会引发非常奇怪的行为。

def t(name, scores=None):
    if scores is None:
        scores = [90]
    else:
        scores.append(90)
    print(name, scores)

t("John", [80])
t("Tom", [76])

t("Marsh")
t("Jim")

# John [80, 90]
# Tom [76, 90]
# Marsh [90]
# Jim [90]

可变参数


def t(name, age=18, *args):  # 把 *args 称为可变参数
    print(name, age)         # 会把 78 83 95 转成一个 tuple (元组)
    for score in args:       # 所以当参数特别多时,会耗尽内存,导致崩溃
        print(score)

t("John", 18, 78, 83)        # 这里必须写 age,不然会被后面的值覆盖

或者

scores = [78, 83]
t("John", 18, *scores)

# John 18
# 78
# 83

命名关键字参数


必须需要一个或多个关键字参数

def t(name, age=18, *, country, **kw):
    print(name, age)
    print(country)
    for key, value in kw.items():
        print(key, value)

t("John", 18, country="China", gender="male")

或者

def t(name, age=18, *args, country, **kw):
    print(name, age)
    for score in args:
        print(score)
    print(country)
    for key, value in kw.items():
        print(key, value)

t("John", 18, 78, 83, country="China", gender="male")

关键字参数


def t(name, age=18, *args, **kw):
    print(name, age)
    for score in args:
        print(score)
    for key, value in kw.items():
        print(key, value)


t("John", 18, 78, 83, gender="male")

或者

others = {"gender": "male"}
t("John", 18, 78, 83, **others)

又或者

scores = [78, 83]
others = {"gender": "male"}
t("John", 18, *scores, **others)

# John 18
# 78
# 83
# gender male

10 new and init


1. __new__是一个静态方法,__init__是一个实例方法.

2. __new__方法会返回一个创建的实例,__init__什么都不返回.

3. 只有在__new__返回一个cls的实例时后面的__init__才能被调用.

4. 当创建一个新实例时调用__new__,初始化一个实例时用__init__.

11 Singleton


在我们工作中经常需要在应用程序中保持一个唯一的实例,

如:IO处理,数据库操作,配置文件等,由于这些对象都要占用重要的系统资源,

所以我们必须始终使用一个公用的实例,如果创造出来多个实例,就会导致许多问题,

比如占用过多资源,不一致的结果等

class Singleton(object):

    def __new__(cls, *args, **kwarg):
        if not hasattr(cls, "_instance"):
            orign = super(Singleton, cls)  # 不清楚什么意思 
            cls._instance = orign.__new__(cls, *args, **kwarg)
        return cls._instance


class MyClass(Singleton):
    pass 


my1 = MyClass()
my2 = MyClass()
print(id(my1))  # 140160695672168
print(id(my2))  # 140160695672168


另外一种单例模式

# mysingleton.py
class My_Singleton(object):
    def foo(self):
            pass

            my_singleton = My_Singleton()

# to use
from mysingleton import my_singleton

my_singleton.foo()

12 作用域


* L Local 局部作用域
* E Enclosing 闭包函数外的函数中
* G Global 全局作用域
* B Built-in 内建作用域

 L --> E --> G --> B 的规则查找,即:在局部找不到,

便会去局部外的局部找,再找不到就会去全局找,再者去内建中找。


__builtins__.a = 0  # Built-in variable
        
b = 1               # Global variable
        

def outside():
    c = 2           # Enclosing variable

    def inside():
        d = 3       # Local variable
        print(a)
        print(b)
        print(c)
        print(d)

    inside()


outside()

# 0
# 1
# 2
# 3


修改Global variable

a = 0              
  
  
def outside():
    b = 1          

    def inside():
        global a    # 与全局变量a指向同一个对象
        a = 100
        c = 2      
        print(a)
        print(b)
        print(c)

    inside()

outside()
print(a)

# 100
# 1
# 2
# 100


修改Enclosing variable

a = 0              
  
  
def outside():
    b = 1          

    def inside():
        nonlocal b    # 与Enclosing variable b指向同一个对象
        b = 10
        c = 2      
        print(a)
        print(b)
        print(c)

    inside()
    print(b)

outside()

# 0
# 10
# 2
# 10


globals

a = 0
print(globals())        # {'a': 0 ...}


def outside():
    globals()['b'] = 1
outside()
print(globals())        # {'a': 0, 'b': 1 ...}


locals

def outside():
    a = 0
    print(locals())     # {'a': 0}
outside()

13 copy and deepcopy


import copy
a = [1, 2, 3, 4, ['a', 'b']]  #原始对象

b = a  #赋值,传对象的引用
c = copy.copy(a)  #对象拷贝,浅拷贝
d = copy.deepcopy(a)  #对象拷贝,深拷贝

a.append(5)  #修改对象a
a[4].append('c')  #修改对象a中的['a', 'b']数组对象

print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d

输出结果:
a =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c =  [1, 2, 3, 4, ['a', 'b', 'c']]
d =  [1, 2, 3, 4, ['a', 'b']]

14 contextmanager



日志打印 

import logging


def t():
    logging.debug("Some debug data")
    logging.error("Error log here")
    logging.debug("More debug data")


t()

# ERROR:root:Error log here



在上下文环境下日志打印 

import logging
from contextlib import contextmanager
    
    
def t():
    logging.debug("Some debug data")
    logging.error("Error log here")
    logging.debug("More debug data")


@contextmanager
def debug_logging(level):
    logger = logging.getLogger()
    old_level = logger.getEffectiveLevel()
    logger.setLevel(level)
    try:
        yield
    finally:
        logger.setLevel(old_level)


with debug_logging(logging.DEBUG):
    print("Inside:")
    t()          # 日志打印的级别为 DEBUG
print("After:")  # 日志打印的级别重新恢复为ERROR
t()


# Inside:
# DEBUG:root:Some debug data
# ERROR:root:Error log here
# DEBUG:root:More debug data
# After:
# ERROR:root:Error log here

15 property



访问属性时,需要表现某种行为时用@property 

class T(object):

    def __init__(self):
        self._value = 5 

    @property                  # 最小惊讶原则
    def value(self):           # 列如
        print("Get value")     # getter里面不应该修改属性
        return self._value     # getter, setter 不应该做复杂或缓慢的操作

    @value.setter
    def value(self, value):
        print("Change value")
        self._value = value


t = T() 
print(t.value)
t.value = 10
print(t.value)

16 descriptor


当多个属性都需要表现同一种行为时, 用描述符

from weakref import WeakKeyDictionary


class Grade(object):

    def __init__(self):    
        self._values = WeakKeyDictionary() 

        # 用字典来记录每个实例的状态。
        # 为了避免实例引用计数无法降为0, 
        # 垃圾回收器无法回收,这里用弱引用字典。

    def __get__(self, instance, instance_type):
        if instance is None:
            return self
        return self._values.get(instance, 0)

    def __set__(self, instance, value):
        if not (0 <= value <= 100):
            raise ValueError("Grade must be between 0 and 100")
        self._values[instance] = value


class Exam(object):
    math = Grade()
    english = Grade()


exam = Exam()         
exam.math = 97        # Exam.__dict__['math'].__set__(exam, 40) 
exam.english = 89
print(exam.math)      # Exam.__dict__['math'].__get__(exam, Exam)
print(exam.english)
exam.english = 87
print(exam.english)

# 97
# 89
# 87

17 decorator


装饰器增强函数功能

不带参数的装饰器


def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Start")
        return func(*args, **kwargs)
    return wrapper


@log             # 相当于 t = log(t)
def t():
    print("End")


t()

# Start
# End

带参数的装饰器


def log(name):
    print(name)
        
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print("Start")
            return func(*args, **kwargs)
        return wrapper
    return decorator


@log("Tom")      # 相当于 t = log("Tom")(t)
def t():
    print("End")


t()

# Tom
# Start
# End

同时支持两种方式


from functools import wraps, partial

    
def debug(func=None, prefix=""):
    if func is None:
        return partial(debug, prefix=prefix)
    msg = prefix + func.__qualname__

    @wraps(func)
    def wrapper(*args, **kwargs):
        print(msg)
        return func(*args, **kwargs)
    return wrapper


@debug
def add(x, y):
    return x + y


print(add(3, 4))
# add
# 7


@debug(prefix="***")
def add(x, y):
    return x + y


print(add(3, 4))

# ***add
# 7

Class Decorator


如果类的实例方法都需要同一种装饰器, 用类装饰器


from functools import wraps, partial


def debug(func=None, prefix=""):
    if func is None:
        return partial(debug, prefix=prefix)
    msg = prefix + func.__qualname__

    @wraps(func)
    def wrapper(*args, **kwargs):
        print(msg)
        return func(*args, **kwargs)
    return wrapper


def debugmethods(cls):
    for name, val in vars(cls).items():
        if callable(val):
            setattr(cls, name, debug(val))
    return cls


class T(object):

    @debug
    def a(self):
        print('a')

    @debug
    def b(self):
        print('b')

    @classmethod    # Not wrapped
    def c(cls):
        print('c')
        
    @staticmethod   # Not wrapped
    def d():
        print('d')

    @classmethod    
    @debug
    def e(cls):
        print('c')
        
    @staticmethod   
    @debug
    def f():
        print('d')


t = T()
t.a()
t.b()
t.c()
t.d()
t.e()
t.f()



@debugmethods
class T(object):

    def a(self):
        print('a')

    def b(self):
        print('b')

    @classmethod    # Not wrapped
    def c(cls):
        print('c')
        
    @staticmethod   # Not wrapped
    def d():
        print('d')

        
t = T()
t.a()
t.b()
t.c()
t.d()

18 metaclass


如果子类的实例方法都需要同一种装饰器, 基类使用元类


from functools import wraps, partial


def debug(func=None, prefix=""):
    if func is None:
        return partial(debug, prefix=prefix)
    msg = prefix + func.__qualname__
        
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(msg)
        return func(*args, **kwargs)
    return wrapper
        
    
def debugmethods(cls):
    for name, val in vars(cls).items():
        if callable(val):
            setattr(cls, name, debug(val))
    return cls


@debugmethods
class Base(object):
    pass
 
 
@debugmethods
class Spam(Base):
    pass

    
@debugmethods
class Grok(Spam):
    pass


@debugmethods
class Mondo(Grok):
    pass


Solution: A Metaclass

class debugmeta(type):
    def __new__(cls, clsname, bases, clsdict):
        clsobj = super().__new__(cls, clsname, bases, clsdict)
        clsobj = debugmethods(clsobj)
        return clsobj
    

class Base(metaclass=debugmeta):
    pass


class Spam(Base):
    pass


class Grok(Spam):
    pass


class Mondo(Grok):

    def t(self):
        print('t')


m = Mondo()
m.t()

19 process

启动一个子进程


import os
from multiprocessing import Process


def t(name):
    print("Child process {0} {1}".format(os.getpid(), name))


if __name__ == "__main__":
    print("Parent process {0}".format(os.getpid()))
    p = Process(target=t, args=("test",))
    print("Child process will start")
    p.start()  # 启动子进程
    p.join()   # 等待子进程结束后再继续往下运行
    print("Child process end")

进程池


import os
import time
import random
from multiprocessing import Pool


def task(name):
    print("Run task {0}, {1}".format(name, os.getpid()))
    start = time.time()
    time.sleep(random.random()*3)
    end = time.time()
    print("Task {0} runs {1} seconds".format(name, (end - start)))


if __name__ == "__main__":
    print("Parent process {0}".format(os.getpid()))
    p = Pool()          # 进程池默认数量和电脑有关, 4核CPU,就是进程池默认是4
    for i in range(5):  # 测试的电脑4核CPU,这里起5个子进程,会有一个进程等待其它进程执行完后执行
        p.apply_async(task, args=(i,))
    print("Waiting for all subprocesses done...")
    p.close()  # close 后就不能继续添加新的Process了
    p.join()   # 等待子进程结束后再继续往下运行
    print("All subprocesses done")


# Parent process 19271
# Waiting for all subprocesses done...
# Run task 0, 19272
# Run task 1, 19273
# Run task 2, 19274
# Run task 3, 19275
# Task 1 runs 1.0092787742614746 seconds
# Run task 4, 19273
# Task 3 runs 1.3692305088043213 seconds
# Task 0 runs 1.4714231491088867 seconds
# Task 2 runs 1.9193198680877686 seconds
# Task 4 runs 1.993635892868042 seconds
# All subprocesses done

subprocess


import subprocess

p = subprocess.Popen(["echo", "Hi"], stdout=subprocess.PIPE)
out, error = p.communicate()
print(out.decode("utf-8"))

# Hi

20 thread

单个线程


from time import time


def factorize(num):
    for i in range(1, num+1):
        if num % i == 0:
            yield i


nums = [2139079, 1214759, 1516637, 1852285]
start = time()
for num in nums:
    list(factorize(num))
end = time()
print(end-start)


# 0.4892253875732422

多个线程


from time import time
from threading import Thread


class FactorizeThread(Thread):

    def __init__(self, num):
        super().__init__()
        self.num = num 

    def factorize(self, num):
        for i in range(1, num+1):
            if num % i == 0:
                yield i

    def run(self):
        self.factors = list(self.factorize(self.num))


nums = [2139079, 1214759, 1516637, 1852285]
start = time()
threads = []
for num in nums:
    thread = FactorizeThread(num)
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join()
end = time()
print(end-start)

# 0.4903602600097656   因为GIl的原因无法真正并行计算

单线程处理阻塞式IO


from time import time
from select import select


def slow():
    select([], [], [], 0.1)


start = time()
for _ in range(5):
    slow()
end = time()
print(end-start)

# 0.5008544921875

多线程处理阻塞式IO


from time import time
from select import select
from threading import Thread

    
def slow():
    select([], [], [], 0.1)


start = time()
threads = []
for _ in range(5):
    thread = Thread(target=slow)
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join()
end = time()
print(end-start)

# 0.10056090354919434   处理阻塞式IO速度快5倍
# Python 还有内置的 asyncio 模块来处理阻塞式IO

多线程之间数据竞争


from threading import Thread


num = 0


def buy():
    global num
    for i in range(1000000):
        num += 1
        
        
threads = []
for _ in range(2):
    thread = Thread(target=buy)
    threads.append(thread)
    thread.start()
    
for thread in threads:
    thread.join()
print(num)

# 1351674  期望是 2000000 

多线程用Lock避免数据竞争


from threading import Thread
from threading import Lock


num = 0 
lock = Lock()


def buy():
    global num 
    for i in range(1000000):
        with lock:
            num += 1


threads = []
for _ in range(2):
    thread = Thread(target=buy)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()
print(num)


# 2000000

21 queue

在获取端阻塞


from queue import Queue
from threading import Thread

queue = Queue()


def consumer():
    print("Consumer waiting")
    queue.get()                # 会阻塞等待put()
    print("Consumer done")


thread = Thread(target=consumer)
thread.start()
print("Producer putting")
queue.put(object())
thread.join()
print("Producer Done")


# Consumer waiting
# Producer putting
# Consumer done
# Producer Done

在添加端阻塞


from queue import Queue
from threading import Thread
import time

queue = Queue(1)  # 这里把缓冲区设为1, 
                  # 意味着第一个put后,如果没有被消耗
                  # 会阻塞在第二个put那里

def consumer():
    time.sleep(0.1)  # 在get前,率先put, 然后阻塞在第二个put上
    queue.get()
    print("Consumer got 1")
    queue.get()
    print("Consumer got 2")


thread = Thread(target=consumer)
thread.start()
queue.put(object())
print("Producer put 1")
queue.put(object())
print("Producer put 2")
thread.join()
print("Producer done")

# Producer put 1
# Consumer got 1
# Producer put 2
# Consumer got 2
# Producer done

追踪工作进度


from queue import Queue
from threading import Thread

queue = Queue()


def consumer():
    print("Consumer waiting")
    queue.get()
    print("Consumer done")
    queue.task_done()


Thread(target=consumer).start()  # 线程不需要调用join方法
queue.put(object())
print("Producer waitting")
queue.join()                     # queue 调用join,等待结束即可
print("Producer done")

# Consumer waiting
# Producer waitting
# Consumer done
# Producer done

22 coroutine


def consumer():
    result = 9
    while True:
        result = yield result
c = consumer()
print(c.send(None))           # 启动生成器
print(c.send(1))              # 传值给生成器
print(c.send(2))
c.close()                     # 结束生成器

# 9
# 1
# 2

23 asyncio



asyncioPython 3.4版本引入的标准库,

直接内置了对异步IO的支持。

import asyncio
  
  
@asyncio.coroutine
def hello(n):
    print("Hello world!")
    r = yield from asyncio.sleep(n)
    print("Hello again!")
    

loop = asyncio.get_event_loop()
tasks = [hello(5), hello(2)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()


Python 3.5开始引入了新的语法asyncawait

import asyncio
  
  
async def hello(n):
    print("Hello world!")
    r = await asyncio.sleep(n)
    print("Hello again!")


loop = asyncio.get_event_loop()
tasks = [hello(5), hello(2)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

Algorithm

1 冒泡


时间复杂度 n^2

nums = [5, 3, 10, 23, 12]

for i in range(len(nums)):
    for j in range(i):
        if nums[i] < nums[j]:
            nums[i], nums[j] = nums[j], nums[i]
print(nums)

# [3, 5, 10, 12, 23]

2 快排



理想时间复杂度logN,但可能出现最坏情况n^2,

可以通过随机化数据,避免最坏的情况。

空间复杂度 1

nums = [5, 3, 10, 23, 12]


def move(nums, low, high):
    i, j = low, low+1
    while j <= high:
        if nums[j] < nums[low]:
            i += 1 
            nums[i], nums[j] = nums[j], nums[i]
        j += 1 
    nums[low], nums[i] = nums[i], nums[low]
    return i


def quick_sort(nums, low, high):
    if low < high:
        index = move(nums, low, high)
        quick_sort(nums, low, index-1)
        quick_sort(nums, index+1, high)


quick_sort(nums, 0, len(nums)-1)
print(nums)

# [3, 5, 10, 12, 23]

3 堆排



时间复杂度 logN

空间复杂度 1

nums = [5, 3, 10, 23, 12]


def flow_up(nums, start, end):
    root = start
    while True:
        child = 2*root + 1
        if child > end: 
            break
        if child+1 <= end and nums[child] < nums[child+1]:
            child = child+1
        if nums[root] < nums[child]:
            nums[root], nums[child] = nums[child], nums[root]
            root = child
        else:
            break


def heap_sort(nums):
    for start in range((len(nums)-2)//2, -1, -1): 
        flow_up(nums, start, len(nums)-1)

    for end in range(len(nums)-1, 0, -1): 
        nums[end], nums[0] = nums[0], nums[end]
        flow_up(nums, 0, end-1)


heap_sort(nums)
print(nums)

4 并排



时间复杂度 logN

空间复杂度 n

nums = [5, 3, 10, 23, 12]
            
            
def merge(left, right):
    i, j = 0, 0
    result = []
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result += left[i:]
    result += right[j:]
    return result


def binary(nums):
    if len(nums) <= 1:
        return nums
    else:
        index = len(nums)//2
        left = binary(nums[:index])
        right = binary(nums[index:])
        return merge(left, right)


print(binary(nums))

5 斐波纳挈


def fib(n):
    a, b = 1, 0
    i = 0
    while i < n:
        print(a)
        a, b = a+b, a
        i += 1


fib(4)

6 链表成对调换


class Node(object):

    def __init__(self, value=None, node=None):
        self.value = value
        self.next = node
        
    
root = Node(1, Node(2, Node(3, Node(4))))

        
def swap(node):
    if node and node.next:
        next_node = node.next
        node.next = swap(next_node.next)
        next_node.next = node
        return next_node 
    return node
    

new_root = swap(root)


def display(node):
    if node:
        print(node.value)
    if node and node.next:
        display(node.next)


display(new_root)

7 单链表逆置


class Node(object):

    def __init__(self, value=None, node=None):
        self.value = value
        self.next = node
    
        
root = Node(1, Node(2, Node(3, Node(4))))
        
        
def reverse(node):
    if node:
        pre = node
        cur = node.next
        pre.next = None
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre
    else:
        return node
    
        
new_root = reverse(root)
        

def display(node):
    if node:
        print(node.value)
    if node and node.next:
        display(node.next)


display(new_root)

8 二叉树


class Node(object):

    def __init__(self, value=None, left=None, right=None):
        self.left = left
        self.right = right
        self.value = value
        
        
root = Node(2, Node(1), Node(5))


def display(node):
    if node and node.left:
        display(node.left)
    if node and node.value:
        print(node.value)
    if node and node.right:
        display(node.right)
        

display(root)

Mysql

MyISAM


适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好

甚至你只是需要update一个字段,整个表都会被锁起来,

而别的进程,就算是读进程都无法操作直到读操作完成

对于 SELECT COUNT(*) 这类的计算是超快无比的

InnoDB


是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢

他是它支持“行锁” ,于是在写操作比较多的时候,会更优秀

InnoDB要求表必须有主键(MyISAM可以没有)

不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,

过长的主索引会令辅助索引变得过大

常用命令


SELECT * FROM table_name

SELECT column1,column2 FROM table_name

INSERT INTO table_name VALUES (1,2,...)

INSERT INTO table_name ( 1,2)  VALUES ( 1,2)

UPDATE table_name SET column = new_value WHERE 条件

DELETE FROM table_name WHERE 条件

Linux

常用命令


ps aux | grep  uwsgi

可以看出主进程

ps -ef | grep uwsgi

Other