简体   繁体   中英

When to use a class instead of a dict

User data, as follows:

user = {"id": 1, "firstName": "Bar", "surname": "Foosson", "age": 20}

is sent to an application via json.

In many places in the code the following it done:

user["firstName"] + " " + user["surname"]

which leads me to believe a function should be used:

def name(user):
    return user["firstName"] + " " + user["surname"]

which in turn leads me to believe that the code should be refactored with the use of a User class instead, with a name method. Do you agree and is there any argument for not refactoring the code to use a class instead?

I'm sure you are hesitant to use classes because of the need to write boilerplate code.

But there's a nice library that may make your life easier: attrs .

Glyph has a post with a self-speaking title: The One Python Library Everyone Needs . Of course, it's an opinionated piece, but here's a quote from its Examples page :

 >>> @attr.s ... class Coordinates(object): ... x = attr.ib() ... y = attr.ib() 

By default, all features are added, so you immediately have a fully functional data class with a nice repr string and comparison methods.

 >>> c1 = Coordinates(1, 2) >>> c1 Coordinates(x=1, y=2) >>> c2 = Coordinates(x=2, y=1) >>> c2 Coordinates(x=2, y=1) >>> c1 == c2 False 

It's a quite handy library, so check it out.

Here's an example of your User class:

import attr

@attr.s
class User(object):

    id = attr.ib()
    firstName = attr.ib()
    surname = attr.ib()
    age = attr.ib()

    @property
    def name(self):
        return '{0.firstName} {0.surname}'.format(self)

user_dict = {'id': 1, 'firstName': 'Bar', 'surname': 'Foosson', 'age': 20}
user = User(**user_dict)
assert user.name == 'Bar Foosson'

Dictionaries are great for storage and retrieval, but if you need more functionality on top of that, a class is usually the way to go. That way you can also assure certain attributes are set, etc.

For your situation, if a user's attributes are read-only, my approach would actually be using namedtuple . You get immutability of attributes, memory efficiency, and you can still set name to a pre-defined method to be used just like you'd use property on a class:

from collections import namedtuple

@property
def name(self):
    return '{} {}'.format(self.firstName, self.surname)

User = namedtuple('User', 'id firstName surname age')
User.name = name

user = User(1, 'Bar', 'Foosson', 20)
print(user.name)  # Bar Foosson

user = User(2, 'Another', 'Name', 1)
print(user.name)  # Another Name

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