Python类方法的例子是什么?

84 投票
7 回答
47893 浏览
提问于 2025-04-16 16:08

我看过Python中的类方法有什么用?这篇文章,但里面的例子太复杂了。我想找一个简单明了、基础的例子,来说明在Python中类方法的具体用法。

你能举一个小而具体的例子,说明在什么情况下使用Python的类方法是最合适的吗?

7 个回答

21

使用 @classmethod 的最大原因之一是为了创建一个可以被继承的备用构造函数。这在多态性中非常有用。举个例子:

class Shape(object):
    # this is an abstract class that is primarily used for inheritance defaults
    # here is where you would define classmethods that can be overridden by inherited classes
    @classmethod
    def from_square(cls, square):
        # return a default instance of cls
        return cls()

注意,Shape 是一个抽象类,它定义了一个类方法 from_square。因为 Shape 本身并没有具体的定义,所以它不知道如何从一个 Square 生成自己,因此它只是返回一个默认的类实例。

继承这个类的其他类可以定义自己的这个方法版本:

class Square(Shape):
    def __init__(self, side=10):
        self.side = side

    @classmethod
    def from_square(cls, square):
        return cls(side=square.side)


class Rectangle(Shape):
    def __init__(self, length=10, width=10):
        self.length = length
        self.width = width

    @classmethod
    def from_square(cls, square):
        return cls(length=square.side, width=square.side)


class RightTriangle(Shape):
    def __init__(self, a=10, b=10):
        self.a = a
        self.b = b
        self.c = ((a*a) + (b*b))**(.5)

    @classmethod
    def from_square(cls, square):
        return cls(a=square.length, b=square.width)


class Circle(Shape):
    def __init__(self, radius=10):
        self.radius = radius

    @classmethod
    def from_square(cls, square):
        return cls(radius=square.length/2)

这样做的好处是,你可以把这些未实例化的类当作多态的对象来处理。

square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle):
    this_shape = polymorphic_class.from_square(square)

你可能会说,这样做很好,但为什么我不能用 @staticmethod 来实现同样的多态行为呢:

class Circle(Shape):
    def __init__(self, radius=10):
        self.radius = radius

    @staticmethod
    def from_square(square):
        return Circle(radius=square.length/2)

答案是,你可以这样做,但你就无法享受到继承的好处,因为在方法中必须明确调用 Circle。这意味着如果我从一个继承的类中调用这个方法而没有重写它,我每次得到的仍然是 Circle

看看当我定义另一个形状类,而这个类并没有任何自定义的 from_square 逻辑时,会有什么收获:

class Hexagon(Shape):
    def __init__(self, side=10):
        self.side = side

    # note the absence of classmethod here, this will use from_square it inherits from shape

在这里,你可以不定义 @classmethod,它会使用 Shape.from_square 的逻辑,同时保留 cls 的身份,并返回适当的形状。

square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle, Hexagon):
    this_shape = polymorphic_class.from_square(square)
34

其实,__new__ 是一个非常重要的类方法。它是用来创建实例的地方。

所以,当你使用 dict() 时,它实际上是在调用 dict.__new__,当然了。不过,还有一种很方便的方法可以创建字典,那就是使用类方法 dict.fromkeys()

比如:

>>> dict.fromkeys("12345")
{'1': None, '3': None, '2': None, '5': None, '4': None}
62

初始化的辅助方法:

class MyStream(object):

    @classmethod
    def from_file(cls, filepath, ignore_comments=False):    
        with open(filepath, 'r') as fileobj:
            for obj in cls(fileobj, ignore_comments):
                yield obj

    @classmethod
    def from_socket(cls, socket, ignore_comments=False):
        raise NotImplemented # Placeholder until implemented

    def __init__(self, iterable, ignore_comments=False):
       ...

撰写回答