python输入数据java执行python脚本上几步操作

简明 Python 教程 / 最初的步骤 / 可执行的Python程序
第3章 最初的步骤
可执行的Python程序
这部分内容只对Linux/Unix用户适用,不过Windows用户可能也对程序的第一行比较好奇。首先我们需要通过chmod命令,给程序可执行的许可,然后 运行 程序。
$ chmod a+x helloworld.py
$ ./helloworld.py
Hello World
chmod命令用来 改变 文件的 模式 ,给系统中所有用户这个源文件的执行许可。然后我们可以直接通过指定源文件的位置来执行程序。我们使用./来指示程序位于当前目录。
为了更加有趣一些,你可以把你的文件名改成仅仅helloworld,然后运行./helloworld。这样,这个程序仍然可以工作,因为系统知道它必须用源文件第一行指定的那个解释器来运行程序。
只要知道程序的确切位置,你现在就可以运行程序了――但是如果你希望你的程序能够从各个位置运行呢?那样的话,你可以把你的程序保存在PATH环境变量中的目录之一。每当你运行任何程序,系统会查找列在PATH环境变量中的各个目录。然后运行那个程序。你只要简单地把这个源文件复制到PATH所列目录之一就可以使你的程序在任何位置都可用了。
$ echo $PATH
/opt/mono/bin/:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/swaroop/bin
$ cp helloworld.py /home/swaroop/bin/helloworld
$ helloworld
Hello World
我们能够用echo命令来显示PATH变量,用$给变量名加前缀以向shell表示我们需要这个变量的值。我们看到/home/swaroop/bin是PATH变量中的目录之一。swaroop是我的系统中使用的用户名。通常,在你的系统中也会有一个相似的目录。你也可以把你选择的目录添加到PATH变量中去――这可以通过运行PATH=$PATH:/home/swaroop/mydir完成,其中“/home/swaroop/mydir”是我想要添加到PATH变量中的目录。
当你想要在任何时间、任何地方运行你的程序的时候,这个方法十分有用。它就好像创造你自己的指令,如同cd或其他Linux终端或DOS提示符命令那样。
对于Python来说,程序、脚本或者软件都是指同一个东西。
使用源文件博客访问: 3749247
博文数量: 3918
博客积分: 6409
博客等级: 准将
技术积分: 15961
注册时间:
认证徽章:
迷彩 潜伏 隐蔽 伪装
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Web开发
原文地址: 作者:
Python对于数据库的管理操作大体可以分为两种方式,一是直接操作数据库,Python仅仅提供一个数据库接口,开发者需要直接和数据库打交道来获取数据;第二种是ORM模式(对象关系映射object-relational mapper),下面会详细介绍。
1. 直接型数据库操作
这种方式是一种直接的数据库操作方式(和其他许多语言都类似),由Python数据库连接模块提供对数据库的连接、查询、修改等接口,这类模块包括MySQLdb、cx_Oracle等,下面介绍下Mysql的使用,其他类型的数据库操作也是类似的。
演示一下插入数据,批量插入数据,更新数据的例子
import MySQLdb
&&&&conn=MySQLdb.connect(host='localhost',user='root',passwd='root',port=3306)
&&&&cur=conn.cursor()
&&&&cur.execute('create database if not exists python')
&&&&conn.select_db('python')
&&&&cur.execute('create table test(id int,info varchar(20))')
&&&&value=[1,'hi rollen']
&&&&cur.execute('insert into test values(%s,%s)',value)
&&&&values=[]
&&&&for i in range(20):
&&&&&&&&values.append((i,'hi rollen'+str(i)))
&&&&cur.executemany('insert into test values(%s,%s)',values)
&& &cur.execute('update test set info="I am rollen" where id=3')
&&&&conn.commit()
&&&&cur.close()
&&&&conn.close()
except MySQLdb.Error,e:
&&&&&print "Mysql Error %d: %s" % (e.args[0], e.args[1])
然后查询数据
import MySQLdb
&&&&conn=MySQLdb.connect(host='localhost',user='root',passwd='root',port=3306)
&&&&cur=conn.cursor()
&&&&conn.select_db('python')
& & count=cur.execute('select * from test')
&&&&print 'there has %s rows record' % count
&&&&result=cur.fetchone()
&&&&print result
&&&&print 'ID: %s info %s' % result
&&&&results=cur.fetchmany(5)
&&&&for r in results:
&&&&&&&&print r
&&&&print '=='*10
&&&&cur.scroll(0,mode='absolute')
&&&&results=cur.fetchall()
&&&&for r in results:
&&&&&&&&print r[1]
& & conn.commit()
&&&&cur.close()
&&&&conn.close()
except MySQLdb.Error,e:
&&&&&print "Mysql Error %d: %s" % (e.args[0], e.args[1])
请注意一定要有mit()这句来提交事务,要不然不能真正的插入数据。
常用的函数:
commit() 提交
rollback() 回滚
cursor用来执行命令的方法:
callproc(self, procname, args):用来执行存储过程,接收的参数为存储过程名和参数列表,返回值为受影响的行数
execute(self, query, args):执行单条sql语句,接收的参数为sql语句本身和使用的参数列表,返回值为受影响的行数
executemany(self, query, args):执行单挑sql语句,但是重复执行参数列表里的参数,返回值为受影响的行数
nextset(self):移动到下一个结果集
cursor用来接收返回值的方法:
fetchall(self):接收全部的返回结果行.
fetchmany(self, size=None):接收size条返回结果行.如果size的值大于返回的结果行的数量,则会返回cursor.arraysize条数据.
fetchone(self):返回一条结果行.
scroll(self, value, mode='relative'):移动指针到某一行.如果mode='relative',则表示从当前所在行移动value条,如果 mode='absolute',则表示从结果集的第一行移动value条.
如果出现了乱码,可以尝试以下方法:
conn = MySQLdb.Connect(host='localhost', user='root', passwd='root', db='python') 中加一个属性:
conn = MySQLdb.Connect(host='localhost', user='root', passwd='root', db='python',charset='utf8')&
charset是要跟你数据库的编码一样,如果是数据库是gb2312 ,则写charset='gb2312'。
Python中提供ORM支持的项目不止一个,知道的就有Django 以及 Storm。这两个项目的应用领域稍有区别,但是数据库操作的理论原理是相同的。ORM在开发者和数据库之间建立了一个中间层,把数据库中的数据转换成了Python中的对象实体,这样既屏蔽了不同数据库之间的差异性,又使开发者可以非常方便的操作数据库中的数据,而且可以使用面向对象的高级特性。
2.1&Django&
Django 是基于 Python 的 Web 应用程序框架,最初旨在简化数据库驱动的、面向新闻的 Web 应用程序的开发。其后,它已经发展成功能完备的 Web 框架,经常用来简化数据库支持的复杂 Web 应用程序的开发。
Django 的对象关系映射器 (ORM) 位于框架的中心,介于数据模型(您在 django.db.models.Model 类之上构建的 Python 类)和基础关系数据库对象之间。定义数据模型之后,您将能够通过映射到基础数据库中的对象的 Python 对象,来创建、检索、更新以及删除数据库数据。需要强调的是,除了 PostgreSQL、MySQL 和 SQLite 之外,Django 还正式支持 Oracle 数据库,可让您使用 ORM 特性访问和操作 Oracle 数据库数据。
大多数情况下,应用的创建至少需要执行以下五个步骤:
在 settings.py 中指定数据库信息
在 urls.py 中配置 URL 模式
在继续上述步骤之前,让我们看一下 Django 应用程序的高级视图,以便您可以更好地了解 Django 中的组件如何工作。下图示意性地显示了 Django 应用程序如何工作以满足用户请求。
根据此图中的图示,工作方式如下:
用户输入支持 Django 的站点的 URL 或在此站点的已加载页面上执行操作,从而将请求发送到托管此站点的 Web 服务器。
Django 的 URL 调度程序遍历 urls.py 文件中的 URL 模式,并选择第一个与用户请求的 URL 匹配的模式,然后调用与所发现模式相关联的视图(Python 回调函数)。
视图使用数据模型获得数据库数据,然后加载指定模板(已嵌入特殊模板标记的 HTML 页面;它类似于 Java 中的 JavaServer Page),并向其传递上下文(包括映射到模板变量名称的已获得数据)。
最后,视图返回由已呈现模板填充的 HttpResponse 对象,如果出现错误,则返回 HTTP 异常。
您可以看到,Django 基于将 Web 应用程序逻辑分为模型、视图和模板的概念,因此有效地将业务逻辑和展示分离开来。通常,这类似于当今许多其他 Web 框架中使用的模型-视图-控制器 (MVC) 范例。然而,在 Django 中,视图更像控制器,介于模型和模板之间。而 Django 模板更接近于 MVC 视图,因为这些模板负责使用从模型中获得的数据生成适当的用户界面。
将 Django 用于 Apache
Django 的内置开发 Web 服务器仅适用于测试,这意味着它并不是生产服务器。如果要将它用于生产,您需要慎重考虑。
您可以通过 mod_python 模块(用于在 Apache 内嵌入 Python)将 Django 部署到 Apache。因此,首先确保您已将 mod_python 模块安装到 Apache 服务器上(可以在 此处找到详细信息)。然后,您可以将以下 Location 块添加到 Apache 的 httpd.conf 配置文件中(在 PythonPath 中使用实际路径):
< Location "/myapp/">
&&&&SetHandler python-program
&&&&PythonPath "['/home/user/myprojects', '/home/user/myprojects/myproj'] + sys.path"
&&&&PythonHandler django.core.handlers.modpython
&&&&SetEnv DJANGO_SETTINGS_MODULE myproj.settings
&&&&PythonDebug On
< /Location>
详细配置和使用方法可以参考&&
与Django不同,Storm 是一个专门的 Python ORM 库,它的使用相对Django 要简单一些。
>>> from storm.locals import *
现在,我们定义一种用几项属性来描述信息的类型(type),用它来作映射。
>>> class Person(object):
... & & __storm_table__ = "person"
... & & id = Int(primary=True)
... & & name = Unicode()
注意,这个定义没有使用任何 Storm 定义的 base 类或构造函数。
创建一个数据库以及仓库(store)
我们还是什么都没讲到,因此,让我们来定义一个储存在内存中的 SQLite 数据库,以及使用该数据库的仓库来玩玩。
>>> database = create_database("sqlite:")
>>> store = Store(database)
目前,有三种数据库被支持: SQLite , MySQL 以及 PostgreSQL 。 create_database 函数接受 URI 作为参数,就像这样:
database = create_database("scheme://username:password@hostname:port/database_name")
其中的 scheme 可以是 sqlite , postgres ,或 mysql 。
现在我们要创建一个表,将该表用来保存我们类中的数据。
>>> store.execute("CREATE TABLE person "
... & & & & & & & "(id INTEGER PRIMARY KEY, name VARCHAR)")
我们得到了一个结果(result),不过现在不必关心它。通过使用 noresult=True ,我们也可以省略所有结果。
让我们通过前面定义的类来创建对象。
>>> joe = Person()
>>> joe.name = u"Joe Johnes"
>>> print "%r, %r" % (joe.id, joe.name)
5 None, u'Joe Johnes'
到目前为止,这个对象都还没有连接到数据库。现在,让我们将它加入到前面创建的仓库当中。
>>> store.add(joe)
>>> print "%r, %r" % (joe.id, joe.name)
None, u'Joe Johnes'
请注意,这个对象并没有任何改变,即便是被加入到仓库之后 —— 这是因为它还没有刷新呢。
对象的仓库
一旦对象被加入到仓库,或从仓库中被检索,它和仓库的关系就明了了。我们也可以很容易地验证对象绑定到了哪一个仓库。
>>> Store.of(joe) is store
>>> Store.of(Person()) is None
对象的查找
现在,如果我们向仓库查询名为 Joe Johnes 的人,会发生什么事?
>>> person = store.find(Person, Person.name == u"Joe Johnes").one()
>>> print "%r, %r" % (person.id, person.name)
1, u'Joe Johnes'
Joe Johnes 已经被仓库记录了!是的,就正如你所期待的一样。
我们还可以通过主键(primary key)来检索对象。
>>> store.get(Person, 1).name
u'Joe Johnes
详细信息参考:&
阅读(4520) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。一个监控脚本带来的Python实践和学习 - 青葱岁月 - ITeye技术网站
博客分类:
工作中经常要和服务器、数据库这些打交道,有些小功能例如:服务监控、数据监控等用java往往无处下手,即使能做也要花费很长的时间,身边好几个同事都会Python,面对这些需求他们往往优先选择Python来实现,又快又省事。所以我也计划着自学一下Python,寻思着买一本入门的书来参考,在豆瓣上挑来挑去最后挑了《Head first Python》这本。买来后断断续续看了好几章了,对Python也有了一些基本的了解,不过一直没真正上手。
废话太多,直接步入正题,昨天领导让我写个脚本来实时监控某个服务的日志,监控日志中报出的用户购买超时的现象,如果某个node累计超时次数达到10次则通过邮件和短信告警。
需求就是上面说的这样,虽然Python用的还不熟练,不过当下也没其它好的方式来实现,没办法,赶鸭子上架,现学现用,如果碰到不会的就借助于万能的互联网吧
一、Python调用shell
首先考虑实现的方式,由于领导要求实时监控,所以当前想到的方式就是使用linux shell的tail命令扫描服务日志,然后再使用关键字来grep,根据grep出来的日志内容进行分析。这时候碰到了第一个问题,如何在Python中执行linux shell命令呢?
没办法,上网求助,网上有人推荐使用os.system,不过大部分都推荐使用subprocess模块来实现,通过官方文档说明,我决定使用subprocess
有这么一段话:
The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several other, older modules and functions, such as:os.systemos.spawn*os.popen*popen2.*commands.*
翻译过来的意思大致就是:subprocess模块允许你新建子进程,可以连接到进程的输入、输出、异常通道,并且可以获取到子进程的返回值,这个模块是Python用来替代一些其它过时的模块和功能的。
所以说,官方推荐使用subprocess来实现类似的功能。
要使用subprocess,首先必须import该模块
import subprocess
要调用shell命令,subprocess有很多方式,比如call、Popen等,这里我们使用Popen
首先看一个最简单的实例:
subprocess.Popen('ls -l',stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
上面的代码构建了一个Popen对象,Popen的构造函数格式如下:
subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
参数args可以是字符串或者序列类型(如:list,元组),用于指定进程的可执行文件及其参数。如果是序列类型,第一个元素通常是可执行文件的路径。
参数stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。他们可以是PIPE,文件描述符或文件对象,也可以设置为None,表示从父进程继承。
如果参数shell设为true,程序将通过shell来执行。
关于其它具体的参数的说明,参见官方文档:
不想看英文的可以看网上的另一篇博客:
我的代码逻辑如下:
#日志文件目录和名称
filename = '/home/project/logs/xxx.log'
#要执行的shell命令
command='tail -f '+filename+'|grep "timeout"'
popen=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
while True:
#获取当前grep出来的日志文本行
line=popen.stdout.readline().strip()
#对日志文本进行分析(这里省略)
二、Python发送http请求
上面已经提到,告警的方式为邮件和短信,我们的短信推送接口是一个http接口,所以如果需要短信告警,则需要通过python来请求该http接口。python中一共有urllib、urllib2、httplib、httplib2支持发送http请求,由于服务器上没有安装python的httplib和httplib2模块,所以只能使用urllib,urllib2
使用GET请求来请求短信推送接口,可以把参数写在url中,如果使用POST方式来请求接口,则数据必须放在data或者body中,不能放在url中,放在url中将被忽略。
附上一个通过urllib,urllib2发送GET请求的示例:
import urllib,urllib2
def main():
url="/s?wd=douban"
req = urllib2.Request(url)
res_data = urllib2.urlopen(req)
res = res_data.read()
if __name__ == '__main__':
关于python对http请求的操作,可以参见博客:
三、脚本进程和子进程的退出
发现了2个问题:
问题1:在上面的代码中,python调用的shell tail命令作用是实时监控当前的日志,而服务是24小时不间断的,该python脚本也一直同步执行,所以只能使用nohup方式后台启动。每次要关闭该脚本,手动通过进程pid来kill。带来了一个新的问题,每次kill掉python主进程时,主进程执行时启动的Popen子进程未关闭,由于调试时曾经连续启动-&kill-&启动-&kill多次,导致系统中出现了一大堆tail日志的进程,这是我原来没有预料到的。
问题2:我们的日志是生成的dailyRolling日志,文件名称为:xxx_dailyRolling.log,每天的0点会自动重命名为xxx_dailyRolling.logyyyyMMdd,yyyyMMdd代表前一天的日期,例如xxx_dailyRolling.log,如果tail -f xxx_dailyRolling.log命令一直执行,到0点时会中断,所以我还需要在每天0点前停止当前的python脚本,然后在第二天0点后定时启动此python脚本
综上,2个问题一起解决,在0点前停止python脚本前先kill掉Popen子进程,然后再停止就OK了。
我的思路时每天设置一个固定的时间点,例如就定为每天的23:30:00(因为我们的服务在凌晨时基本上没人使用,监控的目的主要是为了监控白天高峰期时的服务情况,所以23:30到0点这段时间即使没监控也不影响),然后在Popen子进程执行时判断当前时刻是否到了23:30:00,如果已经到了,则终止子进程。通过实践证明,如果Popen子进程终止了,如果python主进程里没有挂起的其余子进程在执行,则主进程也会终止。
Popen可以通过terminate()或者kill()函数来终止当前的子进程。在执行了terminate()后,如果不想立即终止,可以通过wait()或poll()函数来等待子进程执行结束,关于各函数的使用,具体参考官方文档。
各函数说明如下:
Popen.poll()Check if child process has terminated. Set and return returncode attribute.Popen.wait()Wait for child process to terminate. Set and return returncode attribute.Popen.terminate()Stop the child. On Posix OSs the method sends SIGTERM to the child. On Windows the Win32 API function TerminateProcess() is called to stop the child.Popen.kill()Kills the child. On Posix OSs the function sends SIGKILL to the child. On Windows kill() is an alias for terminate().
附上一个示例:
#程序执行终止时间为当前时刻延迟15秒
stoptime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()+15))
def main():
popen=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
pid=popen.pid
print('Popen.pid:'+str(pid))
while True:
line=popen.stdout.readline().strip()
print(line)
thistime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
if thistime&=stoptime:
#终止子进程
popen.terminate()
#等待子进程终止后跳出while循环
if subprocess.Popen.poll(popen) is not None:
print('waiting for subprocess.Popen terminate()')
print('DONE')
if __name__ == '__main__':
四、Python2.x和3.x版本的区别(部分)
Python在2.x和3.x之间有一些特性区别比较大,由于我本地是安装的最新的3.2.2版本,而服务器上还是2.6.x,所以在编写调试时遇到了一些,也拿出来说说说:
区别1.print函数
在python 2.x版本中,同时支持print(xxx)和print xxx,示例:
&&& name='chenzhou'
&&& print name
&&& print(name)
在python 3.x版本中,只支持print(xxx)的方式,示例:
&&& name='chenzhou'
&&& print(name)
&&& print name
SyntaxError: invalid syntax
区别2.判断字典中的key是否存在
在python 2.x中,可以使用has_key(key)函数,也可以判断 key in xxxMap.keys(),示例:
&&& users={'name':'chenzhou','age':'24','address':'Beijing'}
&&& print users.has_key('name')
&&& print 'name' in users.keys()
&&& print users.has_key('score')
&&& print 'score' not in users.keys()
在python 3.x中,只支持key in xxxMap.keys() 示例:
&&& users={'name':'chenzhou','age':'24','address':'Beijing'}
&&& print('name' in users.keys())
&&& print('score' in users.keys())
&&& print(users.has_key('name'))
Traceback (most recent call last):
File "&pyshell#20&", line 1, in &module&
print(users.has_key('name'))
AttributeError: 'dict' object has no attribute 'has_key'
五、Python UnicodeDecodeError
脚本写完后在linux下执行时报错:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 0: ordinal not in range(128)
网友给出的原因是windows系统下编辑的文件在linux下编码转换出现的问题,具体解决方法如下:
#引入sys模块
import sys
#加入下面两行代码
reload(sys)
sys.setdefaultencoding('utf-8')
在grep关键字时用到了正则表达式,推荐一篇关于Python正则表达式的好博客:
Python官网:
以上就是我第一次使用Python的经历,开始体会到了Python的优势。另外,也应了那句俗话,学习编程语言,光看书是没有效果的,只有理论与实践结合起来才能达到学习的效果,我想这应该就是别人经常提到的应用驱动学习吧。
最后,说明一下,我只是一个Python小菜鸟,写的东西很简单,大家不喜勿喷哈。
浏览 23730
chenzhou123520
浏览: 2116105 次
来自: 北京
大家都用过SVN吧,也就是这样的乐观锁机制。大家可以联想起来就 ...
写的很好,赞~!
org.springframework.web.servle ...
赞!!!刚好需要当前位置: →
→ 说说Python程序的执行过程
说说Python程序的执行过程
& 作者:飞林沙 & 来源: 飞林沙 - 博客园 & 热度:
&收藏到→_→:
摘要: 说说Python程序的执行过程
"说说Python程序的执行过程"::
1. python是一门解释型语言?
我初学python时,听到的关于python的第一句话就是,python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在。如果是解释型语言,那么生成的*.pyc文件是什么呢?c应该是compiled的缩写才对啊!
为了防止其他学习python的人也被这句话误解,那么我们就在文中来澄清下这个问题,并且把一些基础概念给理清。
2. 解释型语言和编译型语言
计算机是不能够识别高级语言的,所以当我们运行一个高级语言程序的时候,就需要一个&#8220;翻译机&#8221;来从事把高级语言转变成计算机能读懂的机器语言的过程。这个过程分成两类,第一种是编译,第二种是解释。
编译型语言在程序执行之前,先会通过对程序执行一个编译的过程,把程序转变成机器语言。运行时就不需要翻译,而直接执行就可以了。最典型的例子就是c语言。
解释型语言就没有这个编译的过程,而是在程序运行的时候,通过解释器对程序逐行作出解释,然后直接运行,最典型的例子是ruby。
通过以上的例子,我们可以来总结一下解释型语言和编译型语言的优缺点,因为编译型语言在程序运行之前就已经对程序做出了&#8220;翻译&#8221;,所以在运行时就少掉了&#8220;翻译&#8221;的过程,所以效率比较高。但是我们也不能一概而论,一些解释型语言也可以通过解释器的优化来在对程序做出翻译时对整个程序做出优化,从而在效率上超过编译型语言。
此外,随着java等基于的语言的兴起,我们又不能把语言纯粹地分成解释型和编译型这两种。
用java来举例,java首先是通过编译成字节码文件,然后在运行时通过解释器给解释成机器文件。所以我们说java是一种先编译后解释的语言。
再换成c#,c#首先是通过将c#文件编译成il文件,然后在通过clr将il文件编译成机器文件。所以我们说c#是一门纯编译语言,但是c#是一门需要二次编此文来自: 马开东博客
转载请注明出处 网址:
译的语言。同理也可等效运用到基于.net平台上的其他语言。
3. python到底是什么
其实python和java/c#一样,也是一门基于的语言,我们先来从表面上简单地了解一下python程序的运行过程吧。
当我们在命令行中输入python hello.py时,其实是激活了python的&#8220;解释器&#8221;,告诉&#8220;解释器&#8221;:你要开始工作了。可是在&#8220;解释&#8221;之前,其实执行的第一项工作和java一样,是编译。
熟悉java的同学可以想一下我们在命令行中如何执行一个java的程序:
javac hello.java
java hello
只是我们在用eclipse之类的ide时,将这两部给融合成了一部而已。其实python也一样,当我们执行python hello.py时,他也一样执行了这么一个过程,所以我们应该这样来描述python,python是一门先编译后解释的语言。
4. 简述python的运行过程
在说这个问题之前,我们先来说两个概念,pycodeobject和pyc文件。
我们在硬盘上看到的pyc自然不必多说,而其实pycodeobject则是python真正编译成的结果。我们先简单知道就可以了,继续向下看。
当python程序运行时,编译的结果则是保存在位于内存中的pycodeobject中,当python程序运行结束时,python解释器则将pycodeobject写回到pyc文件中。
当python程序第二次运行时,首先程序会在硬盘中寻找pyc文件,如果找到,则直接载入,否则就重复上面的过程。
所以我们应该这样来定位pycodeobject和pyc文件,我们说pyc文件其实是pycodeobject的一种持久化保存方式。
5. 运行一段python程序
我们来写一段程序实际运行一下:
程序本身毫无意义。我们继续看:
然而我们在程序中并没有看到pyc文件,仍然是test.py孤零零地呆在那!
那么我们换一种写法,我们把print_str方法换到另外的一个python模块中:
然后运行程序:
这个时候pyc文件出现了,其实认真思考一下不难得到原因,我们考虑一下实际的业务情况。
6. pyc的目的是重用
回想本文的第二段在解释编译型语此文来自: 马开东博客
转载请注明出处 网址:
言和解释型语言的优缺点时,我说编译型语言的优点在于,我们可以在程序运行时不用解释,而直接利用已经&#8220;翻译&#8221;过的文件。也就是说,我们之所以要把py文件编译成pyc文件,最大的优点在于我们在运行程序时,不需要重新对该模块进行重新的解释。
所以,我们需要编译成pyc文件的应该是那些可以重用的模块,这于我们在设计软件类时是一样的目的。所以python的解释器认为:只有import进来的模块,才是需要被重用的模块。
这个时候也许有人会说,不对啊!你的这个问题没有被解释通啊,我的test.py不是也需要运行么,虽然不是一个模块,但是以后我每次运行也可以节省时间啊!
ok,我们从实际情况出发,思考下我们在什么时候才可能运行python xxx.py文件:
a. 执行测试时。
b. 开启一个web进程时。
c. 执行一个程序脚本。
我们逐个来说,第一种情况我们就不用多说了,这个时候哪怕所有的文件都没有pyc文件都是无所谓的。
第二种情况,我们试想一个webpy的程序把,我们通常这样执行:
然后这个程序就类似于一个守护进程一样一直监视着端口,而一旦中断,只可能是程序被杀死,或者其他的意外情况,那么你需要恢复要做的是把整个的web服务重启。那么既然一直监视着,把pycodeobject一直放在内存中就足够了,完全没必要持久化到硬盘上。
最后一个情况,执行一个程序脚本,一个程序的主入口其实很类似于web程序中的controller,也就是说,他负责的应该是model之间的调度,而不包含任何的主逻辑在内,如我在http://www.马开东/kym/archive//1780407.html中所提到,controller应该就是一个facade,无任何的细节逻辑,只是把参数转来转去而已,那么如果做算法的同学可以知道,在一段算法脚本中,最容易改变的就是算法的各个参数,那么这个时候给持久化成pyc文件就未免有些画蛇添足了。
所以我们可以这样理解python解释器的意图,python解释器只把我们可能重用到的模块持久化成pyc文件。
7. pyc的过期时间
说完了pyc文件,可能有人会想到,每次python的解释器都把模块给持久化成了pyc文件,那么当我的模块发生了改变的时候,是不是都要手动地把以前的pyc文件remove掉呢?
当然python的设计者是不会犯这么白痴的错误的。而这个过程其实就取决于pycodeobject是如何写入pyc文件中的。
我们来看一下import过程的源码吧:
这段代码比较长,我们只来看我标注了的代码,其实他在写入pyc文件的时候,写了一个long型变量,变量的内容则是文件的最近修改日期,同理,我们再看下载入pyc的代码:
不用仔细看代码,我们可以很清楚地看到原理,其实每次在载入之前都会先检查一下py文件和pyc文件保存的最后修改日期,如果不一致则重新生成一份pyc文件。
8. 写在最后的
其实了解python程序的执行过程对于大部分,包括python来说意义都是不大的,那么真正有意义的是,我们可以从python的解释器的做法上学到什么,我认为有这样的几点:
a. 其实python是否保存成pyc文件和我们在设计缓存系统时是一样的,我们可以仔细想想,到底什么是值得扔在缓存里的,什么是不值得扔在缓存里的。
b. 在跑一个耗时的python脚本时,我们如何能够稍微压榨一些程序的运行时间,就是将模块从主模块分开。(虽然往往这都不是瓶颈)
<p style="margin-top: 5 搜索此文相关文章:此文来自: 马开东博客
网址: 站长QQ
上一篇:没有了
说说Python程序的执行过程_博客园名博相关文章
博客园名博_总排行榜
博客园名博_最新
博客园名博_月排行榜
博客园名博_周排行榜
博客园名博_日排行榜
马开东博客专栏
企业软件/开发
硬件/嵌入开发
马开东博客专栏
应用服务器
软件工程/管理/测试
马开东博客专栏
Linux/Unix
马开东博客专栏
开发语言/框架
专题开发/技术/项目
马开东博客专栏
高性能开发
马开东博客专栏

我要回帖

更多关于 python 执行linux命令 的文章

 

随机推荐