一、单例模式
1、常用的单例模块
class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance s1 = Singleton() s2 = Singleton() print(s1 is s2) # True
2、属性共用的单例
""" 上面的第一种写法,虽然创建的是同一个实例, 但是属性是不共用的,因为每次__init__都会重新设置 """ class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance def __init__(self, name, age): self.name = name self.age = age s1 = Singleton(name="小明", age=18) print(s1.name, s1.age) # 小明 18 s2 = Singleton(name="小红", age=17) print(s2.name, s2.age) # 小红 17 print(s1 is s2) # True """ 因此想要属性也共用,__init__也需要处理 """ class Singleton(object): _instance = None _initialized = False def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance def __init__(self, name, age): if not self._initialized: self.name = name self.age = age self._initialized = True s1 = Singleton(name="小明", age=18) print(s1.name, s1.age) # 小明 18 s2 = Singleton(name="小红", age=17) print(s2.name, s2.age) # 小明 18 print(s1 is s2) # True
3、加锁的单例
import time import threading class Singleton(object): lock = threading.RLock() # 定义一把锁 _instance = None def __new__(cls, *args, **kwargs): if cls._instance: return cls._instance # 如果之前实例化过,没必要再次实例化,因为都是同一个实例 with cls.lock: # 避免当线程没有返回实例前,另一个线程也进来了,导致出现不止一个实例 if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance def task(arg): obj = Singleton() print(obj) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() time.sleep(10) obj = Singleton()
4、单例装饰器
def singleton(cls): _instance = {} def _singleton(*args, **kwargs): if cls not in _instance: _instance[cls] = cls(*args, **kwargs) return _instance[cls] return _singleton @singleton class A(): def __init__(self, name): self.name = name a1 = A("ming") print(a1.name) # ming a2 = A("dong") print(a2.name) # ming
二、栈
1、自定义一个栈
# 栈是后进先出的数据结构,但是python中并没有栈这种数据结构,因此我们自己实现 class Stack(object): def __init__(self): self.MyStack = [] def push(self, value): """ 向栈插入数据 :param value: :return: """ self.MyStack.append(value) def pop(self): """ 从栈中取走数据 :return: """ return self.MyStack.pop() stack = Stack() stack.push(1) stack.push(2) print(stack.pop()) # 2
2、python中的栈
后进先出(栈) from queue import LifoQueue lq = LifoQueue() lq.put(1) lq.put(2) lq.put(3) print(lq.get()) # 3 print(lq.get()) # 2 print(lq.get()) # 1
三、队列
1、python默认的队列
# 队列(queue)是一种具有先进先出特征的线性数据结构,元素的增加只能在一端进行,元素的删除只能在另一端进行。能够增加元素的队列一端称为队尾,可以删除元素的队列一端则称为队首 import queue q = queue.Queue() # 队列对象 q.put(1) # 往队列存元素 q.put(2) q.put('a') q.put([1,2,3]) print(q.get()) # 1 取元素 print(q.get()) # 2 print(q.get()) # a
2、双端队列(双端列表)
# list的缺点:list在插入元素(insert)的时候是非常慢的,因为你插入一个元素,那么此元素后面的所有元素索引都得改变, # 当数据量很大的时候,那么速度就很慢了。 # 双端队列:可以弥补List的这个缺点 # 双端队列:deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。 from collections import deque dq = deque([1,2,3]) dq.append(4) dq.append(5) dq.appendleft(6) print(dq) # deque([6, 1, 2, 3, 4, 5]) print(dq.pop()) # 5 print(dq.popleft()) # 6
四、有序字典
python3.6之前,字典的Key是无序的(3.6之后字典默认有序,无需用此方法,但是很多公司未必都是在用3.6的版本), 在对dict做迭代时,我们无法确定Key的顺序,如果要保持Key的顺序,可以用OrderedDict。
首先说明一下普通字典的创建,可以使用面向对象的方式创建
# 普通字典的创建方式 dic1 = dict({'a':1,'b':2}) # 括号里面直接写字典 dic2 = dict([('c',3),('d',4)]) # 括号里面写列表,列表每一个元素是二元组,每个元组是字典的键和值 print(dic1) # {'a': 1, 'b': 2} print(dic2) # {'c': 3, 'd': 4}
有序字典的创建
from collections import OrderedDict order_dic = OrderedDict([('a', 1), ('b', 2)]) # 也可以这样创建 order_dic2 = OrderedDict({'c': 3, 'd': 4}) print(order_dic) # OrderedDict([('a', 1), ('b', 2)]) print(order_dic2) # OrderedDict([('c', 3), ('d', 4)]) order_dic['小明'] = '嘿嘿嘿' print(order_dic) # OrderedDict([('a', 1), ('b', 2), ('小明', '嘿嘿嘿')])
五、其他
1、namedtuple:可命名元组
from collections import namedtuple time = namedtuple('My_time', ['hour', 'minute', 'second']) t1 = time(17, 50, 30) print(t1) # My_time(hour=17, minute=50, second=30) print(t1.hour) # 17 print(t1.minute) # 50 print(t1.second) # 30 # 可命名元组非常类似一个只有属性没有方法的类, # 这个类最大的特点就是一旦实例化不能修改属性的值, # 可命名元组不能用索引取值了,只能用属性取值, # ['hour', 'minute', 'second']是对象属性名, # My_time是类的名字,而time就相当于把一个类赋值给一个变量(变量复用地址而已,实际上还是那个类)
2、defaultdict:为字典设置默认值
from collections import defaultdict dic = defaultdict(list) # 为字典设置默认值为空列表(defaultdict里面的参数必须是可调用的) # dic = defaultdict(1) # 报错,因为数字 1 不可调用 print(dic['a']) # [] dic['b'].append(2) print(dic['b']) # [2] # 可与匿名函数结合使用,设置任何默认值 dic = defaultdict(lambda: 'none') # lambda返回什么值都可以 print(dic['a']) # none print(dic) # {'a': 'none'} dic['b'] = 2 print(dic) # {'a': 'none', 'b': 2} # 例子:有如下值集合 [11,22,33,44,55,66,77,88,99,90],将所有大于 66 的值保存至字典的第一个key中, # 将小于 66 的值保存至第二个key的值中。 # 即: {'k1': 大于66 , 'k2': 小于66} # 1、用正常的字典做 lst = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90] dic = {} for num in lst: if num > 66: if 'k1' not in dic: dic['k1'] = [num] else: dic['k1'].append(num) elif num < 66: if 'k2' not in dic: dic['k2'] = [num] else: dic['k2'].append(num) print(dic) # 2、使用字典的默认值 from collections import defaultdict lst = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90] dic = defaultdict(list) for num in lst: if num > 66: dic['k1'].append(num) elif num < 66: dic['k2'].append(num) print(dic)
3、Counter
# Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储, # 其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。 from collections import Counter c = Counter('aaasasabssbba') print(c) # Counter({'a': 6, 's': 4, 'b': 3})