Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Anthony Grodowski
4,902 PointsHow does Book pass it's output into Bookcase and could someone explain to me whole class Bookcase chunk of code?
How does class Book pass these self.title and self.author to class Bookcase? I mean I see the
for title, author in book_list:
books.append(Book(title, author))
chunk of code but how class Bookcase knows that these informations come from class Book?
It doesn's seem like we're importing class Book into class Bookcase. I also don't get why do we need books and book_list in class Bookcase.
Another thing that confuses me is that we're using and instance object in a classmethod (books). We've set books variable that it's an instance object and then we're using that in a classmethod. Could someone please explain whole class Bookcase to me?
2 Answers
Chris Freeman
Treehouse Moderator 68,468 PointsGood question. A Bookcase instance is a list of Book instances. This list is accessible by the attribute books. The class Bookcase does not have an author or title attribute.
The class method argument book_list is an iterable consisting of pairs of a title string and a author string. The lines of code
# take each pair of tile and author strings...
for title, author in book_list:
# create a Book instance using Book(title,author)
# append new book instance to books attribute
books.append(Book(title, author))
The key line is
return cls(books)
where all Book instance in the books list is passed to the Bookcase.__init__(). During __init__, the list of Book instances is assigned to the attribute self.books. Each Book instance remains intact with its own title and author attributes.
The class Book is not imported into class Bookcase. The class Bookcase only has the attribute books that contains a list of instances of Books.
So the class method:
- takes a list of titles and authors
- create a list of
Bookinstances - calls
cls()to create an instance ofBookcase - where
self.booksis assigned this list
Post back if you need more help. Good luck!!!
Imanol Vazquez
2,746 PointsChris i just want to tel you: thank you so much, chief!
Chris Freeman
Treehouse Moderator 68,468 PointsGlad to be of assistance!
Anthony Grodowski
4,902 PointsAnthony Grodowski
4,902 PointsThank you so much Chris for as always a profesional answer! I think I still didn't get a couple of things: where do we determine that
book_listis made oftitle, authorpairs? Do we just intell python that
book_listis a ?list?(I also don't know what type of data it is, we didn't explictly set it tolist) that is based ontitle, authorpairs by sayingfor title, author in book_list:?Another thing I'm confused by is, why do I recieve different outputs by typing in the REPL: a)
bcb)bc.booksc)str(bc.books)? Isn'tbooksattribute the same thing what the whole instnace is? And how do I recieve a "normal" output by typingstr(bc.books[0])into the REPL? Howclass Bookcaseknows how to convert this into a string even tho we didn't provide__str__in this class? And why by puttingstr(bc.books)into the REPL I don't get a "normal" output as I'm getting withstr(bc.books[0])?I'd also would like to make sure that I got whole process right, so:
First of all by typing into the REPL for example
bc = Bookcase.create_bookcase([("Kwantechizm", "Andrzej Dragan"), ("Nienasycenie", "Stanisław Witkacy")])we're creating a ?class instance? by:1) In
we're creating an empty list of
booksand an iterablebook_list.2) In
we're appending
bookslist withclass Bookinstances frombook_list.3) In
return cls(books)we're creating an actual class instance which is then passed into
Bookcase.__init__(), which translates it into a "standard" instance.Chris Freeman
Treehouse Moderator 68,468 PointsChris Freeman
Treehouse Moderator 68,468 Pointswhere do we determine that
book_listis made oftitle, authorpairs? Good question. My assertion thatbook_listshould be a list was not entirely accurate. It could be any iterable as long as it meets expectations of the code.For the line:
for title, author in book_list:to work correctly:
book_listmust be iterable because of the in.book_listmust also be iterable of exactly two items because it must be unpacked into title, authorSo
book_listdoesn't have to be list. It could be a tuple of tuples, or a list of tuples or a tuple of lists, etc. Ifbook_listis not an iterable of two-item iterables, then the code above will raise an error because it would be able to continue otherwise. We don't need to tell python what type of objectbook_listis. Python will just try what it's given and raise an error if it doesn't work.Side note: the title and author items don't explicitly have to be strings. Since
Book.__init__()simply assigns each item to its corresponding attribute, the author and title could be numbers, or any other object.Another thing I'm confused by is, why do I recieve different outputs by typing in the REPL: a)
bcb)bc.booksc)str(bc.books)? Assuming you instantiatedbcusing something like:Isn't
booksattribute the same thing what the whole instance is? They are different.booksis the instance attribute which is alist.bcpoints to the whole bookcase instance.And how do I receive a "normal" output by typing
str(bc.books[0])into the REPL? This is calling the__str__method of theBookinstance pointed to bybc.books[0].How
class Bookcaseknows how to convert this into a string even tho we didn't provide__str__in this class? The instance ofBookcaseis not converting it to a string. Sincebc.books[0]is referenced, it is accessing the__str__method from that instance pointed to bybc.books[0].And why by putting
str(bc.books)into the REPL I don't get a "normal" output as I'm getting withstr(bc.books[0])?str(bc.books)references thelistpointed to bybc.books, so it is printing out the list and its items. It does not call the__str__method on each item in the list.Good up to here. I would correct part 3.
The expression
cls(books)is the same asBookcase(books)sinceclsis assignedBookcasebecause of the@classmethod. So we're creating an actual instance ofBookcasewith our created listbooksbeing passed into instanceself.__init__()Anthony Grodowski
4,902 PointsAnthony Grodowski
4,902 PointsThank you! I think you forgot to answer particulary WHERE does book_list is being filled with
title, authorpairs so we can then iterate trough it.What do you mean by "So we're creating an actual instance of
Bookcasewith our created listbooksbeing passed intoinstance self.__init__()"? So inreturn cls(books)we're creating a class instance and thenBookcase.__init__()takes books attribute from that class instance and makes it an instance? So overall we haveBookcase(books)class instance and a "standard" instance with listbooks?Chris Freeman
Treehouse Moderator 68,468 PointsChris Freeman
Treehouse Moderator 68,468 PointsThe object
book_listis being created/filled withtitle, authorpairs by some other code that callsBookcase.create_bookcaseor is just typed by the user.What might be confusing is the
booksincls(books),Bookcase(books), the argument inBookcase.__init__(self, books=books), and the value set to the attributeself.booksare all the same object.cls(books)is exactly equivalent toBookcase(books)in that they both create an instance ofBookcase. The argumentbooksis passed to the__init__method in both cases which assigns it to theself.booksattribute.There is a step between calling a class to create an instance and the running of
__init__that isn’t talked about much. The step is the running of the__new__method. It is__new__that passes the arguments to__init__.The flow for class instance creation starts with
bc = Bookcase(book_list)Bookcase.__new__(book_list)to create the instance!__new__calls__init__to initialize the instance__init__sets the attribute values of the instance.self.booksset tobook_list__new__which returns the created and initialized instancebcnow points to new instance ofBookcaseThe flow for using the class method is essentially the same:
bc = Bookcase.create_bookcase(title_auth_list)create_bookcasecreates list ofBookinstances fromtitle_auth_list, let’s call it “book_list”create_bookcasecallscls(book_list)which is the same asBookcase(book_list)The process then continues as before:
Bookcase.__new__(book_list)to create the instance!__new__calls__init__to initialize the instance__init__sets the attribute values of the instance.self.booksset tobook_list__new__which returns the created and initialized instancebcnow points to new instance ofBookcase