简体   繁体   中英

How to generalize this class?

I've a few classes like the following one and would like to avoid too much repetition and unnecessarily bloated code . I'm looking for a specific optimization, not a code review .

Current code:

class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    @classmethod
    def from_dictionary(cls, dictionary):
        return cls(
            name=dictionary['name'] if 'name' in dictionary else '',
            price=dictionary['price'] if 'price' in dictionary else ''
        )

Desired (pseudo) code:

class Item:
    def __init__(self, *args, **kwargs):
        for kwarg in kwargs:
            self[kwarg] = kwargs[kwarg]


    @classmethod
    def from_dictionary(cls, dictionary):
        return cls(
            for key, value in dictionary:
                key=value or ''
        )

How can I achieve something close to my desired code in Python?

You can use the builtin setattr to set attributes:

class Item: 
    def __init__(self, *args, **kwargs): 
        for key, value in kwargs.items():
            setattr(self, key, value)


    @classmethod 
    def from_dictionary(cls, dictionary): 
        return cls(**dictionary)

In the classmethod, we use the ** operator to unpack the given dictionary.

Since classes are first-class objects in Python, you could define a function that created a class with the desired attributes. For example:

def make_class(classname, *attrnames):

    class Class:
        def __init__(self, *args):
            for name, value in zip(attrnames, args):
                setattr(self, name, value)

        @classmethod
        def from_dictionary(cls, dictionary):
            inst = cls()  # Empty instance.
            for name in attrnames:
                setattr(inst, name, dictionary.get(name, ''))
            return inst

    Class.__name__ = classname
    return Class


if __name__ == '__main__':

    Class1 = make_class('Class1', 'name', 'price')
    obj1 = Class1('item1', 42)
    print(f'obj1 is instance of {type(obj1).__name__}')
    print(vars(obj1))
    print()
    Class2 = make_class('Class2', 'foo', 'bar')
    obj2 = Class2('whatcha')
    print(f'obj2 is instance of {type(obj2).__name__}')
    print(vars(obj2))
    print()
    obj3 = Class1.from_dictionary({'name': 'item2', 'price': 3.14})
    print(f'obj3 is instance of {type(obj3).__name__}')
    print(vars(obj3))

Output:

obj1 is instance of Class1
{'name': 'item1', 'price': 42}

obj2 is instance of Class2
{'foo': 'whatcha'}

obj3 is instance of Class1
{'name': 'item2', 'price': 3.14}

Use the Python library marshmallow. Then it's as simple as adding @addschema as a class decorator. This will allow for easy deserialization. The code would look like:

item = Item. Schema().load(item_dict)

https://marshmallow.readthedocs.io/en/stable/

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