• python之单例模式、栈、队列和有序字典


    一、单例模式

    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})
  • 相关阅读:
    Java并发之synchronized关键字和Lock接口
    Java并发之volatile关键字
    浏览器的缓存机制
    垃圾回收技术
    import和require区别
    垃圾回收机制
    TCP四次挥手
    进程
    TCP基础概念
    TCP三次握手
  • 原文地址:https://www.cnblogs.com/Zzbj/p/10437873.html
Copyright © 2020-2023  润新知