一篇文章搞懂Python的类与对象名称空间

论坛 期权论坛     
niminba   2021-5-22 18:59   33   0
<p><span style="color: #ff0000"><strong>代码块的分类</strong></span></p>
<p>python中分几种代码块类型,它们都有自己的作用域,或者说名称空间:</p>
<p>文件或模块整体是一个代码块,名称空间为全局范围<br>
</p>
<p>函数代码块,名称空间为函数自身范围,是本地作用域,在全局范围的内层</p>
<ul>
  <li>函数内部可嵌套函数,嵌套函数有更内一层的名称空间</li>
</ul>
<p>类代码块,名称空间为类自身</p>
<ul>
  <li>类中可定义函数,类中的函数有自己的名称空间,在类的内层</li>
  <li>类的实例对象有自己的名称空间,和类的名称空间独立</li>
  <li>类可继承父类,可以链接至父类名称空间</li>
</ul>
<p>正是这一层层隔离又连接的名称空间将变量、类、对象、函数等等都组织起来,使得它们可以拥有某些属性,可以进行属性查找。</p>
<p>本文详细解释类和对象涉及的名称空间,属于纯理论类的内容,有助于理解python面向对象的细节。期间会涉及全局和本地变量作用域的查找规则,如有不明白之处,可先看文章:<a href="https://www.jb51.net/article/152425.htm" rel="external nofollow" target="_blank">Python作用域详述</a></p>
<p><span style="color: #ff0000"><strong>一个概括全文的示例</strong></span></p>
<p>以下是一个能在一定程度上概括全文的示例代码段:</p>
<div class="blockcode">
<pre class="brush:py;">
x = 11 # 全局变量x

def f(): # 全局变量f
print(x) # 引用全局变量x

def g(): # 全局变量g
x = 22 # 定义本地变量x
print(x) # 引用本地变量x

class supcls(): # 全局变量supcls
x = 33 # 类变量x
def m(self): # 类变量m,类内函数变量self
x = 44 # 类内函数变量x
self.x = 55 # 对象变量x

class cls(supcls): # 全局变量cls
x = supcls.x # 引用父类属性x,并定义cls类属性x
def n(self): # 类变量n
self.x = 66 # 对象变量x</pre>
</div>
<p>如果能理解上面的每个x属于哪个作用域、哪个名称空间,本文内容基本上就理解了。</p>
<p><strong>类的名称空间</strong></p>
<p>下面有一个类,类中有类属性x、y,有类方法m和n。</p>
<div class="blockcode">
<pre class="brush:py;">
class supcls():
x = 3
y = 4

def m(self):
x = 33
self.x = 333
self.y = 444
self.z = 555

def n(self):
return self.x, self.y, self.z</pre>
</div>
<p>当python解释到supcls代码块后,知道这是一个类,类有自己的名称空间。所以,当知道了这个类里面有x、y、m、n后,这几个属性都会放进类supcls的名称空间中。</p>
<p>如下图:</p>
<p style="text-align: center"><img alt="" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-b5e2754590ed8574205c991d9f0de908.png"></p>
<p>在上图中,类的名称空间中有属性x、y、m和n,它们都称为类属性。需要说明的是,在python中,函数变量m、n和普通变量没什么区别,仅仅只是它保存了指向函数体的地址,函数体即上图中用func m和func n所表示的对象。</p>
<p>因为有名称空间,可以直接使用完全限定名称去访问这个名称空间中的内容。例如:</p>
<div class="blockcode">
<pre class="brush:py;">
print(supcls.x)
print(supcls.y)
print(supcls.m)
print(supcls.n)</pre>
</div>
<p>输出结果:</p>
<blockquote>
<p>3<br>
4<br>
&lt;function supcls.m at 0x02B83738&gt;<br>
&lt;function supcls.n at 0x02B836F0&gt;</p>
</blockquote>
<p>因为函数m和n也是类的属性,它们也可以直接通过类名来访问执行。例如,新加入一个函数,但不用self参数了,然后执行它。</p>
<div class="blockcode">
<pre class="brush:py;">
class testcls():
z = 3
def a():
x = 1
print(x)
# print(z) # 这是错的

testcls.a()</pre>
</div>
<p>但是需要注意,类方法代码块中看不见类变量。虽然类和类方法的作用域关系类似于全局作用域和函数本地作用域,但并不总是等价。例如,方法a()中无法直接访问类变量z。这就像类内部看不到全局变量一样。</p>
<p>上面全都是使用类名.属性这种完全限定名称去访问类中的属性的。如果生成类的对象,则可以通过对象去访问相关对象属性,因为对象有自己的名称空间,且部分属性来源于类。</p>
<p><span style="color: #ff0000"><strong>对象名称空间</strong></span></p>
<p>类就像一个模板,可以根据这个模板大量生成具有自己特性的对象。在Python中,只需像调用函数一样直接调用类就可以创建对象。</p>
<p>例如,下面创建了两个cls类的对象o1和o2,创建类的时候可以传递参数给类,这个参数可以传递给类的构造函数__init__()。</p>
<div class="blockcode">
<pre class="brush:py;">
o1 = cls()
o2 = cls("some args")</pre>
</div>
<p>对象有自己的名称空间。因为对象是根据类来创建的,类是它们的模板,所以对象名称空间中包含所有类属性,但是对象名称空间中这些属性的值不一定和类名称空间属性的值相同。</p>
<p>现在根据supcls类构造两个对象s1和s2:</p>
<div class="blockcode">
<pre class="brush:py;">
class s
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP