Python模块的显要特性:属性

模块的显要特性:属性

导入和重载提供了一种自然的程序启动的选择,因为导入操作将会在最后一步执行文件。从更宏观的角度来看,模块扮演了一个工具库的角色,这将在第五部分学到。从一般意义上来说,模块往往就是变量名的封装,被认作是命名空间。在一个包中的变量名就是所谓的属性:也就是说,属性就是绑定在特定的对象上的变量名(就像一个
模块)。

在典型的应用中,导入者得到了模块文件中在顶层所定义的所有变量名。这些变量名通常被赋值给通过模块函数、类、变量以及其他被导出的工具。这些往往都会在其他文件或程序中使用。表面上来看,一个模块文件的变量名可以通过两个Python语句读取—— import和from,以及reload调用。

为了讲清楚,请使用文本编辑器创建一个名为myfile.py的单行的Python模块文件,其内容如下所示:

 
 
  1. title = "The Meaning of Life" 

这也许是世界上最简单的Python模块文件之一了(它只包含了一行赋值语句),但是它已经足够讲明白基本的要点。当文件导入时,它的代码运行并生成了模块的属性。这个赋值语句创建了一个名为title的模块的属性。

可以通过两种不同的办法从其他组件获得这个模块的title属性。第一种,你可以通过使用一个import语句将模块作为一个整体载入,并使用模块名后跟一个属性名来获取它:

 
 
  1. % python# Start Python  
  2. >>> import myfile# Run file; load module as a whole  
  3. >>> print(myfile.title)# Use its attribute names: '.' to qualify  
  4. The Meaning of Life 

一般来说,这里的点号表达式代表了object.attribute的语法,可以从任何的object中取出其任意的属性,并且这是Python代码中的一个常用操作。在这里,我们已经使用了它去获取在模块myfile中的一个字符串变量title,即myfile.title。

作为替代方案,可以通过这样的语句从模块文件中获得(实际上是复制)变量名:

 
 
  1. % python# Start Python  
  2. >>> from myfile import title# Run file; copy its names  
  3. >>> print(title)# Use name directly: no need to qualify  
  4. The Meaning of Life 

就像今后看到的更多细节一样,from和import很相似,只不过增加了对载入组件的变量名的额外的赋值。从技术上讲,from复制了模块的属性,以便属性能够成为接收者的直接变量。因此,能够直接以title(一个变量)引用导入字符串而不是myfile.title(一个属性引用注3。

无论使用的是import还是from去执行导入操作,模块文件myfile.py的语句都会执行,并且导入的组件(对应这里是交互提示模式)在顶层文件中得到了变量名的读取权。也许在这个简单的例子中只有一个变量名(变量title被赋值给一个字符串),但是如果开始在模块中定义对象,例如,函数和类时,这个概念将会很有用。这样一些对象就变成了可重用的组件,可以通过变量名被一个或多个客户端模块读取。

在实际应用中,模块文件往往定义了一个以上的可被外部文件使用的变量名。下面这个例子中定义了三个变量名:

 
 
  1. a = 'dead'# Define three attributes  
  2. b = 'parrot'# Exported to other files  
  3. c = 'sketch' 
  4. print(a, b, c)# Also used in this file 

文件treenames.py,给三个变量赋值,并对外部世界生成了三个属性。这个文件并且在一个print语句中使用它自有的三个变量,就像在将其作为顶层文件运行时看到的结果一样:

 
 
  1. % python threenames.py  
  2. dead parrot sketch 

所有的这个文件的代码运行起来就和第一次从其他地方导入(无论是通过import或者from)后一样。这个文件的客户端通过import得到了具有属性的模块,而客户端使用from时,则会获得文件变量名的复本。

 
 
  1. % python  
  2. >>> import threenames# Grab the whole module  
  3. dead parrot sketch  
  4. >>> 
  5. >>> threenames.b, threenames.c  
  6. ('parrot', 'sketch')  
  7. >>> 
  8. >>> from threenames import a, b, c# Copy multiple names  
  9. >>> b, c  
  10. ('parrot', 'sketch') 

这里的结果打印在括号中,因为它们实际上是元组(本书的下一部分介绍的一种对象);目前我们可以暂时忽略它们。

一旦你开始就像这里一样在模块文件编写多个变量名,内置的dir函数开始发挥作用了。你可以使用它来获得模块内部的可用的变量名的列表。下面代码返回了一个Python字符串列表(我们将从下一章开始学习列表):

 
 
  1. >>> dir(threenames)  
  2. ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a', 'b', 'c'] 

我们在Python 3.0和Python 2.6中分别运行它,较早的Python可能返回较少的名字。当dir函数就像这个例子一样,通过把导入模块的名称传至括号里,进行调用后,它将返回这个模块内部的所有属性。其中返回的一些变量名是“免费”获得的:一些以双下划线开头并结尾的变量名,这些通常都是由Python预定义的内置变量名,对于解释器来说有特定的意义。那些通过代码赋值而定义的变量(a、b和c)在dir结果的最后显示。

模块和命名空间

模块导入是一种运行代码文件的方法,但是就像稍后我们即将在本书中讨论的那样,模块同样是Python程序最大的程序结构。

一般来说,Python程序往往由多个模块文件构成,通过import语句连接在一起。每个模块文件是一个独立完备的变量包,即一个命名空间。一个模块文件不能看到其他文件定义的变量名,除非它显式地导入了那个文件,所以模块文件在代码文件中起到了最小化命名冲突的作用。因为每个文件都是一个独立完备的命名空间,即使在它们拼写相同的情况下,一个文件中的变量名是不会与另一个文件中的变量冲突的。

实际上,就像你将看到的那样,正是由于模块将变量封装为不同部分,Python具有了能够避免命名冲突的优点。我们将会在本书后面章节讨论模块和其他的命名空间结构(包括类和函数的作用域)。就目前而言,模块是一个不需要重复输入而可以反复运行代码的方法。

注意:import VS from:我应该指出,from语句在某种意义上战胜了模块的名称空间分隔的目的,因为from把变量从一个文件复制到另一个文件,这可能导致在导入的文件中相同名称的变量被覆盖(并且,如果发生这种情况的话,不会为你给出警告)。这根本上会导致名称空间重叠到一起,至少在复制的变量上会重叠。

因此,有些人建议使用import而不是from。然而,我不建议这么做,不仅因为from更短,而且因为它传说中的问题在实际中几乎不是问题。此外,这是由你来控制的问题,可以在from中列出想要的变量;只要你理解它们将是要赋的值,这不会比编写赋值语句更危险,而赋值是你可能想要使用的另一功能。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值