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 trialWelby Obeng
20,340 Points@classmethod
Is @classmethod basically a way for you to call a method with initiating class?
What is the pros and cons in initiating it then calling method vs just calling method with @classmethod
6 Answers
Kenneth Love
Treehouse Guest TeacherWelby Obeng The main use of @[Akshay Nilangekar](https://teamtreehouse.com/cl0udkicker)
is to provide an alternate constructor. Consider this example:
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
If I want to create a person I have to know the first name and the last name of that person (apologies to all of the people whose names don't match this description). That sucks if I have some other way of getting names. Maybe they always come in as a string with both name pieces in the string.
I can split them up and then create the people. Sure. But maybe the class creator was nice and gave me a way of doing all at once.
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@classmethod
def from_string(cls, name_string):
names = name_string.split()
return cls(first_name=names[0], last_name=' '.join(names[1:]))
Now I can do Person.from_string('Kenneth Love')
and get back a Person
object. I don't have to do that splitting work in my own business logic and everyone is more-or-less happy.
Kenneth Love
Treehouse Guest TeacherThe basic reason to use @classmethod
instead of just a regular method is whether you want to have an instance before you call the method.
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def create(self, make=None, model=None, year=None):
return Car(make=make, model=model, year=year)
Say I have the above class. If I want to use the Car.create()
method, I have to have a car first.
>>> my_car = Car('subaru', 'forrester', 2005)
>>> another_car = my_car.create('chevy', 'focus', 2004)
>>> blank_car = Car.create('ford', 'taurus', 1998)
>>> blank_car.make
'taurus'
>>> blank_car.model
1998
That doesn't make a lot of sense, does it? Why would I create a car just so I can create a new car? And if I try to just use the method without an instance, all of the values are off by one. Let's make one small change.
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
@classmethod
def create(cls, make=None, model=None, year=None):
return cls(make=make, model=model, year=year)
We'll add @classmethod
to the method and changed self
to cls
. Due to how @classmethod
works, cls
now references the class (in this case, Car
) instead of the instance, which is what self
usually points to. I don't have to name it cls
, of course, but it's a naming convention. What happens if I use it?
>>> my_car = Car.create('subaru', 'forrester', 2005)
>>> my_car.make
'subaru'
>>> my_car.model
'forrester'
>>> my_car.year
2005
Hey, it worked right! And I didn't have to create an instance first.
Welby Obeng
20,340 PointsIn the first code example above, why not just create a new car by initiating a class? and not use the “create” method at all? Like
my_car1 = Car('subaru', 'forrester', 2005)
my_car2 = Car('chevy', 'focus', 2004)
etc
Also In the first code example how come you said :
return Car(make=make, model=model, year=year)
and not
return self.Car(make=make, model=model, year=year)
Kenneth Love
Treehouse Guest TeacherThis example doesn't show it, but imagine you had a class that you always wanted created through a particular workflow. You wouldn't necessarily want it just created directly from the class. Or maybe it's just more convenient through that method.
For the second question, there's no such thing as self.Car
. self
is the instance, a Car
object, and an instance doesn't have an attribute of it's class. You could do self.__class__
but that still requires an instance. The point of @classmethod
is to not have an instance first.
Welby Obeng
20,340 PointsI'm still confused about the class method :(
I have read almost every article on google but it's still vague...
Kenneth Love
Treehouse Guest TeacherHonestly, most of the time, you won't need @classmethod
or @staticmethod
so don't worry too much about cementing them in your Python understanding just yet. You'll generally start to see where they're useful as you write more and more code.
That said, how can I help you understand it better? What parts, specifically, are still fuzzy?
Welby Obeng
20,340 PointsCan you give me one more real world example where I will typically do it the messy way and how it can be improved with class method with explanation pleaseeeeeee?
Thanks
Iain Simmons
Treehouse Moderator 32,305 PointsI believe it's more about how the method is attached to the class. With the @classmethod
decorator, all instances of the class (and of inherited classes) can use it, and it is run in the context of the class itself, not the instance of the class.
It's a particularly confusing topic. Here's a fairly in-depth article that attempts to explain it all: The definitive guide on how to use static, class or abstract methods in Python
Welby Obeng
20,340 Pointsahh I see, it's starting to make sense.
Does this mean that Person object that you just created will inherit from_string method? Like this
welby = Person.from_string('Welby Obeng') and I can use welby object to create another person like this kenneth = welby.Person.from_string('Kenneth Love') ?
Kenneth Love
Treehouse Guest Teacherwelby
doesn't have a Person
attribute, so no.
Welby Obeng
20,340 Pointssorry I meant:
welby = Person.from_string('Welby Obeng') and I can use welby object to create another person like this
kenneth = welby.from_string('Kenneth Love') ?
Kenneth Love
Treehouse Guest TeacherThat should work, yes. Since it's a @classmethod
, it should know to peel the class off of the instance and use that to run the method.
Welby Obeng
20,340 Pointsperfect...I get it now...
Welby Obeng
20,340 PointsThis means that the blueprint to create an instance is given to the instance when you use @classmethod?
Kenneth Love
Treehouse Guest TeacherWell, the instance has a class and the class has this special constructor, so, yes. But instances always have access to their class and every class has an __init__
method, so they always have the ability to create a new instance if you go down the right path.
Y B
14,136 PointsI'm fairly comfortable with @classmethod and what it does, but I can't see it's use case, (other than possibly counting instances of the class that have been created).
In your car example here wouldn't you just create the class with the init constructer and amend that as needed. Using this we can create an instance without having to create another instance first.
Perhaps this can be done (and is normally) and as per your comment, @classmethod is only used in the construction of a class when we are restricted to a particular workflow.
In the example in the course could we just remove the create_user() method and replace it with an init()?
Kenneth Love
Treehouse Guest Teacher@classmethod
, especially in this example, comes in handy when you need a different constructor. I want to be able to create User
objects through their __init__
, or normally, if needed. Maybe I need a fake User
for something or maybe I just want to leave it alone just in case. Since I've created this @classmethod
for creating users with a specific workflow, I can have both options all of the time.
Y B
14,136 PointsThanks Kenneth that's helps to make it clearer
Iain Simmons
Treehouse Moderator 32,305 PointsIain Simmons
Treehouse Moderator 32,305 PointsHi Kenneth Love, I think your answer might have picked up the
@
symbol and converted it to a Treehouse user mention... I assume you were trying to write@classmethod
.