请问通过 dict.get(xxxx,'None')这种操作获得字典中的数据的时候,为什么会出现时有时无的情况? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
danzzzz
V2EX    Python

请问通过 dict.get(xxxx,'None')这种操作获得字典中的数据的时候,为什么会出现时有时无的情况?

  •  
  •   danzzzz 2018-10-25 13:12:51 +08:00 3904 次点击
    这是一个创建于 2543 天前的主题,其中的信息可能已经有所发展或是发生改变。

    就是我一开始定义了一个 session = {},紧接着通过 session['a'] = 1 的方式给字典赋值, 然后在 get 的过程中,出现了有时候拿到了数据,有时候返回 None 的情况,不得其解。 麻烦大家了,先感谢各位的解答。

    第 1 条附言    2018-10-25 15:28:42 +08:00
    global session
    session = {}

    class Todolist(Resource):
    #用户进入页面后将该用户所有的待办事项返回给前端渲染到页面
    def get(self,rdSession):
    global session
    openid = session.get(rdSession,None) #通过前端发送过来的随机串 key 得到对应的 value
    user = User.query.filter_by(open_id=openid).first()
    if user is None:
    return jsonify({'err':'This user_id is not in the user_table!'})
    pass

    #增
    def post(self,rdSession):
    '''
    获取用户的 open_id 的目的是在添加事项的时候给事项记录加上 user_id,
    因为 To_do_list 表中的 user_id 是 User 表的外键,
    这样才能实现通过 user.to_do_lists 来获取用户对应的所有待办事项。
    '''
    global session
    openid = session.get(rdSession,None)
    user = User.query.filter_by(open_id=openid).first()
    if user is None:
    return jsonify({'err':'This user_id is not in the user_table!'})
    pass

    #前端扫码向服务器发送临时 code
    class Session3d(Resource):
    def get(self):
    global session
    appid = 'xxxxxx'
    secrect = 'xxxxxxxxxxx'
    js_code = request.args.get('code',None)
    if js_code is not None:
    url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appid + '&secret=' + secrect + '&js_code=' + js_code + '&grant_type=authorization_code'
    r = requests.get(url)
    json_data = r.json()
    openid = json_data.get('openid')

    tupl = get_3rd_session(openid) #对 openid 进行加密
    rdSession = tupl[1].decode() #得到加密后的随机串

    user = User(open_id=openid)
    db.session.add(user)
    db.session.commit()
    session[rdSession] = openid #将随机串和 openid 作为键值对存进 session
    return jsonify(rdSession=rdSession) #返回随机串给前端
    return jsonify({})

    api.add_resource(Todolist,'/v1_todolist/<rdSession>')
    api.add_resource(Session3d,'/get_session3d')
    24 条回复    2018-10-26 09:46:08 +08:00
    Rand01ph
        1
    Rand01ph  
       2018-10-25 13:28:20 +08:00
    有代码吗?
    Finest
        2
    Finest  
       2018-10-25 13:43:47 +08:00
    >>> s ={}
    >>> s['a']=None
    >>> s['b']=1
    >>> s.get('a','None')
    >>> print s.get('a','None2')
    None
    >>> print s.get('b','None2')
    1
    >>> print s.get('c','None2')
    None2
    jasonqiao36
        3
    jasonqiao36  
       2018-10-25 13:51:16 +08:00 via Android
    "None" --> None
    danzzzz
        4
    danzzzz  
    OP
       2018-10-25 13:53:07 +08:00
    @Rand01ph
    这是类的外部定义的
    global session
    session = {}

    紧接着
    类的内部的某个函数
    global session
    openid = json_data.get('openid','None')
    tupl = get_3rd_session(openid)
    rdSession = tupl[1].decode()
    session[rdSession] = openid #看这一句跟第一句就好了

    最后在另外一个类的某个函数里面调用的时候是这样的
    global session
    openid = session.get(rdSession,'None')

    理论上讲应该是能获取到这个 openid 的,但是却出现了有时拿到了有时拿不到的情况。百思不得其解
    anonymous256
        5
    anonymous256  
       2018-10-25 13:54:30 +08:00
    session = {'a': 1, 'b': 2, 'c': 3}
    session.get('a') 这种, 只要字典中有这个 key 是可以拿到相应的 value, 如果返回是 None, 则说明这个 key 不存在. 显然, 你"有时候返回 None 的情况", 就是因为不存在这个 key. 一般你可以对 None 这种情况进行处理, 不妨这样写:


    value = session.get('某个 key')
    if value is not None:
    # 获取成功 do something
    else:
    # 该 key 不存在
    anonymous256
        6
    anonymous256  
       2018-10-25 14:02:44 +08:00
    @danzzzz #4
    1. 建议你在赋值之前 print 这两个: openid, rdSession 键值对, 确定你的 rdSession 存在于这个 dict 中.
    2. 大量重复使用 global session, 似乎不是一个好方法, 如果它不是可变的对象, 建议在类的构造方法中这样写:
    def __init__(self, session)
    ....self.session = session
    danzzzz
        7
    danzzzz  
    OP
       2018-10-25 14:03:56 +08:00
    @anonymous256 谢谢你的回答。不过我确实是把 key 以及对应的 value 加进去了,但是在不断的获取的过程中出现了有时候这个 key 存在,有时候又不存在的情况,我不太清楚是什么原因。
    danzzzz
        8
    danzzzz  
    OP
       2018-10-25 14:09:38 +08:00
    @anonymous256
    其实我是最近在写一个微信小程序的项目,在登录的时候需要通过一个随机串来判断对应的 openid 是否存在,这个 rdSession 就是随机串,跟 openid 形成键值对。
    我在每次将 rdSession 返回给前端的时候,都会将其写入 session 中,之后调用接口的时候就利用 rdSession 来判断是谁调用了接口,再返回数据。
    最后就是卡在了这个地方,每次 session.get()来寻找是哪个用户的时候,有时候就找不到了,有时候却可以,很是纳闷。
    danzzzz
        9
    danzzzz  
    OP
       2018-10-25 14:11:58 +08:00
    @jasonqiao36 不好意思,不太明白你的意思。
    anonymous256
        10
    anonymous256  
       2018-10-25 14:14:05 +08:00
    @danzzzz #7 建议采用 logging 跟踪一下键值对的变化. dict 作为 python 最强大的数据结构之一, 应该不可能出现存在这个 key 却获取不到的情况, 我觉得唯一的可能是你对这个 key 最后一次的赋值了 None.
    d = {}
    d['1'] = 1
    d['1'] = None
    print(d.get('1'))
    Sylv
        11
    Sylv  
       2018-10-25 14:17:30 +08:00 via iPhone
    可能性一:存取的 session 不是同一个 session。
    可能性二:存取的键 rdSession 不是同一个值。

    试着在每次 session 存取时:
    print(id(session)
    print(repr(rdSession))
    检查是否一致。
    anonymous256
        12
    anonymous256  
       2018-10-25 14:18:47 +08:00
    @danzzzz #9
    他的意思是这个:
    session = {'a': 1}
    b1 = session.get('b1', 'None')
    b2 = session.get('b2', None)

    >>>print(b1, b2)
    None None
    >>>print(type(b1), type(b2))
    <class 'str'> <class 'NoneType'>
    Hstar
        13
    Hstar  
       2018-10-25 14:29:14 +08:00
    推测,在函数获取前又走了一遍
    ``` python
    global session
    session = {}
    ```
    建议追踪一个这个 session 变量
    mengzhuo
        14
    mengzhuo  
       2018-10-25 15:03:50 +08:00
    恭喜你,有时有,有时无,大概率是数据竞态。
    单节点可以通过减少全局变量,读写锁来规避。
    多节点的话,用 memcache、redis 之类的保证。
    集群的话,shard+version (乐观锁)能基本保证。
    再向上我没有碰到过了,欢迎讨论。
    Yourshell
        15
    Yourshell  
       2018-10-25 15:19:47 +08:00 via iPhone
    你要不每次 get 之前先 print 出来吧,现在我们也不知道你的上下文,你说的只需要看某一段代码有点不妥。
    danzzzz
        16
    danzzzz  
    OP
       2018-10-25 15:23:02 +08:00
    @anonymous256 上网查了一些相关资料,不是很明白怎么跟踪。不知道前辈能不能讲一下大概。
    danzzzz
        17
    danzzzz  
    OP
       2018-10-25 15:29:40 +08:00
    @Yourshell 我把相关代码都贴上了,劳烦看一下了。
    danzzzz
        18
    danzzzz  
    OP
       2018-10-25 15:30:09 +08:00
    @anonymous256 不好意思,我把部分相关的代码贴上了,能麻烦你看一下吗?
    Rand01ph
        19
    Rand01ph  
       2018-10-25 15:47:33 +08:00
    @danzzzz 那你这个服务是如何 run 起来的呢?看起来有可能是多进程模型的问题。
    anonymous256
        20
    anonymous256  
       2018-10-25 16:04:46 +08:00
    @danzzzz
    1. 跟踪这个问题的关键是, 输出的这个字典, 我观察到:
    openid = session.get(rdSession,None) # Todolist 类, get 方法中, 字典的访问操作 F1
    openid = session.get(rdSession,None) # Todolist 类, post 方法中, 字典的访问操作 F2
    session[rdSession] = openid # Session3d 类中, get 方法中, 字典的修改操作 F3

    因此你要在这个三个地方, 输出这个字典. 尤其是修改操作的前后的变化, 要跟踪其中的值.

    2. 追踪这个 dict 的值有两种方式, 如果你是开发环境, 可以直接 print 出来, 或者用 logging 模块. 下面是:
    logging 的方式:

    # Logging 配置
    logger = logging.getLogger('my_logger')
    logger.setLevel(logging.INFO)
    file_handler = logging.FileHandler(filename='我的小程序日志.log')
    formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] ' +
    '%(levelname)s %(message)s')
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    然后在 F1, F2 的地方: logging.info(str(session)),
    在 F3 的代码的上下行 : logging.info(str(session)),

    3. Todolist 中只有字典的访问的操作, 似乎不需要使用 global 关键字也可以
    danzzzz
        21
    danzzzz  
    OP
       2018-10-25 17:35:15 +08:00
    @Rand01ph 这个是放在服务器上跑的。
    danzzzz
        22
    danzzzz  
    OP
       2018-10-25 17:36:56 +08:00
    @anonymous256 不好意思,请问放到代码中的时候是这样子吗?
    '''
    ....上面的代码省略

    import logging

    logger = logging.getLogger('my_logger')
    logger.setLevel(logging.INFO)
    file_handler = logging.FileHandler(filename='我的小程序日志.log')
    formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] ' +
    '%(levelname)s %(message)s')
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    class Todolist(Resource):
    #用户进入页面后将该用户所有的待办事项返回给前端渲染到页面
    def get(self,rdSession):
    global session
    logging.info(str(session))
    openid = session.get(rdSession,None) #通过前端发送过来的随机串 key 得到对应的 value
    logging.info(str(session))
    xpresslink
        23
    xpresslink  
       2018-10-25 17:46:54 +08:00
    请问楼主这个代码是多进程方式部署的么?
    重要的事情说三遍:
    每个进程中的变量是相互隔离的。
    每个进程中的变量是相互隔离的。
    每个进程中的变量是相互隔离的。

    进程是并发执行的,进程之间默认是不能共享全局变量的。如果要共享全局变量需要用
    ( multiprocessing.Value("d",10.0),数值)
    ( multiprocessing.Array("i",[1,2,3,4,5]),数组)
    ( multiprocessing.Manager().dict(),字典)
    ( multiprocessing.Manager().list(range(5)))。
    进程通信(进程之间传递数据)用进程队列( multiprocessing.Queue(),单向通信),
    管道( multiprocessing.Pipe() ,双向通信)。

    或者用个 redis 服务来保存 kv
    vipppppp
        24
    vipppppp  
       2018-10-26 09:46:08 +08:00
    这是个 flask 服务吗 ==
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2575 人在   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 04:56 PVG 12:56 LAX 21:56 JFK 00:56
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86