<p>尽管<code>classmethod</code>和<code>staticmethod</code>非常相似,但这两个实体的用法略有不同:<code>classmethod</code>必须将对类对象的引用作为第一个参数,而<code>staticmethod</code>则完全没有参数。</p>
<h2>示例</h2>
<pre><code>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')
</code></pre>
<h2>解释</h2>
<p>让我们假设一个类的例子,处理日期信息(这将是我们的样板文件):</p>
<pre><code>class Date(object):
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
</code></pre>
<p>这个类显然可以用来存储关于某些日期的信息(没有时区信息;假设所有日期都以UTC表示)。</p>
<p>这里有一个Python类实例的典型初始值设定项<code>__init__</code>,它以典型的<code>instancemethod</code>形式接收参数,第一个非可选参数(<code>self</code>)保存对新创建实例的引用。</p>
<p><strong>类方法</strong></p>
<p>我们有一些任务可以使用<code>classmethod</code>很好地完成</p>
<p><em>假设我们要创建许多类实例,其中的日期信息来自外部源,编码为格式为“dd-mm-yyy”的字符串。假设我们必须在项目的源代码中的不同位置执行此操作。</em></p>
<p>所以我们必须做的是:</p>
<ol>
<li>解析一个字符串,将日、月和年作为三个整数变量或由该变量组成的三项元组接收。</li>
<li>通过将这些值传递给初始化调用来实例化<code>Date</code>。</li>
</ol>
<p>这看起来像:</p>
<pre><code>day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)
</code></pre>
<P>为此,C++可以实现具有过载的特性,但Python没有这种重载。相反,我们可以使用<code>classmethod</code>。让我们创建另一个“<em>构造函数</em>”。</p>
<pre><code> @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')
</code></pre>
<p>让我们更仔细地看一下上面的实现,并回顾一下我们在这里有哪些优势:</p>
<ol>
<li>我们在一个地方实现了日期字符串解析,现在可以重用了。</li>
<li>封装在这里工作得很好(如果您认为可以在其他地方将字符串解析作为单个函数实现,那么这个解决方案更适合OOP范式)。</li>
<li><code>cls</code>是一个保存类本身的对象,而不是类的实例。这很酷,因为如果我们继承我们的<code>Date</code>类,所有的子类都将定义<code>from_string</code>。</li>
</ol>
<p><strong>静态方法</strong></p>
<p>那<code>staticmethod</code>呢?它与<code>classmethod</code>非常相似,但不接受任何必需的参数(就像类方法或实例方法那样)。</p>
<p>让我们看看下一个用例。</p>
<p><em>我们有一个日期字符串,我们想以某种方式验证它。这个任务在逻辑上也绑定到我们目前使用的<code>Date</code>类,但不需要实例化它。</em></p>
<p>这里是<code>staticmethod</code>有用的地方。让我们看下一段代码:</p>
<pre><code> @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')
</code></pre>
<p>因此,正如我们从<code>staticmethod</code>的用法中看到的,我们没有任何访问类的权限——它基本上只是一个函数,在语法上称为方法,但没有访问对象及其内部(字段和其他方法)的权限,而classmethod有。</p>