I'm trying to clean up this code.
For example
data = [
{
"version": "11g",
"edition": "Enterprise",
"build_number": "11.2.0.4.0",
"path": "",
"devices": [
{
"host_name": "server1",
"manufacturer": "HP",
},
{
"host_name": "server2",
"manufacturer": "HP",
}
]
},
{
"version": "11g",
"edition": "Enterprise",
"build_number": "11.2.0.4.0",
"path": "",
}
]
for each in data:
version = each["version"]
if "devices" in each:
for server in each["devices"]:
hostname = server["host_name"]
print(version, hostname)
else:
hostname = None
print(version, hostname)
This prints out the following which is what I want. Is there a way to do it without using two print statements?
11g server1
11g server2
12g None
CodePudding user response:
Null Object (1 print)
If you want to print (version, None) for each without "devices", then something like this slould do:
for each in data:
version = each["version"]
for server in each.get("devices", [{"host_name": None}]):
hostname = server["host_name"]
print(version, hostname)
Explanation: if each doesn't have "devices", get() with return a list with one fake device ([{"host_name": None}]), with a hostname that you want to print when there's no device.
For readability, I would save that fake device to a named constant:
NONE_DEVICE = {"host_name": None}
for each in data:
version = each["version"]
for server in each.get("devices", [NONE_DEVICE]):
hostname = server["host_name"]
print(version, hostname)
This is similar to "Null Object" design pattern, where you return a special "empty" object when there is no object.
My solution (2 prints)
However, it's debatable whether it's appropriate to fake missing devices with some special object instead of just admitting that there's no devices. I personally wouldn't get rid of the if statement and the second print. I would clean up this code in a different area:
# `server` is renamed to `device`,
# so that the same thing doesn't have two different names.
# I'd also change `each` to something meaningful.
for each in data:
if "devices" not in each:
print(each["version"], None)
continue
for device in each["devices"]:
print(each["version"], device["host_name"])
CodePudding user response:
Another solution would be to use list comprehensions. Shorter but less readable. Lets start with the simple case: print version if no device present:
[print(row['version']) for row in data if 'devices' not in row]
But with the nested list comprehension things get less readable:
[print(row['version'], [device['host_name'] for device in row['devices']]) for row in data if 'devices' in row]
