在Python中有多种运行外部程序的方法,比如,运行操作系统命令或另外的Python脚本,或执行一个磁盘上的文件,或通过网络来运行文件。这完全取决于想要干什么。特定的环境包括:
  在当前脚本继续运行
  创建和管理子进程
  执行外部命令或程序
  执行需要输入的命令
  通过网络来调用命令
  执行命令来创建需要处理的输出
  执行其他的Python脚本
  执行一系列动态生成的Python语句
  导入Python模块
  Python中,内建和外部模块都可以提供上述各种功能。程序员得根据实现的需要,从这些模块中选择合适的处理方法。

可调用对象

许多Python对象都是我们所说的可调用的,即是任何通过函数操作符()来调用的对象。Python有4中可调用对象:函数,方法,类,以及一些类的实例。

1.函数
Python有3中不同类型的函数对象,第一种是内建函数。
内建函数(BIFs)
BIF是用C/CPP写的,编译过后放入Python解释器,然后把它们作为第一(内建)名字空间的一部分加载进系统。这些函数在_builtin_模块里,并作为__builtins__模块导入到解释器中。
可以用dir()列出函数的所有属性:

>>> dir(type)
['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__doc__', '__eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__instancecheck__', '__itemsize__', '__le__', '__lt__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasscheck__', '__subclasses__', '__subclasshook__', '__weakrefoffset__', 'mro']

从内部机制来看,因为BIFs和内建方法(BIMs)属于相同类型,所以对BIF或者BIM调用type()的结果是:

>>> type(dir)
<type 'builtin_function_or_method'>

用户定义的函数(UDF)
UDF通常是用Python写的,定义在模块的最高级,因此会作为全局名字空间的一部分装置到系统中。函数也可以在其他函数体内定义,我们可以对多重嵌套作用域中的属性进行访问。
从内部机制来看,用户自定义的函数是“函数”类型的:

>>> def foo():pass

>>> type(foo)
<type 'function'>

lambda表达式
lambda表达式和用户自定义函数相比,略有不同。虽然它们也是返回一个函数对象,但是不是用def语句创建的,而是用lambda关键字:
因为lambda表达式没有给命名绑定的代码提供基础结构,所以要通过函数式编程接口来调用,或把它们的引用赋值给一个变量,然后就可以直接调用或者再通过函数来调用。变量仅是个别名,并不是函数对象的名字。
通过lambda来创建函数的对象除了没有命名之外,和UDF有相同的属性;__name__或者func_name属性给定位字符串"<lambda>"

>>> lambdaFunc = lambda x: x * 2
>>> lambdaFunc(12)
24
>>> type(lambdaFunc)
<type 'function'>
>>> lambdaFunc.__name__
'<lambda>'

如果是UDF的名字,则是这样:

>>> def foo():pass

>>> foo.__name__
'foo'

以上是三种函数对象

2.方法
用户自定义方法是被定义为类的一部分的函数。许多Python的数据类型,比如列表和字典,也有方法,被称为内建方法。为了说明所有权的类型,方法通过对象的名字和句点属性标识符命名。

内建方法(BIMs)
刚刚我们说了BIF和BIM的类似之处。只有内建类型有内建方法。对于内建方法,type()工厂函数给出了和BIF一样的输出。

>>> type([].append)
<type 'builtin_function_or_method'>

此外BIM和BIF两者有相同属性。不同之处在于BIM的__self__属性指向一个Python对象,BIF指向None。

用户定义的方法(UDM)
UDM包含在类定义之中,只是拥有标准函数的包装,仅有定义他们的类可以使用。如果没有在子类定义中被覆盖,也可以通过子类实例来调用它们。

3.类
调用类的结果就是创建了实例,也就是实例化。

4.类的实例
Python给类提供了名为__call__的特别方法,该方法允许程序员创建可调用的对象(实例)。默认情况下,__call__()方法是没有实现的,这意味着大多数情况下实例是不可调用的。然而,如果在类中覆盖了这个方法,那么这个类的实例就成为可调用的了。调用这样的实例对象等同于调用__call__()方法。如:foo()和foo.__call__(foo)的效果相同,这里的foo也作为参数出现,因为是对自己的引用,实例将自动成为每次方法调用的第一个参数,如果__call__()有参数,那么foo(arg)就和foo.__call__(foo, arg)一样。

代码对象

可调用对象是Python执行环境里最重要的部分,然而这并不是全部。Python语句,赋值,表达式,甚至还有模块构成了更宏大的场面。这些可执行对象无法像可调用物那样被调用。这些代码块被称为代码对象。

每个可调用物的核心都是代码对象,由语句,赋值,表达式,以及其他可调用物组成。查看一个模块意味着观察一个较大的、包含了模块中所有代码的对象。然后代码分成语句,赋值,表达式,以及可调用物。可调用物又可以递归分解到下一层,那里有它自己的代码对象。
一般来说,代码对象可以作为函数或者方法调用的一部分来执行,也可用exec语句或内建函数eval()来执行。从整体上看,一个Python模块的代码对象是构成该模块的全部代码。
如果要执行Python代码,那么该代码必须先要转换成字节编译的代码(又称字节码)。这才是真正的代码对象。然而,它们不包含任何关于它们执行环境的信息,这便是可调用物存在的原因,它被用来包装一个代码对象并提供额外的信息。
UDF有 udf.func_code 属性就是代码对象。UDM的udm.im_func也是一个函数对象,他同样有它自己的udm.im_func.func_code代码对象。这样的话,你会发现,函数对象仅是代码对象的包装,方法则是给函数对象的包装。当研究到最底层,便是一个代码对象。

可执行的对象声明和内建函数

Python提供了大量的BIF来支持可调用/可执行对象。

1.callable()
callable()是一个布尔函数,确定一个对象是否可以用函数操作符()来调用。如果可调用便返回True,否则便是False。

2.compile()
compile()函数允许程序员在运行时刻迅速生成代码对象,然后就可以用exec语句或者内建函数eval()来执行这些对象或者他们进行求值。
compile的三个参数都是必需的,第一参数代表了要编译的Python代码。第二个参数是字符串,虽然是必需的,但通常被置为空串,该参数代表了存放代码对象的文件的名字(字符串类型)。compile的通常用法是动态生成字符串形式的Python代码,然后生成一个代码对象——代码显然没有存放在任何文件。最后的参数是个字符串,用来表明代码的类型。有三个可能值:
'eval' 可求值的表达式[和eval()一起使用]
'single' 单一可执行语句[和exec一起使用]
'exec' 可执行与剧组[和exec一起使用]

可求值表达式

>>> eval_code = compile('10-2','','eval')
>>> eval(eval_code)
8

单一可执行语句

>>> single_code = compile('print "Hello world"','','single')
>>> single_code
<code object <module> at 024DC698, file "", line 1>
>>> exec single_code
Hello world

可执行语句组

>>> exec_code = compile("""
req = input('Count how many numbers?')
for eachNum in range(req):
  print eachNum
""",'','exec')
>>> exec exec_code
Count how many numbers?6
0
1
2
3
4
5

3.eval()
eval()对表达式求值,表达式可以为字符串或内建函数compile()创建的预编译代码对象。这个对象是第一个也是最重要的参数。第二个和第三个参数是可选的,分别代表了全局和局部名称空间中的对象。如果给出了这两个参数,全局必须是个字典,局部可以是任意的映射对象。如果没有给出这两个参数,分别默认为globals()和locals()返回的对象。如果只传入了一个全局字典,那么该字典也作为局部参数传入。
这是eval()的一个例子。

>>> eval('')
123
>>> int('')
123
>>> eval('123+234')
357
>>> int('123+234') Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
int('123+234')
ValueError: invalid literal for int() with base 10: '123+234'

开始,我们传入'123'给eval()和int()的时候,返回了相同的结果,但是方式是不尽相同的,eval()接受引号内的字符串把它作为Python表达式求值,int()接受代表整数的字符串并把它转换为整数。而当我们输入'123+234'时,情况就不一样了。int()调用就失败了。可以认为eval()函数对表达式两端的引号视而不见,将它执行在解释器上,返回结果。

4.exec
和eval()相似,exec语句执行代码对象或字符串形式的Python代码。类似地,用compile()预编译重复代码有助于改善性能,因为在调用时不必经过字节编译处理。exec只接受一个参数,语法是:

exec obj

obj可以是原始的字符串,比如单一语句或语句组,也可以预编译层一个代码对象。

>>> exec """
x = 0
print 'x is currently:',x
while x < 5:
  x += 1
  print 'incrementing x to:',x
"""
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5

exec还可以接受有效的Python文件对象。如果我们用上面的多行代码创建一个xcount.py的文件,那么也可以这样执行相同代码:

>>> f = open('xcount.py') # open the file
>>> exec f # execute the file
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5

上面我们调用了文件f,如果在完成后继续调用它

>>> exec f
>>>

