user10200421
user10200421

Reputation: 217

Adding a classmethod

I wrote the following code which runs correctly:

import math

class Point:
    """Two-Dimensional Point(x, y)"""
    def __init__(self, x=0, y=0):
        # Initialize the Point instance
        self.x = x
        self.y = y

    def __iter__(self):
         yield self.x
         yield self.y

    def __add__(self, other):
        addedx = self.x + other.x
        addedy = self.y + other.y
        return Point(addedx, addedy)

    def __mul__(self, other):
        mulx = self.x * other
        muly = self.y * other
        return Point(mulx, muly)

    def __rmul__(self, other):
        mulx = self.x * other
        muly = self.y * other
        return Point(mulx, muly)

    @classmethod
    def from_tuple(


    @property
    def magnitude(self):
        # """Return the magnitude of vector from (0,0) to self."""
        return math.sqrt(self.x ** 2 + self.y ** 2)


    def distance(self, self2):
         return math.sqrt((self2.x - self.x) ** 2 + (self2.y - self.y) ** 2)

    def __str__(self):
        return 'Point at ({}, {})'.format(self.x, self.y)

    def __repr__(self):
        return "Point(x={},y={})".format(self.x, self.y)

I want to add a @classmethod called from_tuple to the Point class that allows creation of Point instances from a tuple containing the x and y values. I want to make it so the tuple input is required. I am lost on the syntax of how to do something like this. The following is the expected output:

location = 2, 3
print(location)
    (2, 3)
point = Point.from_tuple(location)
print(point)
    Point(x=2, y=3)
point = Point.from_tuple()
Traceback (most recent call last):
[...]
TypeError: from_tuple() missing 1 required positional argument: 'coords'

Upvotes: 0

Views: 68

Answers (2)

abarnert
abarnert

Reputation: 365667

A classmethod is very similar to an instance method, except that:

  • You can call it on the class itself without getting an "unbound method" that needs an extra argument, and
  • Whether you call it on the class itself or on an instance, you get the class object as your first parameter.

Traditionally, you name that parameter cls. So:

@classmethod
def from_tuple(cls, tup):
    x, y = tup
    return cls(x, y)

You may be wondering why you need cls at all here. After all, couldn't you just write this as a staticmethod?

@staticmethod
def from_tuple(tup):
    x, y = tup
    return Point(x, y)

Yes, you can—but that doesn't play nice with inheritance. If I make a subclass of Point, and call MyPoint.from_tuple(2, 3), I'd expect to get a MyPoint back, not a Point. By using a classmethod and constructing an instance of cls instead of hardcoding Point, I get a MyPoint, because cls is MyPoint.

Upvotes: 3

blue note
blue note

Reputation: 29071

It's just

@classmethod
def from_tuple(cls, location):
    return cls(*location)

Upvotes: 3

Related Questions