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)
posted @ 2019-03-15 09:31  咕噜噜~  阅读(498)  评论(0编辑  收藏  举报