调用会失败。并不是真正的失败,只是不再做任何事。事实上,exec已从文件中读取了全部数据且停留在文件末尾(EOF)。当用相同的文件对象对exec进行调用的时候,没有可执行的代码了,所以exec什么都不做。
我们可以用tell()方法来告诉我们处于文件的何处,然后用os.path.getsize()来告诉我们脚本由多大。然后就会发现,这两个数字完全一样:

>>> f.tell()
116
>>> f.close()
>>> from os.path import getsize
>>> getsize('xcount.py')
116

如果想在不关闭和重新打开文件的情况下再次运行它,可以用seek()到文件最开头并再次调用exec。假定我们还没有调用f.close(),那么:

>>> f.seek(0)
>>> exec f
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
>>> f.close()

5.input()
之前用到的内建函数input()是eval()和raw_input()的组合,等价于eval(raw_input()),input()和raw_input()一样有一个可选的参数给用户字符串提示。
input不同于raw_input(),input()返回的数据是对输入表达式求值的结果,是一个Python对象。

6.使用Python在运行时生成和执行Python代码
书上提供了两个例子,这两个例子在运行时吧Python代码作为字符串并执行。
第一个例子是loopmake.py脚本。一个简单迅速和执行循环的计算机辅助软件工程。提示用户给出各种参数,生成代码字符串,并执行它。

dashes = '\n' + '-' * 50
exec_dict = {
'f':''' #for loop
for %s in %s:
print %s
''', 's':''' # sequence while loop
%s = 0
%s = %s
while %s < len(%s):
print %s[%s]
%s = %s + 1
''', 'n':''' # counting while loop
%s = %d
while %s < %d:
print %s
%s = %s + %d
'''
} def main(): ltype = raw_input('Loop type? (For/While)')
dtype = raw_input('Data type? (Number/Sequence)') if dtype == 'n':
start = input('Starting value? ')
stop = input('Ending value (non-inclusive)? ')
step = input('Stepping value? ')
seq = str(range(start, stop, step)) else:
seq = raw_input('Enter sequence:') var = raw_input('Iterative variable name?') if ltype == 'f':
exec_str = exec_dict['f'] % (var, seq, var) elif ltype == 'w':
if dtype == 's':
svar = raw_input('Enter sequence name? ')
exec_str = exec_dict['s'] % \
(var, svar, seq, var, svar, svar, var, var, var)
elif dtype == 'n':
exec_str = exec_dict['n'] % \
(var, start, var, stop, var, var, var, step) print dashes
print 'The custom-generated code for you is:' + dashes
print exec_str + dashes
print 'The execution of the code:' + dashes
exec exec_str
print dashes if __name__ == '__main__':
main()

有兴趣的人可以执行一下这段代码,十分有趣,可以帮助你生成代码并执行。反正我写这段代码的时候感觉到了exec和input的强大。

第二个例子是有条件地执行代码
这是代码:

def foo():
return True def bar():
'bar() does not do much'
return True foo.__doc__ = 'foo() does not do much'
foo.tester = '''
if foo():
print 'PASSED'
else:
print 'FAILED'
''' for eachAttr in dir():
obj = eval(eachAttr)
if isinstance(obj, type(foo)):
if hasattr(obj, '__doc__'):
print '\nFunction "%s" has a doc string:\n\t%s'\
% (eachAttr, obj.__doc__)
if hasattr(obj, 'tester'):
print 'Function "%s" has a tester... executing'\
% eachAttr
exec obj.tester
else:
print 'Function "%s" has no tester... skipping'\
% eachAttr
else:
print '"%s" is not a function' % eachAttr

下面是执行后的结果:

>>>
"__builtins__" is not a function
"__doc__" is not a function
"__file__" is not a function
"__name__" is not a function
"__package__" is not a function Function "bar" has a doc string:
bar() does not do much
Function "bar" has no tester... skipping Function "foo" has a doc string:
foo() does not do much
Function "foo" has a tester... executing
PASSED

代码并不难理解,但其所做的事的确很有趣不是么?

