1 解析json串

需求: 给出一个字串, 例如字符串

1
str1 = {"name": "liu", "age": "3", "sex": 0, "educations": [{"school": "A", "location": "HANGZHOU"}]}

如何编写一个函数转换为json格式的输出? 得到类似json.dumps(str1, indent=2)的输出格式.

2 单例

2.1 使用场景

问题: 单例模式是什么? 单例模式的使用场景或者优势在哪里?
使用场景:

  • 提供一个全局的访问,且只要求一个实例,如应用的配置信息
  • 创建一个对象比较耗费资源,如数据库连接管理、文件管理、日志管理等
  • 资源共享,如线程池
  • 工具类对象(也可以直接使用静态常量或者静态方法)
  • 要求一个类只能产生两三个实例对象,比如某些场景下,会要求两个版本的网络库实例,如公司内网和外网的网络库实例

要求:

  • 延时加载或者懒加载
  • 线程安全
  • 防止反射破坏

其他:

  • 饿汉模式: 在类初始化时, 执行静态代码以及初始化静态域来完成实例的创建, 例如python的模块导入, 由JVM/Python虚拟机来确保线程安全
  • 懒汉模式: 在调用getInstance()时才会去实例化类, 但是并非线程安全
  • 懒汉模式-线程安全: 在实例化时, 增加同步锁机制
  • 反射破坏: 利用反射机制去访问单例类的私有构造方法来进行实例化

装饰器在python中的实现

  • 使用模块, 一个模块本身就是一个单例(基于解释器)
  • __new__控制类的初始化
  • metaclass元类来控制类的创建: 拦截类, 修改类定义, 返回类

2.2 实现方式

方式1, 利用wraps来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 使用__new__来实现单例
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance

# 使用wraps来装饰某一个类
from functools import wraps
def singleton(cls):
instances = {}
@wraps(cls)
def getinstance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances
return getinstance

@singleton
class A(object):
a = 1

方式 2, 利用__meta__:

1
2
3
4
5
6
7
8
9
10
# metaclass控制类的创建
class Singleton(object):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in _instances:
_instances[cls] = cls(*args, **kwargs)
return _instances[cls]

class B(object):
__metaclass__ = Singleton

3 AOP

AOP-Aspect Oriented Programming, 面向切面编程, 在不影响原有功能的前提下, 为软件
提供横向扩展功能, 即通过 AOP是的某一个功能能够作用于某一个横向模块的所有方法中.
AOP是 OOP 的补充, 在如下使用场景中:

  • 日志记录
  • 操作记录
  • 参数校验和判断空
  • 无痕埋点
  • 安全控制, 比如全局登录控制, 参数校验控制等
  • 性能统计
  • 异常处理
  • 缓存
  • 软件破解, 比如利用hook来修改软件验证逻辑

这些场景中存在大量公共引用行为, 产生大量的冗余代码, 特别是 JAVA/C++这些语言中,就算是python
中, 也是此类冗余情景, 此时使用 AOP 就能完美解决问题. 关于代码冗余问题, 我们先简单谈下目前的
解决方案以及各种优缺点:

  • 硬代码编写, 这会导致大量的代码重复, 极强耦合
  • 抽离复用或者类继承, 这也会导致强耦合, 特别是 JAVA/C++编译型语言
  • AOP, 横向抽离, 低耦合

另外, 关于装饰器设计模式见 GOF 结构模型, 115 页. 后续研究下该模式是否跟 Python/JAVA 语法糖
的设计相关.

4 Decorator

4.1 定义

装饰器是什么? 使用场景都有哪些? 如何编写一个装饰器?多个装饰器之间顺序是怎样的?
其他知识点:

  • 嵌套函数: 装饰器实现的基础
  • 万物皆对象: 在函数中返回函数, 将函数作为参数传入另外一个函数, 这是python装饰器容易实现的一点

对于多个装饰器, 采用从外到内的调用逻辑.

4.2 简单装饰器

首先, 让我们一步步的讲解装饰器的变化历史, 下面是一个简单的装饰器例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import logging

def my_log(func):
""" 返回一个在函数内部执行传入函数的函数对象 """
def wrapper():
logging.warnning('{} is running'.format(func.__name__))
return func()
return wrapper # 注意这里返回函数对象本身, 并非内部的直接执行.

def wa():
print("WAAAA")

true_wa = my_log(wa)
true_wa()

此时执行true_wa函数的时候回执行wrapper()函数, 在真正执行wa()之前执行日志打印.
在这个例子中, 在层面函数进入, 函数退出中, 都有一个统一的日志打印函数, 这就是
第二章讲过的 AOP–面向切面编程.

其次, 在大部分语言中都存在语法糖的用法, @就是python装饰器语法糖用法, 利用语法糖, 上面的
简单装饰器用法可以变为如下:

1
2
3
4
5
@my_log
def wa():
print("WAAA")

wa()

再次, 不仅可以给函数对象添加装饰器, 还可以实现类装饰器, 不过要求类装饰器实现__call__方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Foo(object):
def __init__(self, func):
self._func = func

def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')

@Foo
def bar():
print ('bar')

bar()

最后, 让我们简单了解下带参数装饰器的使用说明.

1
2
3
4
5
6
7
8
9
10
11
12
13
@decorator(x, y, z)
def func(a, b):
pass

# 上面的装饰器等价于下面
def decorator(x, y, z):
def d(func):
return func
return d
def func(a, b):
pass
func = decorator(x, y, z)(func)
func(a, b)

4.3 wraps装饰器

可以使用functools来更加方便的实现装饰器.

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
# 1.授权: 检查是否有权限访问某些端点
from functools import wraps
def require_auth(func):
@wraps(func)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return func(*args, **kwargs)
return decorated

# 2. 带参数装饰器, API参数校验
def check_params(service_name, api_name):
def decorator(func):
@wraps(func)
def decorated_function():
try:
rsp, status = func(body_data)
except Exception, msg:
print("Exception")
finally:
print("Nothing")
return rsp, status
return decorated_function
return decorator

# 装饰类方法
def catch_exc(func):
def wrapper(self, *args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as msg:
traceback.print_exc()
return wrapper
class Test(object):
def __init__(self):
pass
@catch_exc
def main(self):
print("Main")

上面带参数的装饰器中. @check_params(s, b)实际上就相当于@decorator, 具体见 4.2 节.