简体   繁体   中英

Have the class as value in a dictionary

I have a class:

class Competition:

    def __init__(self, year = int, distance = int, stages = int, winner = None , cyclist = list):
        self.year = year
        self.distance = distance
        self.stages = stages
        self.winner = winner
        self.cyclist = cyclist


    def __str__(self):
        return "Competition({}, {}, {}, {}, {}".format(self.year, self.distance, self.stages, self.winner, self.cyclist)

    def __repr__(self):
        return "{} {} {} {} {}".format(self.year, self.distance, self.stages, self.winner, self.cyclist)

And I want to add the class to a dictionary as the value, and as key the years. The information I get is from a file.

So I have this

 with open('tour-de-france.csv') as file:
    reader = csv.reader(file)
    no_header = next(reader, None)

    new_dict = {}
    for x in reader:
        new_dict[int(x[0])] = Competition(int(x[0]), x[3], x[11], None,[])
    print(new_dict)

Part of the output is:

{1903: 1903 2428 6 None [], 1904: 1904 2428 6 None [], 1905: 1905 2994 11 None [],

But I would like it as:

{1903: Competition(1903, 2428, 6, None, []), 1904: Competition(1904, 2428, 6, None, []), 1905: Competition(1905, 2994, 11, None, []),

Is that possible?

When printing dictionaries with classes in them, it will print the return value of the __repr__ function. Therefore, you can simply make the __repr__ function as follows (since the __str__ function is already returning the value that you want):

def __repr__(self):
    return self.__str__()

As @Seth Peace said, the thing is that in order to get a string value for your class, Python calls __repr__ if it is defined, not __str__ .

However, a cleaner way to do this can be to use a dataclass:

from dataclasses import dataclass
from typing import Optional

@dataclass
class Competition:
    year: int
    distance: int
    stages: int
    winner: Optional[str]
    cyclist: list

print(Competition(2019, 3, 5, "John Doe", []))

By doing so, __init__ , __str__ and __repr__ will already have been defined in a meaningful way.

When you print a container, it includes the repr of its elements. The problem is that you've swapped the __str__ and __repr__ methods.

Although, there's not much point in having a separate __str__ if it's practically the same as __repr__ just written a bit different. I would add some additional info to make it more helpful to an end user.

As well, you've mixed up type annotations and default values in __init__ . All the ones that have a type as their default value are incorrect. Only winner is correct, but because it has a default and the others don't, it needs to go at the end.

class Competition:

    def __init__(self, year: int, distance: int, stages: int, cyclist: list, winner=None):
        self.year = year
        self.distance = distance
        self.stages = stages
        self.cyclist = cyclist
        self.winner = winner

    def __repr__(self):
        s = "Competition({}, {}, {}, {}, {})".format(
            self.year,
            self.distance,
            self.stages,
            self.cyclist,
            self.winner
            )
        return s

    def __str__(self):
        s = "{}: {} km, {} stages, winner {} out of {})".format(
            self.year,
            self.distance,
            self.stages,
            self.winner,
            self.cyclist,
            )
        return s

(You were also missing a closing parenthesis inside the format string.)

And then instantiation would look like this:

year = int(x[0])
new_dict[year] = Competition(year, x[3], x[11], [])

For example:

c = Competition(1903, 2428, 6, [])
print(c)  # -> 1903: 2428 km, 6 stages, winner None out of [])
print(repr(c))  # -> Competition(1903, 2428, 6, [], None)

You cannot have the class as a value in this way. You sure can pass a reference to the class itself, but having it this way ( Competition(1903, 2428, 6, None, []) ) what you actually want is to print an object - an instance to a class . So, if you want to print a string that is like the desired output you should do something like you already did with __str__ , but it will be a string (enclosed in quotes) instead of the declarative class form.

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