Sib007 / intro_machine_learning_using_python

0 stars 0 forks source link

Integrating the class `FreeLancer` #2

Open montesmariana opened 1 year ago

montesmariana commented 1 year ago

The idea as I suggested it (but keep asking if it's still not clear) is to create a class that represents a translator (FreeLancer) and have the values of translator and reviewer be instances of that class. Whether the employee is "Internal" could be an attribute of FreeLancer.

I will not write the class for you, but only describe the behaviour as I'm envisioning it. Note that in this case the translator and reviewer attributes of your Project class (ex Translation_agency?) would not be class attributes but instance attributes (because they are specific of each project), and instead of strings they would be instances of FreeLancer. So you would have something like this:

tr = FreeLancer("Sibylle de Woot", "sibylle.de.woot@email.me", is_internal = False) # and any other relevant arguments
rev = FreeLancer("Mariana Montes", "mariana.montes@company.be", is_internal = True) # and any other relevant arguments
project = Project(...) # whatever arguments you want to initialize with
project.set_translator(tr)
project.set_reviewer(rev)

As we discussed in class, maybe the translator, reviewer, or other arguments are set at initialization (as arguments when you instantiate the class), or with methods. I illustrated here with methods but you could have translator = tr, reviewer = rev inside your Project() call. Then when you call project.reviewer you get an instance of the FreeLancer class, which maybe has its own print statement. project.reviewer.name will print the name, project.reviewer.is_internal whether they are internal (so, "Mariana Montes" and True respectively, in this example)... And when designing what you print in the __str__() call of the Project class, you can access the information from within with self.reviewer.name, self.reviewer.is_internal, etc...

Is that a bit more clear?

Sib007 commented 1 year ago

Thank you for the explanations! I think I understand, I'll try to incorporate it into my script as soon as I'm done with the passing requirements and I'll let you know if it turns out that I didn't understand it well enough to make it work.

Sib007 commented 1 year ago

After trying to implement it, I run into two problems:

  1. I instantiate my class based on a list of dictionaries which I read from a json-file. However, I can't export a dictionary containing a class object to a json-file. Is there a way to still export the list of dictionaries to a json-file, while maintaining the object from the Freelancer class as value for "translator" and "reviewer"?
  2. I go through the info in the json-file and print each project's info using a for-loop, but that doesn't instantiate separate objects from the Projects class which I could then call the various attributes of. Is there a way to instantiate separate objects while still reading the info from a json-file?

I worked in the Jupyter Notebook "Final-assignement_trial-and-error_7_linking classes" for this part.

Many thanks in advance!

montesmariana commented 1 year ago

For the first problem: your file (especially if you want it to be readable beyond your module) won't know that something is from class Freelancer. But you can have the data of the freelancer as a nested dictionary OR use an id.

Nested dictionary = when you store the JSON of the project, the "translator" and "reviewer" don't have a string as value but an object with all the properties of the Freelancer class (attributes, not classes) ID = if your freelancer data has a unique ID for each translator/reviewer, you can use that as the string value of "translator" / "reviewer" in the JSON of your project, and that already lets you know how to retrieve the freelancer's information from their database.

Is that clear? (If you need we can chat)

For the second question: you can use a comprehension list instead. For loops are for dealing with one item at a time. If you want to "transform" your list, e.g. turn your list of dictionaries into a list of Project instances, you can use a comprehension list, e.g:

my_projects = [Project(x) for x in my_dictionary]

And then my_projects is a list of Project instances. You could also make it a dictionary instead. Say that each element in my_dictionary is a dictionary that you use to instantiate the Project AND it has a name attribute that is unique. You can do:

my_projects = { x['name'] : Project(x) for x in my_dictionary }

And if you have a project with name project_00, then my_projects['project_00'] will be that Project instance.

Let me know if anything is not clear!

montesmariana commented 1 year ago

It's a bit tough to comment on a Jupyter Notebook via the PR because it's not really plain text, so I'll leave here some notes about "Final-assignement_trial-and-error_7_linking classes".

for key, value in dictionary.items():
    setattr(self, key, value)

It is not a bad idea BUT it is less robust in that it doesn't offer any validation if the inputted data is wrong. You are not adding validation in this class anyways yet (as long as you have validation in the other class AND you mention it in the docs as "future feature", that's fine), but it will make it harder to add it later, I find.

If you want to provide a dictionary instead of many separated arguments, you can use **kwargs (which I did not teach because it was a bit too much, but I think you can handle it. You seem to have the need for it.) - Some docs

image

So: in your case you could keep the class like Freelancers', but withkwargsas argument, then check for each argument and validate (eventually, not necessarily for this submission), so that a user can either doFreelancers(name = "Some name", email = "email@email.com")orFreelancers(my_dictionary)and both would do the same. You can also apply that to yourProject` class. Let me know if anything is not clear!

montesmariana commented 1 year ago

Ok, now looking at your notebook a bit more I finally understand why you want to put everything in one JSON. Don't! You don't need that.

My suggestion was something like this:

You have one JSON with a list of projects, or one JSON per project (or a csv with one row per project, whatever). Think what makes the most sense in practice, and if you're still unsure of how to implement it, hit me up. Say that you have one JSON per project, such as "lit_translation_001.json", "tech_translation_002.json", etc.

Then you have another JSON (or csv with one row per person) that has the information of each translator. So that the info of each translator is registered only once, in one place: you don't repeat it in the file of the projects. Say this is called "freelancers.json".

So, in the project's JSON, the translator / reviewer will be just a string with a unique ID, which can be some randomly generated ID or the person's name, as long as it's unique. You are already trying to use ID, so let's say you use ID (and thus allow for different people with the same name and/or email).

When you instantiate your Project, the data that you receive from the JSON is just that ID. But if you also have the JSON of the translators, you can retrieve the right freelancer based on that ID. For example:

with open('freelancers.json', 'r') as f:
    my_freelancers = {x.id : x for x in json.load(f)} # if the json is a list of dictionaries
with open('lit_translation_001.json', 'r') as f2:
    project_dict = json.load(f2)
    if 'translator' in project_dict and project_dict['translator'] in my_freelancers:
        project_dict['translator'] = Freelancer(**my_freelancers[project_dict['translator']])
    if 'reviewer' in project_dict and project_dict['reviewer'] in my_freelancers:
        project_dict['reviewer'] = Freelancer(**my_freelancers[project_dict['reviewer']])
    project = Project(**project_dict) # of course you have to allow 

Then you should also check that translator and reviewer are either strings (your default) or of class Freelancer (type(translator) == str or type(translator) == Freelancer). The if statements I added check that there is a 'translator' / 'reviewer' value in your dictionary and that the value is one of the IDs in the freelancers database.

Sib007 commented 1 year ago

Just an update to let you know that linking these two classes now works! Many thanks for your help! :)