zoukankan      html  css  js  c++  java
  • 4.1 python类的特殊成员,偏函数,线程安全,栈,flask上下文

    一. Python 类的特殊成员(部分)

    class MyClass(object):
        def __call__(self, *args, **kwargs):
            print(f'__call__ -- args:{args}')
    
        def __setattr__(self, key, value):
            print(f'__setattr__ -- key:{key} value:{value}')
    
        def __getattr__(self, item):
            print(f'__getattr__ -- item:{item}')
    
        def __setitem__(self, key, value):
            print(f'__setitem__ -- key:{key} value:{value}')
    
        def __getitem__(self, item):
            print(f'__getitem__ -- item:{item}')
    
    
    my_class = MyClass()
    
    my_class(1, 2, 3)  				# 执行__call__
    my_class.age = 41  				# 执行__setattr__
    res1 = my_class.age  			# 执行__getattr__
    my_class['王力宏'] = '王二哥'		# 执行__setitem__
    res2 = my_class['王力宏']		  # 执行__getitem__
    
    # 以上代码执行结果:
    __call__ -- args:(1, 2, 3)
    __setattr__ -- key:age value:41
    __getattr__ -- item:age
    __setitem__ -- key:王力宏 value:王二哥
    __getitem__ -- item:王力宏
    

    二. Python偏函数

    Python 偏函数是通过 functools 模块被用户调用。

    1. 描述

    函数在执行时,要带上所有必要的参数进行调用。但是,有时参数可以在函数被调用之前提前获知。这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调用。

    偏函数是将所要承载的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数后续的参数,除非使用关键字参数。

    通过语言描述可能无法理解偏函数是怎么使用的,那么就举几个常见的例子来说明。

    2. 实例一: 取余函数

    取余函数,对于整数 100,取得对于不同数 m 的 100%m 的余数。

    from functools import partial
    
    def mod(n, m):
        return n % m
    
    mod_by_100 = partial(mod, 100)
    
    print(mod(100, 7))		# 2
    print(mod_by_100(7))	# 2
    

    3. 实例二: 求三个数的和

    from functools import partial
    
    
    def add(a, b, c):
        print(a, b, c)
        return a + b + c
    
    
    par_add = partial(add, 1, 2)
    print(par_add(3))
    
    par_add2 = partial(add, 1)
    print(par_add2(5, 7))
    
    # 执行结果:
    1 2 3
    6
    1 5 7
    13
    

    三. 线程安全

    1. 实例一: 无线程,消耗时间过长

    import time
    
    class Foo(object):
        pass
    
    foo = Foo()
    
    def add(i):
        foo.num = i
        time.sleep(1)
        print(foo.num)
    
    for i in range(10):
        add(i)
    
    # 执行结果: 每秒打印出一个数字,总共耗时10秒
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    

    2. 实例二: 开启线程,节省了时间,但数据不安全

    import time
    import threading
    
    class Foo(object):
        pass
    
    foo = Foo()
    
    def add(i):
        foo.num = i
        time.sleep(1)
        print(foo.num, i)
    
    for i in range(20):
        th = threading.Thread(target=add, args=(i,))
        th.start()
    
    # 执行结果: 几乎在1秒的时间打印出了全部结果
    19 4
    19 2
    19 1
    19 3
    19 0
    19 14
    19 13
    19 11
    19 10
    19 9
    19 7
    19 5
    19 16
    19 8
    19 15
    19 19
    19 18
    19 17
    19 6
    19 12
    

    3. 实例三: 使用local, 以空间换时间, 保证了数据安全

    import time
    import threading
    from threading import local
    
    class Foo(local):  # 继承local
        pass
    
    foo = Foo()
    
    def add(i):
        foo.num = i
        time.sleep(1)
        print(foo.num, i, threading.current_thread().ident)
    
    for i in range(20):
        th = threading.Thread(target=add, args=(i,))
        th.start()
    
    # 执行结果: 以空间换时间,浪费了部分资源,保证了执行效率和数据安全
    8 8 7760
    11 11 1856
    9 9 836
    7 7 10612
    5 5 1148
    4 4 12124
    2 2 6040
    19 19 12652
    6 6 8288
    3 3 6552
    18 18 10232
    17 17 12668
    15 15 9348
    13 13 13132
    10 10 7948
    1 1 7404
    16 16 13200
    12 12 9440
    0 0 7880
    14 14 7616
    

    4. Flask上下文机制

    # 总结: threading.local
    Flask上下文机制就是使用的 threading.local,这个技术不算很牛逼,但是概念很重要:
    线程进来,开辟一个空间给这个线程,线程操作的所有任务,都会复制一份到该空间中.
    

    四. 栈Stack

    栈遵循 后进先出(Last In First Out) 原则.

    # 栈Stack: 遵循 后进先出(Last In First Out) 的原则
    
    class Stack(object):
        data = []
    
        def __setattr__(self, key, value):
            self.push(key, value)
    
        def push(self, key, value):
            self.data.append({key: value})
    
        def pop(self):
            return self.data.pop()
    
    
    stack = Stack()
    
    stack.name = '666'
    stack.name = '777'
    stack.name = '888'
    
    print(stack.data)
    
    print(stack.pop(), stack.data)
    print(stack.pop(), stack.data)
    print(stack.pop(), stack.data)
    
    # 执行结果:
    [{'name': '666'}, {'name': '777'}, {'name': '888'}]
    {'name': '888'} [{'name': '666'}, {'name': '777'}]
    {'name': '777'} [{'name': '666'}]
    {'name': '666'} []
    

    五. LocalStack

    from threading import get_ident  # get_ident()可以获取到当前线程id
    import threading
    import time
    
    
    class MyLocalStack(object):
        storage = {}  # 结构: {key1: [el1], key2: [el2]}
    
        def push(self, item):
            try:
                self.storage[get_ident()].append(item)
            except:
                self.storage[get_ident()] = [item]
    
        def pop(self):
            return self.storage[get_ident()].pop()
    
    
    my_local_stack = MyLocalStack()
    
    
    def run(i):
        my_local_stack.push(i)
        time.sleep(1)
    
    
    for i in range(5):
        th = threading.Thread(target=run, args=(i,))
        th.start()
    
    print(my_local_stack.storage)
    
  • 相关阅读:
    day84
    模型层之单表操作
    Django的模板层
    Django框架导读
    创建Django项目
    名称空间2.0path
    js基础之BOM和DOM
    LG5003 跳舞的线
    20191003 「HZOJ NOIP2019 Round #8」20191003模拟
    LG3092 「USACO2013NOV」No Change 状压DP
  • 原文地址:https://www.cnblogs.com/haitaoli/p/10535019.html
Copyright © 2011-2022 走看看