为何hasattr无法检测yaml.safe_load加载的字典中ethernets键?
问题
我写了一段读取YAML配置文件的Python代码,需要判断配置中是否存在ethernets属性,于是用ethernets1测试属性不存在时的代码行为。测试代码如下:
#!/usr/bin/python import yaml import simplejson as json NETPLAN = "/etc/netplan/01-network-manager-all.yaml" # get netplan file with open(NETPLAN, "r") as stream: try: netplan_config = yaml.safe_load(stream) print("netplan_config = " + json.dumps(netplan_config)) stream.close() except yaml.YAMLError as e: print(f"error = {str(e)}") # test 1 if hasattr(netplan_config["network"], "ethernets"): print("mark1") else: print("mark2") # test 2 if netplan_config["network"]["ethernets"]: print("mark3") else: print("mark4") # test 3 if netplan_config["network"]["ethernets1"]: print("mark5") else: print("mark6") # test 4 try: if netplan_config["network"]["ethernets1"]: print("mark7") except KeyError: print("mark8")
输出结果:
mark2 mark3 error thrown: KeyError: 'ethernets1'
我不理解为什么hasattr没法作用在netplan_config上,导致mark1没被打印出来;另外test2的写法在属性不存在时会报错。我知道test4可行,但更倾向用更简洁的写法替代hasattr。
参考的YAML配置文件内容:
network: ethernets: eth0: addresses: - 192.168.4.31/22 dhcp4: false dhcp6: false match: macaddress: 24:4b:fe:e2:1c:4a nameservers: addresses: - 8.8.8.8 - 8.8.4.4 routes: - to: default via: 192.168.4.1 set-name: eth0 renderer: NetworkManager version: 2
解答
问题核心在于:yaml.safe_load()加载YAML文件后返回的是Python字典对象,不是自定义类的实例,而hasattr()是用来检查对象是否有某个**属性(类的成员变量/方法)**的,不是用来检查字典是否有某个键的。
所以test1里用hasattr(netplan_config["network"], "ethernets")永远会返回False,因为字典的键不是对象的属性——字典的属性是keys()、values()这类方法,而ethernets是字典的键,不是属性。
要判断字典中是否存在某个键,正确的写法有两种:
使用
in关键字(最简洁直接)
把test1改成:# 修正后的test1 if "ethernets" in netplan_config["network"]: print("mark1") else: print("mark2")这样就能正确识别
ethernets是否存在,输出mark1;如果换成ethernets1,则会输出mark2。使用字典的
get()方法(适合要同时获取值的场景)
如果需要在判断存在的同时获取对应的值,可以用get(),它在键不存在时会返回None(或你指定的默认值),不会抛出KeyError:ethernets_config = netplan_config["network"].get("ethernets") if ethernets_config: print("mark1") else: print("mark2")
另外你提到的test2写法netplan_config["network"]["ethernets"],当键不存在时会直接抛出KeyError,这是字典的默认行为——直接通过[]访问不存在的键就会报错,所以这种写法不安全,建议用上面两种方式替代。
内容的提问来源于stack exchange,提问作者xinthose

