How to assign from input to object from a class

I have multiple classes and I have instances from each class e.g: Student class. every instance (a student) has their own courses. Now when a user signs in (by input) I want to print their list of courses. Or even just their age to show that I have the correct object.

Is there a better way than eval() to get an object from class based on input like the following example:

class Student:
  def __init__(self, name, age):
    self._name = name
    self._age = age

blablue = Student('bla blue', '23')
name = input('enter your name')
name = name.split(' ')
stundent = eval(name[0] + name[1])
print(student)
print(student.age)

output:

enter your name: bla blue
<__main__.Foo object at 0x000001B2978C73C8>
23

Upvotes: 1

Views: 177

Answers (1)

bruno desthuilliers
bruno desthuilliers

Reputation: 77912

I assume this is for educational purpose (production code would use a SQL database and some ORM):

try:
    # python 2.x
    input = raw_input
except NameError:
    # python 3.x
    pass


class AlreadyExists(ValueError):
    pass


class DoesNotExist(LookupError):
    pass


class FooCollection(object):
    def __init__(self):
        self._foos = {}

    def add(self, foo):
        if foo.name in self._foos:
            raise AlreadyExists("Foo with name '{}' already exists".format(foo.name))
        self.update(foo)

    def update(self, foo):
        self._foos[foo.name] = foo    

    def get(self, name):
        try:
            return self._foos[name]
        except KeyError:
            raise DoesNotExist("no Foo named '{}'".format(name))


class Foo(object):
    def __init__(self, name, age):
        self._name = name
        self._age = age

    # we at least need to be able to read the name   
    @property
    def name(self):
        return self._name

    def __repr__(self):
        return "Foo({}, {})".format(self._name, self._age)


def main():
    foos = FooCollection()     
    blablue = Foo('bla blue', '23')
    foos.add(blablue)

    name = input('enter your name: ').strip()
    try:
        print("found {}".format(foos.get(name)))
    except DoesNotExist as e:
        print(e)

if ___name__ == "__main__":
    main()

The principle here is to have a storage for your instances. I chose a dict for fast lookup with the Foo.name as key, in real life you'd probably want an opaque unique identifier for each instance and multiple indexes (i.e. one by id, one by name etc) - but actually in real life you would use a SQL database that already provide all those features in a much more optimized way ;-)

Also, I wrapped the dict in a dedicated class with its own interface. This allows to decouple the interface from the implementation (if you later decide you want more indexes than just name for example), and encapsulate domain logic too (i.e. checking you don't accidentally overwrite an existing Foo).

Upvotes: 2

Related Questions