站内链接:
解析 json 串
需求: 给出一个字串, 例如字符串
1
| str1 = {"name": "liu", "age": "3", "sex": 0, "educations": [{"school": "A", "location": "HANGZHOU"}]}
|
如何编写一个函数转换为 json 格式的输出? 得到类似json.dumps(str1, indent=2)
的输出格式.
单例
使用场景
问题: 单例模式是什么? 单例模式的使用场景或者优势在哪里?
使用场景:
- 提供一个全局的访问,且只要求一个实例,如应用的配置信息
- 创建一个对象比较耗费资源,如数据库连接管理、文件管理、日志管理等
- 资源共享,如线程池
- 工具类对象(也可以直接使用静态常量或者静态方法)
- 要求一个类只能产生两三个实例对象,比如某些场景下,会要求两个版本的网络库实例,如公司内网和外网的网络库实例
要求:
其他:
- 饿汉模式: 在类初始化时, 执行静态代码以及初始化静态域来完成实例的创建, 例如 python 的模块导入, 由 JVM/Python 虚拟机来确保线程安全
- 懒汉模式: 在调用 getInstance()时才会去实例化类, 但是并非
线程安全
- 懒汉模式-线程安全: 在实例化时, 增加
同步锁
机制
- 反射破坏: 利用反射机制去访问
单例类
的私有构造方法来进行实例化
装饰器在 python 中的实现
- 使用模块, 一个模块本身就是一个单例(基于解释器)
__new__
控制类的初始化
- metaclass 元类来控制类的创建: 拦截类, 修改类定义, 返回类
实现方式
方式 1, 利用 wraps 来实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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
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
| 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
|
AOP
AOP-Aspect Oriented Programming, 面向切面编程, 在不影响原有功能的前提下, 为软件提供横向扩展
功能, 即通过 AOP 是的某一个功能能够作用于某一个横向模块的所有方法中. AOP 是 OOP 的补充, 在如下使用场景中:
- 日志记录
- 操作记录
- 参数校验和判断空
- 无痕埋点
- 安全控制, 比如全局登录控制, 参数校验控制等
- 性能统计
- 异常处理
- 缓存
- 软件破解, 比如利用 hook 来修改软件验证逻辑
这些场景中存在大量公共引用行为, 产生大量的冗余代码, 特别是 JAVA/C++这些语言中,就算是 python 中, 也是此类冗余情景, 此时使用 AOP 就能完美解决问题. 关于代码冗余问题, 我们先简单谈下目前的解决方案以及各种优缺点:
- 硬代码编写, 这会导致大量的代码重复, 极强耦合
- 抽离复用或者类继承, 这也会导致强耦合, 特别是 JAVA/C++编译型语言
- AOP, 横向抽离, 低耦合
另外, 关于装饰器设计模式
见 GOF 结构模型, 115 页. 后续研究下该模式是否跟 Python/JAVA 语法糖的设计相关.
Decorator
定义
装饰器是什么? 使用场景都有哪些? 如何编写一个装饰器?多个装饰器之间顺序是怎样的? 其他知识点:
- 嵌套函数: 装饰器实现的基础
- 万物皆对象: 在函数中返回函数, 将函数作为参数传入另外一个函数, 这是 python 装饰器容易实现的一点
对于多个装饰器, 采用从外到内
的调用逻辑.
简单装饰器
首先, 让我们一步步的讲解装饰器的变化历史, 下面是一个简单的装饰器例子:
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)
|
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
| 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
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 节.