Python中 的 @classmethod 和 @staticmethod

star2017 1年前 ⋅ 3779 阅读

Python 是一种独特的编程语言,它语法简洁、易于学习,功能却非常强大。Python 有很多进阶用法,今天我们来聊聊装饰 @classmethod@staticmethod。可能在我们的很多项目中可能用不到,但在了解了这些之后可以使我们的开发变得更加高效。如何创建Python静态方法并不明显,这就是这两个装饰器的用武之地。

本文会讲讲每个装饰器的作用以及它们的不同之处,并会给一些示例。

@classmethod 装饰器

有了这个装饰器,我们就可以创建在函数调用中传递实际类对象的类方法,就像 self 传递给类中任何其他普通实例方法一样。

在对象的实例方法中,self 参数是类实例对象本身,我们可以用它来对实例数据进行一些操作。@classmethod 方法也有一个强制性的第一个参数,它表示的是未实例化的类本身,而非类的实例。

我们来看一个典型的类方法的用法:

class Student(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

scott = Student('Scott',  'Robinson')

如果我们用 @classmethod 的话就可以这样表示:

class Student(object):

    @classmethod
    def from_string(cls, name_str):
        first_name, last_name = map(str, name_str.split(' '))
        student = cls(first_name, last_name)
        return student

scott = Student.from_string('Scott Robinson')  

这样就很好地遵循了静态工厂模式,将解析逻辑封装在方法本身内部。如此我们的代码就有了更丰富的表达能力,它便可以处理多种格式来源的数据统一解析成我们的的对象了:

class Student(object):

    @classmethod
    def from_string(cls, name_str):
        first_name, last_name = map(str, name_str.split(' '))
        student = cls(first_name, last_name)
        return student

    @classmethod
    def from_json(cls, json_obj):
        # parse json...
        return student

    @classmethod
    def from_pickle(cls, pickle_file):
        # load pickle file...
        return student

当在子类中实现这些方法时,装饰器将会变得更加有用。

@staticmethod 装饰器

@staticmethod 装饰类似于@classmethod ,它能够从一个非实例类对象被调用,但是没有传递 cls 参数。我们来看一个例子:

class Student(object):

    @staticmethod
    def is_full_name(name_str):
        names = name_str.split(' ')
        return len(names) > 1

Student.is_full_name('Scott Robinson')   # True  
Student.is_full_name('Scott')            # False  

由于没有 self 传递任何对象,这意味着此装饰器方法无法访问任何实例数据,并且也无法在实例化对象上调用此方法。

这些类型的方法通常不是为了创建/实例化对象,它们是为了处理一些与类本身有关的逻辑。

@classmethod vs @staticmethod

这些装饰器之间最明显的事情是它们能够在类中创建静态方法,可以在未实例化的类对象上调用这些类型的方法,就像在 Java 中使用关键字 static 的类一样。

这两个方法装饰器之间实际上只有一个区别。在上文对这两种装饰器的介绍中我们可以发现,@classmethod方法有一个cls参数会传递到他们的方法中,而@staticmethod方法没有。

这个cls参数是我们讨论过的类对象,它允许@classmethod方法方便地实例化类。而方法中缺少cls参数的@staticmethod是真正传统意义上的静态方法。它们的主要目的是处理包含与类有关的逻辑,并且该逻辑类实例数据无关。

一个完整的例子

现在让我们看另一个例子,在同一个类中同时使用这两种类型:

# static.py

class ClassGrades:

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

    @classmethod
    def from_csv(cls, grade_csv_str):
        grades = list(map(int, grade_csv_str.split(', ')))
        cls.validate(grades)
        return cls(grades)


    @staticmethod
    def validate(grades):
        for g in grades:
            if g < 0 or g > 100:
                raise Exception()

try:  
    # Try out some valid grades
    class_grades_valid = ClassGrades.from_csv('90, 80, 85, 94, 70')
    print('Got grades:', class_grades_valid.grades)

    # Should fail with invalid grades
    class_grades_invalid = ClassGrades.from_csv('92, -15, 99, 101, 77, 65, 100')
    print(class_grades_invalid.grades)
except:  
    print('Invalid!')

执行

$ python static.py
Got grades: [90, 80, 85, 94, 70]  
Invalid!

可以好好体会下两者的用法哦。

更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: