Reputation: 151
I know this has been asked before, but I couldn't find an answer for my problem and all of the answers got me more confused.
So I created a class called Books, which takes as input a file location and the name of the file, and has a method called countwords which counts the words of the file.
I created a bunch of instances(are they called like this?) of this class, but I want to iterate the method CountWords on all of them. This is my code:
class Books():
def __init__(self, path, fullname):
self.path = path
self.fullname = fullname
def count_words(self):
try:
with open(self.path + self.fullname, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {self.fullname} doesn't exist.")
else:
words = contents.split()
num_words = len(words)
print(f"The file {self.fullname} has about {num_words}"
f"words.")
alice = Books("text_files/", 'alice.txt')
siddharta = Books("text_files/", 'siddhartha.txt')
mobydick = Books('text_files/', 'moby_dick.txt')
little_women = Books('text_files/', 'little_women.txt')
I want to write something like this:
for book in Books.list():
book.count_words()
and get:
The file alice.txt has about 29465 words.
The file siddhartha.txt has about 1500 words.
The file moby_dick.txt has about 215830 words.
The file little_women.txt has about 189079 words.
Printing the words count of all the instances associated with the Books() class, how can I achieve this? thank you!
EDIT: I have tried different approaches but this is the one I'm using now:
code:
# 1
import weakref
class Book():
# 2
book_list = []
def __init__(self, path, fullname):
self.path = path
self.fullname = fullname
# 3
self.__class__.book_list.append(weakref.proxy(self))
def count_words(self):
try:
with open(self.path + self.fullname, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {self.fullname} doesn't exist.")
else:
words = contents.split()
num_words = len(words)
print(f"The file {self.fullname} has about {num_words} "
f"words. ")
alice = Book("text_files/", 'alice.txt')
siddharta = Book("text_files/", 'siddhartha.txt')
mobydick = Book('text_files/', 'moby_dick.txt')
little_women = Book('text_files/', 'little_women.txt')
# 4
for book in Book.book_list:
book.count_words()
Upvotes: 2
Views: 1120
Reputation: 21
Judging by your variable, it might be easier to comprehend by naming the class Book
:
class Book():
def __init__(self, path, fullname):
self.path = path
self.fullname = fullname
def count_words(self):
try:
with open(self.path + self.fullname, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {self.fullname} doesn't exist.")
else:
words = contents.split()
num_words = len(words)
print(f"The file {self.fullname} has about {num_words}"
f"words.")
make the instances of books as you've described
alice = Book("text_files/", 'alice.txt')
siddharta = Book("text_files/", 'siddhartha.txt')
mobydick = Book('text_files/', 'moby_dick.txt')
little_women = Book('text_files/', 'little_women.txt')
and add them into a list referenced as books
:
books = [alice, siddhartha, mobydick, little_women]
then you can iterate over the list calling the count_words
method on each book
Upvotes: 1
Reputation: 140286
that's the wrong way to approach the problem.
I suggest you create a dictionary of classes instead, with filename as key:
instead of:
alice = Books("text_files/", 'alice.txt')
siddharta = Books("text_files/", 'siddhartha.txt')
mobydick = Books('text_files/', 'moby_dick.txt')
little_women = Books('text_files/', 'little_women.txt')
do:
books_dict = {name:Books('text_files/',name+".txt") for name in ["alice","siddhartha","moby_dick","little_women"}
Now you have a dictionary of Books
instances. You can now iterate on it like this:
for book_name,book_instance in books_dict.items():
print(book_name,book_instance)
If you want to "unregister" an instance, just do:
books_dict.pop("alice")
Better not create x variables for x instances. Use a federating structure.
Upvotes: 1
Reputation: 709
All you have to do is create a class variable which will store the book information when the instance is instantiated.
And then expose a class level method which return this list when Books.list
gets called.
Here is the code for the same
class Books(object):
_books_list = list()
def __init__(self, path, fullname):
self.path = path
self.fullname = fullname
self._books_list.append(self.path + self.fullname)
def count_words(self):
try:
with open(self.path + self.fullname, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {self.fullname} doesn't exist.")
else:
words = contents.split()
num_words = len(words)
print(f"The file {self.fullname} has about {num_words}"
f"words.")
@classmethod def list(): return self._books_list
alice = Books("text_files/", 'alice.txt')
siddharta = Books("text_files/", 'siddhartha.txt')
mobydick = Books('text_files/', 'moby_dick.txt')
little_women = Books('text_files/', 'little_women.txt')
Upvotes: 2
Reputation: 19895
Rather than having your class keep references to all the instances that have been created, I suggest you define your data first, and then create a collection of instances from that data.
For example:
book_paths = [('text_files/', 'alice.txt'),
('text_files/', 'siddharta.txt'),
('text_files/', 'moby_dick.txt'),
('text_files/', 'little_women.txt')]
books = []
for path, name in book_paths:
book = Books(path, name)
books.append(book)
book.count_words()
You can also later iterate over books
to do whatever you want. Another way to do this, using a list
comprehension:
books = [Books(path, name) for path, name in book_paths]
for book in books:
book.count_words()
Upvotes: 2