当前位置:   article > 正文

三分钟透彻理解Python中的@staticmethod和@classmethod_pytorch中定义网络时的@staticmethod

pytorch中定义网络时的@staticmethod

三分钟透彻理解Python中的@staticmethod和@classmethod

这篇博文主要讲解以下问题:

@classmethod和@staticmethod在Python中是什么意思,它们有何区别?我应该在何时使用它们,为什么要使用它们,以及如何使用它们?

@classmethod告诉一个类,这是一个应该被子类继承的方法,或者某种程度上是这样。然而,这样做的目的是什么呢?为什么不直接定义类方法,而不添加@classmethod、@staticmethod或任何@定义呢?

引入

虽然@classmethod和@staticmethod非常相似,但它们在用法上有轻微的区别:classmethod必须将一个类对象的引用作为第一个参数,而staticmethod可以不带任何参数

Example:

class Date(object):
    
    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = year

    @classmethod
    def from_string(cls, date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        date1 = cls(day, month, year)
        return date1

    @staticmethod
    def is_date_valid(date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        return day <= 31 and month <= 12 and year <= 3999

date2 = Date.from_string('11-09-2012')
is_date = Date.is_date_valid('11-09-2012')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

Explanation:
让我们假设一个处理日期信息的类的示例(这将是我们的模板):

class Date(object):
    
    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = year
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个类显然可以用来存储关于特定日期的信息(不包含时区信息;让我们假设所有日期都以UTC时区表示)。

这里有一个__init__,是Python类实例的典型初始化方法,它接收参数作为典型的实例方法,第一个非可选参数(self)用于保存对新创建实例的引用。

Class Method

有些任务可以很好地使用classmethod完成。

假设我们想要创建大量的Date类实例,这些实例包含来自外部源的日期信息,以字符串格式 ‘dd-mm-yyyy’ 编码。假设我们在项目源代码的不同位置都需要执行这个操作。

因此,在这里我们需要做的是:

1、解析字符串以获取日期、月份和年份,将它们作为三个整数变量或一个包含这些变量的3项元组。
2、通过将这些值传递给初始化调用来实例化Date类。
这将看起来像这样:

day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)
  • 1
  • 2

为了实现这个目的,C++可以通过重载来实现这样的特性,但Python缺乏这种重载功能。相反,我们可以使用classmethod。让我们创建另一个构造函数。

    @classmethod
    def from_string(cls, date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        date1 = cls(day, month, year)
        return date1

date2 = Date.from_string('11-09-2012')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

让我们仔细看一下上面的实现,并回顾一下这里的优点:

  1. 我们在一个地方实现了日期字符串的解析,并且现在可以重复使用它。
  2. 封装在这里运作良好(如果您认为您可以在其他地方将字符串解析实现为一个单独的函数,那么这个解决方案更符合面向对象编程范式)。
  3. cls 代表的是类本身,而不是类的实例。这相当酷,因为如果我们继承了我们的 Date 类,所有的子类也都会有 from_string 方法。

Static Method

那么staticmethod呢?它与classmethod非常相似,但不需要任何必须的参数(就像类方法或实例方法那样)。

让我们看下一个使用情景。

我们有一个日期字符串,我们想要以某种方式对其进行验证。这个任务在逻辑上也与我们迄今使用的Date类相关,但不需要对其进行实例化。

这正是staticmethod可以派上用场的地方。让我们来看下面的代码片段:

    @staticmethod
    def is_date_valid(date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        return day <= 31 and month <= 12 and year <= 3999

# usage:
is_date = Date.is_date_valid('11-09-2012')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

因此,从使用staticmethod的情况可以看出,我们无法访问类的内容——它基本上只是一个函数,从语法上看像是一个方法,但没有访问对象及其内部(字段和其他方法)的权限,而classmethod却有这种权限。

如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。也就是说在classmethod中可以调用类中定义的其他方法、类的属性,但staticmethod只能通过A.a调用类的属性,但无法通过在该函数内部调用A.foo2()。用代码加以说明:

class A(object):
    a = 'a'
    @staticmethod
    def foo1(name):
        print 'hello', name
        print A.a # 正常
        print A.foo2('mamq') # 报错: unbound method foo2() must be called with A instance as first argument (got str instance instead)
    def foo2(self, name):
        print 'hello', name
    @classmethod
    def foo3(cls, name):
        print 'hello', name
        print A.a
        print cls().foo2(name)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/716515
推荐阅读
相关标签
  

闽ICP备14008679号