这个装饰器存在,因此您可以创建在函数调用中传递实际类对象的类方法,就像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')
这很好地遵循静态工厂模式,将解析逻辑封装在方法本身内部。
上面的示例非常简单,但您可以想象更复杂的示例,使其更具吸引力。想象一下,如果一个Student
对象可以被序列化为多种不同的格式。您可以使用相同的策略来解析它们:
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
当您在子类中实现其有用性时,装饰器变得更加有用。由于类对象是在方法中给出的,因此您仍然可以@classmethod
对子类使用相同的对象。
所述@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
传递任何对象,这意味着我们也无法访问任何实例数据,因此也无法在实例化对象上调用此方法。
这些类型的方法通常不是为了创建/实例化对象,但它们可能包含某些与类本身有关的逻辑,如助手或实用程序方法。
这些装饰器之间最明显的事情是它们能够在类中创建静态方法。可以在未实例化的类对象上调用这些类型的方法,就像static
在Java中使用关键字的类一样。
这两个方法装饰器之间实际上只有一个区别,但它是一个主要的区别。您可能在上面的部分中注意到,@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 = 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!
注意静态方法如何与使用对象from_csv
调用一起工作。运行上面的代码应打印出一系列有效等级,然后在第二次尝试时失败,从而打印出“无效!”。validate
cls
在本文中,您了解了装饰器@classmethod
和@staticmethod
装饰器在Python中的工作原理,每个装置的实例以及它们之间的区别。希望现在您可以将它们应用到您自己的项目中并使用它们来继续提高您自己的代码的质量和组织。
您以前曾经使用过这些装饰器,如果是的话,怎么样?让我们在评论中知道!