Why use @classmethod?

Posted on Jul 20, 2017 by doesitmatter

Why use @classmethod?

本文从一个网站转载,做了适应 CSDN blog 的排版。
原文点击标题 ​? 即可进入。

In the video Kenneth says that you do not want to pass a mutable argument as an argument when initializing the class. I don’t get why?

class Book:

    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return "{} by {}".format(self.title, self.author)


class BookCase:

    def __init__(self, books=None):
        self.books = books

    @classmethod
    def create_bookcase(cls, books):
        list_of_books = []

        for t, a in books:
            list_of_books.append(Book(t, a))

        return cls(list_of_books)

my_bookcase = BookCase([Book("Alice In Wonderland", "Lewis Carroll"),
                        Book("Sherlock Holmes", "Arthur Conan Doyle"),
                        Book("The Stranger", "Albert Camus")])

for i in my_bookcase.books:
    print(i)

my_bookcase_2 = BookCase.create_bookcase([("Alice In Wonderland", "Lewis Carroll"), 
                                          ("Sherlock Holmes", "Arthur Conan Doyle"), 
                                          ("The Stranger", "Albert Camus")])

for i in my_bookcase_2.books:
    print(i)

In the code above I achieve the exact same thing with my_bookcase as with my_bookcase_2 which uses the create_bookcase classmethod, so what is the point of using a classmethod?

And finally, why is books = None used instead of just books inside of the init()?

class BookCase:

    def __init__(self, books=None):
        self.books = books

3 Answers


Chris FreemanMOD
from Chris Freeman
on Jul 25, 2017

In this case, it is possible to do without the classmethod. The lesson is about the general use of classmethods and simple examples might seem contrived or trivially bypassed. In a more complicated example, the create_bookcase classmethod might provide more validation of the incoming books or add other attributes that might not be obvious outside of the Book class…

The books=None allows someone to create a bookcase instance without any supplied books. Since books is used in the init code, it needs to have a default value or it will raise a NameError.

Post back if you have more questions!


Pete P
from Pete P
on Feb 19

Based off of your answer, I’m wondering if this would be an example of where classmethods should be used.

Let’s say I have a class that takes a file name as an argument. This file name could refer to a text file, excel file, or csv file. I need to perform different operations and set attributes differently based upon the type of file that is passed to the class.

So, rather than doing something like in this pseudo code:

class Thingy:
    def __init__(self, filename):
        if filename is txtfile:
            # validate file exists
            # read file
            # set attributes 
        elif filename is excel_file:
            # validate file exists
            # parse file / create pandas dataframe
            # get some data
            # set attributes
        else:
            # validate file exists
            # read in the csv
            # set attributes

I could (should?) define classmethods to handle each file type

class Thingy:

    @classmethod
    def data_from_txtfile(cls, file):
            # validate file exists
            # read file
            # set attributes
    @classmethod
    def data_from_excelfile(cls, file):
            # validate file exists
            # parse file / create pandas dataframe
            # get some data
            # set attributes
    @classmethod
    def data_from_csvfile(cls, file):
            # validate file exists
            # do stuff to the csv
            # set attributes

Or am I way off? Thanks for all of your help!


Chris Freeman
from Chris Freeman
on Feb 19

Great follow-up question! It’s helped me think more about how I would decide when to use a classmethod over an instance method. I came to this conclusion:

If a classmethod is intended to operate on the class and a regular instance method is intended to operate on an instance of the class, then a classmethod is best used to for functionality associated with the class, but that would not be useful if applied to an existing instance of a class. One example is helping construct specific classes instances.`

So in your example, I would have the init method create the class from a data set and use the classmethods to prep the data set used by the init method. Restructure it more like:

class Thingy:
    def __init__(self, data=None):
        # set attributes based on data

    @classmethod
    def data_from_txtfile(cls, file):
        # validate file exists
        # data = data read from file
        # return instance of class created from data
        return cls(data=data)

    @classmethod
    def data_from_excelfile(cls, file):
        # validate file exists
        # parse file / create pandas dataframe
        # data = some data from parse or dataframe
        # return instance of class created from data
        return cls(data=data)

    @classmethod
    def data_from_csvfile(cls, file):
        # validate file exists
        # do stuff to the csv
        # data = some data from csv file
        # return instance of class created from data
        return cls(data=data)

This StackOverflow question lists other examples on where classmethods are useful.

Hope this makes sence. As always, post back as needed!


Pete P
from Pete P
on Feb 19

Makes sense. Completely cleared up my confusion. Thanks again!


Aaron Banerjee
from Aaron Banerjee
on Mar 18

Chris Freeman, so does the __init__ method interact with the class method to instantiate the data in the example above?


Chris Freeman
Chris Freeman
on Jul 1

The final statement in the class method is of the form

return cls(data)
It is this call within the class method that instantiates the class and subsequently calls the __init__ method.


Huston Petty
from Huston Petty
on Jul 1

A better example, like the one above by Chris, needs to be used in the video. The one in the video is confusingly simple. I struggled for like 10 minutes to understand WHY you would want to create a class method that appeared to do exactly what __init__ would do. I kept asking myself “Why not just put all of that in the __init__?!”. Maybe the video example just needs to show a few different class methods to show why they are useful. Like, a create_bookcase vs create_sorted_by_author_bookcase vs create_sorted_by_title_bookcase. Just a thought.


Chris Freeman
Chris Freeman
on Jul 1

Nice feedback! Tagging Craig Dennis


Craig Dennis
from Craig Dennis
on Jul 3

Thanks Chris Freeman and Huston Petty ! Added to refresh notes!



发布了164 篇原创文章 · 获赞 76 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_29757283/article/details/84778784
今日推荐