2015/10/9 Python基础(21):可调用和可执行对象的更多相关文章

  1. 二十一. Python基础(21)--Python基础(21)

    二十一. Python基础(21)--Python基础(21) 1 ● 类的命名空间 #对于类的静态属性:     #类.属性: 调用的就是类中的属性     #对象.属性: 先从自己的内存空间里找名 ...

  2. 2015/9/9 Python基础(10):文件和输入输出

    文件对象文件对象不仅可以用来访问普通的磁盘文件,而且也可以访问其它任何类型抽象层面上的“文件”.一旦设置了合适的“钩子”,你就可以访问文件类型接口的其它对象,就好像访问的是普通文件一样.文件对象的处理 ...

  3. 2015/10/9 Python核编初级部分学习总结

    终于在十一长假之后的两天看完了<Python核心编程>的初级部分.虽然到后来两章,类和环境看得越来越慢,越来越难以理解.很多东西只能靠强记,也没办法真正掌握了,我想了想,还是不强迫自己去背 ...

  4. 10个Python基础练习项目,你可能不会想到练手教程还这么有趣

    美国20世纪最重要的实用主义哲学家约翰·杜威提出一个学习方法,叫做:Learning By Doing,在实践中精进.胡适.陶行知.张伯苓.蒋梦麟等都曾是他的学生,杜威的哲学也影响了蔡元培.晏阳初等人 ...

  5. python基础--------字符串的调用详解(2)

    Python 字符串的的调用方法~~~@@@ 17.  strip  : 去除字符串左右两边指定的字符 18.   rstrip : 去除字符串右边指定的字符 19 .   lstrip  :  去除 ...

  6. python 基础 ------字符串的调用详解(1)

    Python 字符串的的调用方法~~~ 废话不多说直接奔主题 >>>>>>>>>>>>>>>>> ...

  7. 2015/9/29 Python基础(20):类的授权

    类的授权 1.包装包装在Python编程世界中时经常会被提到的一个术语.它是一个通用的名字,意思是对一个已存在的对象进行包装,不管它是数据类型,还是一段代码,可以是对一个已存在的对象,增加新的,删除不 ...

  8. 2015/9/20 Python基础(16):类和实例

    面向对象编程编程的发展已经从简单控制流中按步的指令序列进入到更有组织的方式中,依靠代码块可以形成命名子程序和完成既定的功能.结构化的或过程性编程可以让我们把程序组织成逻辑快,以便重复或重用.创造程序的 ...

  9. python基础-9.1 面向对象进阶 super 类对象成员 类属性 私有属性 查找源码类对象步骤 类特殊成员 isinstance issubclass 异常处理

    上一篇文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中) 对象 ...

随机推荐

  1. 2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest Problem F. Format

    题目来源:http://codeforces.com/group/aUVPeyEnI2/contest/229510 时间限制:1s 空间限制:512MB 题目大意: 给定一个字符串,使用%[...] ...

  2. 基于 IBM WAS ND v6.1 搭建稳定高效的集群环境

    如今的电子商务及电子政务应用系统的发展已经到了一个新的阶段,应用系统的成熟度和可用性都达到了更高的水准.因此庞大的部署规模和海量的用户访问成为目前大型电子商务及电子政务应用系统的显著特征.在这样的情况 ...

  3. IntelliJ IDEA 创建 hello world Java web Maven项目从头到尾都有图有真相2017版本

    学Java的大部分吧都是要整Java web开发项目的,那么最好用的编辑器估计就是这个 IntelliJ IDEA,然后现在maven管理项目是很流行的.然后我就示范一下,如何使用这个IntelliJ ...

  4. python3.6 SSL module is not available

    pip is configured with locations that require TLS/SSL, however the ssl module in Python is not avail ...

  5. linux设置时区和自动同步时间

    1.设置时区 编辑 /etc/sysconfig/clock 修改 ZONE="Asia/Shanghai" 然后  cp  /usr/share/zoneinfo/Asia/Sh ...

  6. 【php】header下载文件后,文件变大的问题;(ob_clean()清空缓存)

    事由: 按照常理,为了下载一个生产的文件,都是使用header函数,指定下文件信息,然后开始下载,但是下载后发现,文件体积总是比源文件要大2个字节,源文件是24字节,下载后是26字节,查看服务器返回的 ...

  7. ViewPager、Fragment、Matrix综合使用实现Tab滑页效果

    原文地址:http://www.cnblogs.com/kross/p/3372987.html 我们实现一个上面是一个可以左右滑动的页面,下面是三个可点击切换的tab按钮,tab按钮上还有一个激活条 ...

  8. PHP中面向对象编程思想的3个特征

    面向对象编程思想的3个特征: 封装: 无非是一个大的指向思想,目的是为了将一个类设计得更为健壮! 其基本做法是: 尽可能地将一个类的成员私有化,只开放那些必不可少的对外的属性或方法,能private的 ...

  9. mysql中联合查询

    联合查询union 一个翻译问题的解释: 在mysql的手册中,将连接查询(Join)翻译为联合查询: 而联合查询(union),没有明确翻译. 但: 在通常的书籍或文章中,join被翻译为“连接”查 ...

  10. java & maven pom

    java & maven pom https://maven.apache.org/pom.html http://www.tutorialspoint.com/maven/maven_pom ...