简体   繁体   中英

Pythonic way of try/except setting of object variables

I'm working on a bit of code that takes in dictionaries and creates an instance of an object. While doing some learning on the try and except blocks, I have incorporated it into my little function. I've ready many times that checking before doing something isn't Pythonic, so I was wondering how I would alter my code (below) to meet that suggestion. At it stands, the code works only because I use getattr before setting. Otherwise, setattr will create the property rather than failing because the property does not exist.

class Gem:
    def __init__(self):
        self.name = None
        self.val = None
        
class Rock:
    def __init__(self):
        self.name = None
        self.weight = None
        
def create_objects(data):
    obj_list = []
    for i in data:
        new_obj = Gem()
        try:
            for k, v in i.items():
                getattr(new_obj, k)
                setattr(new_obj, k, v)
            obj_list.append(new_obj)
        except:
            print("Fail")
    return obj_list

data_list = [
    {"name": "Star", "val": 5},
    {"name": "Square", "val": 1},
    {"name": "Granite", "weight": 50}
]

obj_list = create_objects(data_list)

for o in obj_list:
    for k, v in vars(o).items():
        print(k, v)

To set attributes when creating instances, pass them as arguments to __init__ . That way, you can be sure that they do not exist yet and you need no try / except :

class Gem:
    def __init__(self, name, val):
        self.name = name
        self.val = val

obj_list = []
for gem_attributes in data_list:
    gem = Gem(gem_attributes['name'], gem_attributes['val'])
    obj_list.append(gem)

Passing dictionary values as arguments with the same names as the keys can be shortened with the ** argument unpacking syntax:

gem = Gem(**gem_attributes)

And the whole list creation can be shortened to a list comprehension:

obj_list = [
    Gem(**gem_attributes)
    for gem_attributes in data_list
]

As an additional complication you have different object types.

In order to create both Gem and Rock objects in the same loop, I recommend to add the object type explicitly to the input data, instead of relying on the attribute names to distinguish them:

data_list = [
    ('Gem', {'name': 'Star', 'val': 5}),
    ...
    ('Rock', {'name': 'Granite', 'weight': 50})
]

obj_list = []
for obj_type, obj_attributes in data_list:
    obj_class = {'Gem': Gem, 'Rock': Rock}[obj_type]
    obj_list.append(obj_class(**obj_attributes))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM