切换到Python3后要注意字典的值!

中国- 概述

自从Python2的支持结束已经快要过去一年了,但是由于切换到Python3,dict.values的行为发生了变化,所以我想重新介绍一下。
原因是因为根据写法的不同,可能会出现与Python2时代相同的行为,所以可能没有意识到以下所述的问题。

大致总结官方页面的内容是:在Python2中,通过values()、items()和keys()方法获取字典变量的结果是列表类型,但在Python3中,会返回字典视图对象。据说通过添加list过滤器可以得到与Python2相同的结果。

立刻开始编码

在Python3中,由于块样式和常规样式产生不同的结果,所以即使你认为一切都好,只要改变了写法(常规样式),就有可能引发意料之外的结果。
顺便说一下,ansible_python_interpreter并不会改变行为,ansible本身的行为会根据Python2.x或Python3.x而改变。


# 設定なし
> ansible-config view
ERROR! Invalid or no config file was supplied

# Python3版 ansible
> ansible --version

ansible 2.9.14
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.9/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.9.0 (default, Nov 18 2020, 13:28:38) [GCC 8.3.0]

# 設定なし
> ansible-config view
ERROR! Invalid or no config file was supplied

# Python2版 ansible
> ansible --version

ansible 2.9.14
  config file = None
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python2.7/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.18 (default, Apr 20 2020, 19:27:10) [GCC 8.3.0]

---
- name: Dict values 
  hosts: localhost
  connection: local
  gather_facts: False
  vars:
    mydict: {"a": {"aa": 1 }, "b": {"bb": 2 }, "c": {"cc": 3 }}
  tasks:
    - name: block style debug
      debug:
        msg: >-
          {%- for d in mydict.values() -%}
            {{ d }}
          {%- endfor -%}

    - name: normal style debug
      debug:
        msg: "{{ item }}"
      with_items: "{{ mydict.values() }}"

方块样式和常规结果完全相同。


TASK [debug] *************************************************************************
ok: [localhost] => {
    "msg": "{u'aa': 1}{u'cc': 3}{u'bb': 2}"
}

TASK [debug] *************************************************************************
ok: [localhost] => (item={u'aa': 1}) => {
    "msg": {
        "aa": 1
    }
}
ok: [localhost] => (item={u'cc': 3}) => {
    "msg": {
        "cc": 3
    }
}
ok: [localhost] => (item={u'bb': 2}) => {
    "msg": {
        "bb": 2
    }
}

通常情况下,结果以dict_values的形式输出。
因此,如果对此结果进行循环操作,行为将发生变化,所以需要注意。

TASK [debug] *************************************************************************
ok: [localhost] => {
    "msg": "{'aa': 1}{'bb': 2}{'cc': 3}"
}

TASK [debug] *************************************************************************
ok: [localhost] => (item=dict_values([{'aa': 1}, {'bb': 2}, {'cc': 3}])) => {
    "msg": "dict_values([{'aa': 1}, {'bb': 2}, {'cc': 3}])"
}

应对措施 duì cuò shī)

通过添加list过滤器来解决问题。
为了保持整个代码的一致性,我认为在代码中也可以添加块状的list过滤器。(输出结果不会改变)


---
- name: Dict values 
  hosts: localhost
  connection: local
  gather_facts: False
  vars:
    mydict: {"a": {"aa": 1 }, "b": {"bb": 2 }, "c": {"cc": 3 }}
  tasks:
    - name: block style debug
      debug:
        msg: >-
          {%- for d in mydict.values() | list -%}
            {{ d }}
          {%- endfor -%}

    - name: normal style debug
      debug:
        msg: "{{ item }}"
      with_items: "{{ mydict.values() | list }}"
bannerAds