HoneyTian's picture
update
80bf15d
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import inspect
class ParamsSingleton(object):
"""根据传入的参数不同而创建单例.
由于参数中可能包含字典, 如果转字符串的话, 字典的 key 是无序的.
所以用了列表而不是字典来存实例. """
__instance = list()
_initialized = False
def __new__(cls, *args, **kwargs):
kwargs = cls.to_kwargs(*args, **kwargs)
kwargs['cls'] = cls
for obj, params in cls.__instance:
if params == kwargs:
return obj
obj = super().__new__(cls)
# 让每个类实例, 可以拿到自己的 kwargs
# setattr(obj, 'kwargs', kwargs)
obj.kwargs = kwargs
cls.__instance.append((obj, kwargs))
return obj
@classmethod
def get_all_instance(cls) -> list:
return cls.__instance
@classmethod
def to_kwargs(cls, *args, **kwargs):
"""将传入 __init__ 的参数全部转为 key-value 字典的关键字参数"""
# 获取当前传入参数值.
argvalues = inspect.getargvalues(inspect.currentframe())
args = list(argvalues.locals['args'])
kwargs = argvalues.locals['kwargs']
for k, v in argvalues.locals.items():
if k in ('cls', 'args', 'kwargs'):
continue
else:
kwargs[k] = v
# 获取函数接受哪些参数.
fullargspec = inspect.getfullargspec(cls.__init__)
# 函数的参数分为已知的位置参数, 未知的位置参数, 已知的关键字参数, 未知的关键字参数.
# 在 `未知的位置参数` 之前的参数都是 `已知的位置参数`. 它们可能有默认值
# 有默认值的参数并不都是关键字参数. 关键字参数也可以没有默认值.
# fullargspec.args: `已知的位置参数` 的名称的列表.
# fullargspec.defaults: 元组或None. `已知的位置参数` 中最后几项的默认值.
# fullargspec.kwonlyargs: `已知的关键字参数` 的名称列表 (没有默认值的关键字参数, 是必须要传入的).
# fullargspec.kwonlydefaults: `已知的关键字参数` 的默认值.
arg_name_list = fullargspec.args
# 将未被赋值 `已知的位置参数` 的默认值写入 kwargs.
if fullargspec.defaults is not None:
l = len(fullargspec.defaults)
default_args = fullargspec.args[-l:]
for k, v in zip(default_args, fullargspec.defaults):
if k in kwargs:
continue
else:
kwargs[k] = v
# 将 `已知关键字参数` 的默认值写入 kwargs.
if fullargspec.kwonlydefaults is not None:
for k, v in fullargspec.kwonlydefaults.items():
if k in kwargs:
continue
else:
kwargs[k] = v
# if fullargspec.kwonlyargs is not None:
# arg_name_list.extend(fullargspec.kwonlyargs)
kwargs = dict()
for arg_name in arg_name_list:
if arg_name == 'self':
continue
try:
value = args.pop(0)
except IndexError:
break
kwargs[arg_name] = value
if fullargspec.varargs is not None:
kwargs[fullargspec.varargs] = tuple(args)
return kwargs
@classmethod
def flush(cls):
cls.__instance = list()
return
def demo1():
class A(ParamsSingleton):
pass
class B(A):
# def __init__(self, name, *args1, age, **kwargs):
def __init__(self, name, age=27, **kwargs):
pass
b1 = B('jack')
print('-' * 25)
# b2 = B('jack', 1, 2, age=25, **{'high': 165})
# print('-' * 25)
b3 = B(name='jack', **{'age': 25, 'high': 165})
# b3 = B(name='jack', **{'high': 165})
print('-' * 25)
# print(b1)
return
if __name__ == '__main__':
demo1()