<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="http://itecfun.com/extern.php?action=feed&amp;tid=52&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[个人知识管理站 / Python的静态方法和类成员方法]]></title>
		<link>http://www.itecfun.com/viewtopic.php?id=52</link>
		<description><![CDATA[Python的静态方法和类成员方法 最近发表的帖子。]]></description>
		<lastBuildDate>Fri, 30 Jan 2015 06:46:56 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[Python的静态方法和类成员方法]]></title>
			<link>http://www.itecfun.com/viewtopic.php?pid=120#p120</link>
			<description><![CDATA[<p>Python的静态方法和类成员方法都可以被类或实例访问，两者概念不容易理清，但还是有区别的：<br />1）静态方法无需传入self参数，类成员方法需传入代表本类的cls参数；<br />2）从第1条，静态方法是无法访问实例变量的，而类成员方法也同样无法访问实例变量，但可以访问类变量；<br />3）静态方法有点像函数工具库的作用，而类成员方法则更接近类似Java面向对象概念中的静态方法。</p><p><strong>实现静态方法和类方法的两种方式</strong></p><p><strong>一、在Python 2.3及之前，用staticmethod和classmethod类型对象包装实现</strong><br />例子如下（注意print里的说明）：<br />class MyClass:<br />&#160; &#160; val1 = &#039;Value 1&#039;<br />&#160; &#160; def __init__(self):<br />&#160; &#160; &#160; &#160; self.val2 = &#039;Value 2&#039;<br />&#160; &#160; def staticmd():<br />&#160; &#160; &#160; &#160; print &#039;静态方法，无法访问val1和val2&#039;<br />&#160; &#160; smd = staticmethod(staticmd)</p><p>&#160; &#160; def classmd(cls):<br />&#160; &#160; &#160; &#160; print &#039;类方法，类：&#039; + str(cls) + &#039;，val1：&#039; + cls.val1 + &#039;，无法访问val2的值&#039;<br />&#160; &#160; cmd = classmethod(classmd)</p><p>执行：<br />&gt;&gt;&gt; mc = MyClass()<br />&gt;&gt;&gt; mc.smd()<br />&gt;&gt;&gt; mc.cmd()<br />&gt;&gt;&gt; MyClass.smd()<br />&gt;&gt;&gt; MyClass.cmd()</p><p><strong>二、在Python 2.4及之后，用装饰器（decorators）实现</strong><br />装饰器使用@操作符，例子如下：<br />class MyClass:<br />&#160; &#160; val1 = &#039;Value 1&#039;<br />&#160; &#160; def __init__(self):<br />&#160; &#160; &#160; &#160; self.val2 = &#039;Value 2&#039;</p><p>&#160; &#160; @staticmethod<br />&#160; &#160; def staticmd():<br />&#160; &#160; &#160; &#160; print &#039;静态方法，无法访问val1和val2&#039;</p><p>&#160; &#160; @classmethod<br />&#160; &#160; def classmd(cls):<br />&#160; &#160; &#160; &#160; print &#039;类方法，类：&#039; + str(cls) + &#039;，val1：&#039; + cls.val1 + &#039;，无法访问val2的值&#039;</p><p>不管是以上两种方式中的哪一种，执行情况都是一样的，以方式二执行结果为例分析如下：<br />执行：<br />&gt;&gt;&gt; mc = MyClass()&#160; # 实例化</p><p>&gt;&gt;&gt; mc.staticmd()&#160; # 实例调用静态方法，无法访问实例变量val1和val2<br />&gt;&gt;&gt; <br />静态方法，无法访问val1和val2</p><p>&gt;&gt;&gt; mc.classmd()&#160; # 实例调用类方法，注意，这里访问的是类MyClass的变量val1的值，不是实例化后mc的实例变量val1，这里容易混淆，往下看就会明白。val2一直是实例变量，所以无法访问<br />&gt;&gt;&gt; <br />类方法，类：__main__.MyClass，val1：Value 1，无法访问val2的值</p><p>&gt;&gt;&gt; MyClass.staticmd()&#160; # 类直接调用静态方法，结果同上面的实例调用，无论是类变量还是实例变量都无法访问<br />&gt;&gt;&gt; <br />静态方法，无法访问val1和val2</p><p>&gt;&gt;&gt; MyClass.classmd()&#160; # 类直接调用类方法，结果同上面的实例调用<br />&gt;&gt;&gt; <br />类方法，类：__main__.MyClass，val1：Value 1，无法访问val2的值</p><p>&gt;&gt;&gt; mc.val1 = &#039;Value changed&#039;&#160; # 改变实例变量val1的值</p><p>&gt;&gt;&gt; mc.classmd()&#160; # 实例调用类方法，注意到cls.val1的值没变，所以，这时的cls.val1是类变量val1，而非实例变量val1<br />&gt;&gt;&gt; <br />类方法，类：__main__.MyClass，val1：Value 1，无法访问val2的值</p><p>&gt;&gt;&gt; MyClass.classmd()&#160; # 类直接调用类方法，结果同上面的实例调用<br />&gt;&gt;&gt; <br />类方法，类：__main__.MyClass，val1：Value 1，无法访问val2的值</p><p>&gt;&gt;&gt; MyClass.val1 = &#039;Class Value changed&#039;&#160; # 改变类变量val1的值</p><p>&gt;&gt;&gt; mc.classmd()&#160; # 实例调用类方法，注意到cls.val1的值变了，所以，进一步证明了这时的cls.val1是类变量val1，而非实例变量val1<br />&gt;&gt;&gt; <br />类方法，类：__main__.MyClass，val1：Class Value changed，无法访问val2的值</p><p>&gt;&gt;&gt; MyClass.classmd()&#160; # 类直接调用类方法，结果同上面的实例调用<br />&gt;&gt;&gt; <br />类方法，类：__main__.MyClass，val1：Class Value changed，无法访问val2的值</p><p><strong>结论</strong><br />如果上述执行过程太复杂，记住以下两点就好了：<br />静态方法：无法访问类属性、实例属性，相当于一个相对独立的方法，跟类其实没什么关系，换个角度来讲，其实就是放在一个类的作用域里的函数而已。<br />类成员方法：可以访问类属性，无法访问实例属性。上述的变量val1，在类里是类变量，在实例中又是实例变量，所以容易混淆。</p>]]></description>
			<author><![CDATA[dummy@example.com (xuyg)]]></author>
			<pubDate>Fri, 30 Jan 2015 06:46:56 +0000</pubDate>
			<guid>http://www.itecfun.com/viewtopic.php?pid=120#p120</guid>
		</item>
	</channel>
</rss>
