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 trialAnthony 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,457 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 Book
s.
So the class method:
- takes a list of titles and authors
- create a list of
Book
instances - calls
cls()
to create an instance ofBookcase
- where
self.books
is 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,457 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_list
is made oftitle, author
pairs? Do we just intell python that
book_list
is a ?list?(I also don't know what type of data it is, we didn't explictly set it tolist
) that is based ontitle, author
pairs 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)
bc
b)bc.books
c)str(bc.books)
? Isn'tbooks
attribute 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 Bookcase
knows 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
books
and an iterablebook_list
.2) In
we're appending
books
list withclass Book
instances 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,457 PointsChris Freeman
Treehouse Moderator 68,457 Pointswhere do we determine that
book_list
is made oftitle, author
pairs? Good question. My assertion thatbook_list
should 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_list
must be iterable because of the in.book_list
must also be iterable of exactly two items because it must be unpacked into title, authorSo
book_list
doesn't have to be list. It could be a tuple of tuples, or a list of tuples or a tuple of lists, etc. Ifbook_list
is 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_list
is. 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)
bc
b)bc.books
c)str(bc.books)
? Assuming you instantiatedbc
using something like:Isn't
books
attribute the same thing what the whole instance is? They are different.books
is the instance attribute which is alist
.bc
points 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 theBook
instance pointed to bybc.books[0]
.How
class Bookcase
knows how to convert this into a string even tho we didn't provide__str__
in this class? The instance ofBookcase
is 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 thelist
pointed 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)
sincecls
is assignedBookcase
because of the@classmethod
. So we're creating an actual instance ofBookcase
with our created listbooks
being 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, author
pairs so we can then iterate trough it.What do you mean by "So we're creating an actual instance of
Bookcase
with our created listbooks
being 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,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsThe object
book_list
is being created/filled withtitle, author
pairs by some other code that callsBookcase.create_bookcase
or is just typed by the user.What might be confusing is the
books
incls(books)
,Bookcase(books)
, the argument inBookcase.__init__(self, books=books)
, and the value set to the attributeself.books
are all the same object.cls(books)
is exactly equivalent toBookcase(books)
in that they both create an instance ofBookcase
. The argumentbooks
is passed to the__init__
method in both cases which assigns it to theself.books
attribute.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.books
set tobook_list
__new__
which returns the created and initialized instancebc
now points to new instance ofBookcase
The flow for using the class method is essentially the same:
bc = Bookcase.create_bookcase(title_auth_list)
create_bookcase
creates list ofBook
instances fromtitle_auth_list
, letโs call it โbook_listโcreate_bookcase
callscls(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.books
set tobook_list
__new__
which returns the created and initialized instancebc
now points to new instance ofBookcase