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)  # 这里相当于是重新赋值了name和age,之后的name age都是这个值
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 Singleton._initialized:
            self.name = name
            self.age = age
            Singleton._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})

 

posted @ 2019-02-26 15:51  我用python写Bug  阅读(1093)  评论(0编辑  收藏  举报