class:Python类方法的一个用例是什么?

我读过Python中的类方法是做什么的?但那篇文章中的例子很复杂。我正在寻找一个清晰、简单、基本的例子,说明Python中类方法的特定用例。

您能举出一个小型的、特定的用例吗?


初始化的助手方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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):
       ...


__new__是一个非常重要的类方法。它通常是实例的来源

因此,dict()当然调用dict.__new__,但有时还有另一种方便的方法来进行dicts,那就是classmethod dict.fromkeys()

如。

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


比如命名构造函数方法?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class UniqueIdentifier(object):

    value = 0

    def __init__(self, name):
        self.name = name

    @classmethod
    def produce(cls):
        instance = cls(cls.value)
        cls.value += 1
        return instance

class FunkyUniqueIdentifier(UniqueIdentifier):

    @classmethod
    def produce(cls):
        instance = super(FunkyUniqueIdentifier, cls).produce()
        instance.name ="Funky %s" % instance.name
        return instance

用法:

1
2
3
4
5
6
>>> x = UniqueIdentifier.produce()
>>> y = FunkyUniqueIdentifier.produce()
>>> x.name
0
>>> y.name
Funky 1

我发现,在不需要类的实例来使用代码的情况下,我最常使用@classmethod将一段代码与类关联起来,以避免创建全局函数。

例如,我可能有一个数据结构,它只在键符合某种模式时才认为键是有效的。我可能会在课堂内外用到它。但是,我不想再创建另一个全局函数:

1
2
3
def foo_key_is_valid(key):
    # code for determining validity here
    return valid

我更愿意将这段代码与它关联的类进行分组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo(object):

    @classmethod
    def is_valid(cls, key):
        # code for determining validity here
        return valid

    def add_key(self, key, val):
        if not Foo.is_valid(key):
            raise ValueError()
        ..

# lets me reuse that method without an instance, and signals that
# the code is closely-associated with the Foo class
Foo.is_valid('my key')


使用@classmethod的最大原因是在打算继承的替代构造函数中。这在多态性中非常有用。一个例子:

1
2
3
4
5
6
7
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派生自己,所以它只返回该类的一个默认实例。

然后允许继承的类定义它们自己的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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)

这种用法允许您多态地处理所有这些未实例化的类

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

您可能会说这一切都很好,但是为什么我不能使用as @staticmethod来完成相同的多态行为:

1
2
3
4
5
6
7
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逻辑时,得到了什么:

1
2
3
4
5
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并返回适当的形状。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
in class MyClass(object):
    '''
    classdocs
    '''

    obj=0
    x=classmethod
    def __init__(self):
        '''
        Constructor
        '''

        self.nom='lamaizi'
        self.prenom='anas'
        self.age=21
        self.ville='Casablanca'
if __name__:
    ob=MyClass()
    print(ob.nom)
    print(ob.prenom)
    print(ob.age)
    print(ob.ville)