0

I'm trying to learn OOP but I'm getting very confused with how I'm supposed to run the methods or return values. In the following code I want to run read_chapters() first, then sendData() with some string content that comes from read_chapters(). Some of the solutions I found did not use __init__ but I want to use it (just to see/learn how i can use them).

How do I run them? Without using __init__, why do you only return 'self'?

import datetime

class PrinceMail:

    def __init__(self):
        self.date2 = datetime.date(2020, 2, 6)
        self.date1 = datetime.date.today()
        self.days = (self.date1 - self.date2).days
        self.file = 'The_Name.txt'
        self.chapter = '' # Not sure if it would be better if i initialize chapter here-
                           # or if i can just use a normal variable later


    def read_chapters(self):
        with open(self.file, 'r') as book:
            content = book.readlines()
            indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
            indexes = indexes[self.days:]
            heading = content[indexes[0]]
            try:
                for i in (content[indexes[0]:indexes[1]]):
                    self.chapter += i # can i use normal                      var and return that instead?
                    print(self.chapter)
            except IndexError:
                for i in (content[indexes[0]:]):
                    self.chapter += i
                    print(self.chapter)
        return self????? # what am i supposed to return? i want to return chapter
                         # The print works here but returns nothing.

    # sendData has to run after readChapters automatically
    def sendData(self):
         pass
         #i want to get the chapter into this and do something with it


    def run(self):
        self.read_chapters().sendData()
        # I tried this method but it doesn't work for sendData
        # Is there anyother way to run the two methods?


obj = PrinceMail()
print(obj.run())
#This is kinda confusing as well

3 Answers3

1

Chaining methods is just a way to shorten this code:

temp = self.read_chapters()
temp.sendData()

So, whatever is returned by read_chapters has to have the method sendData. You should put whatever you want to return in read_chapters in a field of the object itself (aka self) in order to use it after chaining.

frollo
  • 1,296
  • 1
  • 13
  • 29
  • Got it to work. I had to return self in read_chapters(). Or I get an AttributeError: 'NoneType' object has no attribute 'sendData'. Any idea why this is?? – learner882342 Feb 06 '20 at 18:30
  • In your code you were effectively returning `None`, which is of `NoneType` and does not have the method `sendData` – frollo Feb 07 '20 at 09:18
0

First of all, __init__ has nothing to do with what you want to achieve here. You can consider it as a constructor for other languages, this is the first function that is called when you create an object of the class.

Now to answer your question, if I am correct you just want to use the output of read_chapters in sendData. One of the way you can do that is by making the read_chapters a private method (that is if you don't want it to use through the object) using __ in the starting of the name like __read_chapters then make a call to the function inside the sendData function.

Another point to consider here is, when you are using self and don't intend to use the function through the object you don't need to return anything. self assigns the value to the attribute of the current instance. So, you can leave the function read_chapters at self.chapter = i and access the same in sendData. Ex -

def sendData(self):
    print(self.chapter)
  • Yup. It worked without returning self.chapters or just chapters. But I had to return 'self' when I run it like frollo's answer. Any idea why that is? – learner882342 Feb 06 '20 at 18:34
  • My understanding is, that it is because there is an assignment. When you say `temp = self.read_chapters()` a return value is expected by temp, else it will be empty as there is nothing to be assigned to temp, hence `NoneTpye`. So, when you do `temp.sendData()` you are basically calling a method on basically nothing. Hope that helps. Also, please accept the answer or mark it as helpful, if it helped. – Siddhartha Pramanik Feb 06 '20 at 19:19
0

I'm not an expert but, the reason to return self is because it is the instance of the class you're working with and that's what allows you to chain methods.

For what you're trying to do, method chaining doesn't seem to be the best approach. You want to sendData() for each iteration of the loop in read_chapters()? (you have self.chapter = i which is always overwritten)

Instead, you can store the chapters in a list and send it after all the processing. Also, and I don't know if this is a good practice but, you can have a getter to return the data if you want to do something different with (return self.chapter instead of self)

I'd change your code for:

import datetime

class PrinceMail:

    def __init__(self):
        self.date2 = datetime.date(2020, 2, 6)
        self.date1 = datetime.date.today()
        self.days = (self.date1 - self.date2).days
        self.file = 'The_Name.txt'
        self.chapter = []


    def read_chapters(self):
        with open(self.file, 'r') as book:
            content = book.readlines()
            indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
            indexes = indexes[self.days:]
            heading = content[indexes[0]]
            try:
                for i in (content[indexes[0]:indexes[1]]):
                    self.chapter.append(i)
            except IndexError:
                #not shure what you want to do here
                for i in (content[indexes[0]:]):
                    self.chapter.append(i)

        return self

    # sendData has to run after readChapters automatically
    def sendData(self):
        pass
        #do what ever with self.chapter

    def get_raw_chapters(self):
        return self.chapter

Also, check PEP 8 Style Guide for naming conventions (https://www.python.org/dev/peps/pep-0008/#function-and-variable-names)

More reading in

Method chaining - why is it a good practice, or not?

What __init__ and self do on Python?

Henrique Gonçalves
  • 1,572
  • 3
  • 16
  • 27
  • yes. You save the data in your chapter variable of the class. So, when you call sendData, self.chapter will have the data that was processed in read_chapters – Henrique Gonçalves Feb 06 '20 at 18:32
  • Test it here: https://repl.it/repls/GrowingSizzlingCylinders . It generates 3 random numbers and concatenate them to a string then, sendDate prints it – Henrique Gonçalves Feb 06 '20 at 18:45