详解Python中的下划线

 python  详解Python中的下划线已关闭评论
7月 052017
 

重新温习下下划线, 转自:http://python.jobbole.com/81129/

本文将讨论Python中下划线(_)字符的使用方法。我们将会看到,正如Python中的很多事情,下划线的不同用法大多数(并非所有)只是常用惯例而已。

单下划线(_)

通常情况下,会在以下3种场景中使用:

1、在解释器中:在这种情况下,“_”代表交互式解释器会话中上一条执行的语句的结果。这种用法首先被标准CPython解释器采用,然后其他类型的解释器也先后采用。

2、作为一个名称:这与上面一点稍微有些联系,此时“_”作为临时性的名称使用。这样,当其他人阅读你的代码时将会知道,你分配了一个特定的名称,但是并不会在后面再次用到该名称。例如,下面的例子中,你可能对循环计数中的实际值并不感兴趣,此时就可以使用“_”。

3、国际化:也许你也曾看到”_“会被作为一个函数来使用。这种情况下,它通常用于实现国际化和本地化字符串之间翻译查找的函数名称,这似乎源自并遵循相应的C约定。例如,在Django文档“转换”章节中,你将能看到如下代码:

可以发现,场景二和场景三中的使用方法可能会相互冲突,所以我们需要避免在使用“_”作为国际化查找转换功能的代码块中同时使用“_”作为临时名称。

名称前的单下划线(如:_shahriar)

程序员使用名称前的单下划线,用于指定该名称属性为“私有”。这有点类似于惯例,为了使其他人(或你自己)使用这些代码时将会知道以“_”开头的名称只供内部使用。正如Python文档中所述:

以下划线“_”为前缀的名称(如_spam)应该被视为API中非公开的部分(不管是函数、方法还是数据成员)。此时,应该将它们看作是一种实现细节,在修改它们时无需对外部通知。

正如上面所说,这确实类似一种惯例,因为它对解释器来说确实有一定的意义,如果你写了代码“from <模块/包名> import *”,那么以“_”开头的名称都不会被导入,除非模块或包中的“__all__”列表显式地包含了它们。了解更多请查看“Importing * in Python”。

名称前的双下划线(如:__shahriar)

名称(具体为一个方法名)前双下划线(__)的用法并不是一种惯例,对解释器来说它有特定的意义。Python中的这种用法是为了避免与子类定义的名称冲突。Python文档指出,“__spam”这种形式(至少两个前导下划线,最多一个后续下划线)的任何标识符将会被“_classname__spam”这种形式原文取代,在这里“classname”是去掉前导下划线的当前类名。例如下面的例子:

正如所预料的,“_internal_use”并未改变,而“__method_name”却被变成了“_ClassName__method_name”。此时,如果你创建A的一个子类B,那么你将不能轻易地覆写A中的方法“__method_name”。

这里的功能几乎和Java中的final方法和C++类中标准方法(非虚方法)一样。

名称前后的双下划线(如:__init__)

这种用法表示Python中特殊的方法名。其实,这只是一种惯例,对Python系统来说,这将确保不会与用户自定义的名称冲突。通常,你将会覆写这些方法,并在里面实现你所需要的功能,以便Python调用它们。例如,当定义一个类时,你经常会覆写“__init__”方法。

虽然你也可以编写自己的特殊方法名,但不要这样做。

其实,很容易摆脱这种类型的命名,而只让Python内部定义的特殊名称遵循这种约定。

Python 多版本共存之 pyenv

 python  Python 多版本共存之 pyenv已关闭评论
3月 312017
 

Python 多版本共存之 pyenv

转自:http://seisman.info/python-pyenv.html

经常遇到这样的情况:

  • 系统自带的 Python 是 2.6,自己需要 Python 2.7 中的某些特性;
  • 系统自带的 Python 是 2.x,自己需要 Python 3.x;

此时需要在系统中安装多个 Python,但又不能影响系统自带的 Python,即需要实现 Python 的多版本共存。pyenv 就是这样一个 Python 版本管理器。

安装 pyenv

在终端执行如下命令以安装 pyenv 及其插件:

				
1
				
$ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash

安装完成后,根据提示将如下语句加入到 ~/.bashrc 中:

				
1
2
3
4
				
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)" # 这句可以不加

然后重启终端即可。

安装 Python

查看可安装的版本

				
1
				
$ pyenv install --list

该命令会列出可以用 pyenv 安装的 Python 版本。列表很长,仅列举其中几个:

2.7.8   # Python 2 最新版本
3.4.1   # Python 3 最新版本
anaconda2-4.1.0  # 支持 Python 2.6 和 2.7
anaconda3-4.1.0  # 支持 Python 3.3 和 3.4

其中 2.7.8 和 3.4.1 这种只有版本号的是 Python 官方版本,其他的形如 anaconda2-4.1.0 这种既有名称又有版本后的属于 “衍生版” 或发行版。

安装 Python 的依赖包

在编译 Python 过程中会依赖一些其他库文件,因而需要首先安装这些库文件,已知的一些需要预先安装的库如下。

在 CentOS/RHEL/Fedora 下:

sudo yum install readline readline-devel readline-static
sudo yum install openssl openssl-devel openssl-static
sudo yum install sqlite-devel
sudo yum install bzip2-devel bzip2-libs

在 Ubuntu下:

sudo apt-get update
sudo apt-get install make build-essential libssl-dev zlib1g-dev
sudo apt-get install libbz2-dev libreadline-dev libsqlite3-dev wget curl
sudo apt-get install llvm libncurses5-dev libncursesw5-dev

安装指定版本

用户可以使用 pyenv install 安装指定版本的 python。如果你不知道该用哪一个,推荐你安装 anaconda3 的最新版本,这是一个专为科学计算准备的发行版。

				
1
2
3
4
				
$ pyenv install anaconda3-4.1.0 -v
/tmp/python-build.20170108123450.2752 ~
Downloading Anaconda3-4.1.0-Linux-x86_64.sh...
-> https://repo.continuum.io/archive/Anaconda3-4.1.0-Linux-x86_64.sh

执行该命令后,会从给定的网址中下载安装文件 Anaconda3-4.1.0-Linux-x86_64.sh。但由于文件很大,通常下载需要很久。建议的做法是,先执行以上命令然后马上中断安装,这样就知道 pyenv 要下载的文件的链接。然后用户自己用其他更快的方式(比如wget、迅雷等等)从该链接中下载安装文件,并将安装文件移动到 ~/.pyenv/cache 目录下(该目录默认不存在,用户要自行新建)。

以本文说的情况为例:

  1. 执行 pyenv install anaconda3-4.1.0 -v 获取下载链接
  2. 用wget从下载链接中获取文件 Anaconda3-4.1.0-Linux-x86_64.sh
  3. 将安装包移动到 ~/.pyenv/cache/Anaconda3-4.1.0-Linux-x86_64.sh
  4. 重新执行 pyenv install anaconda3-4.1.0 -v 命令。该命令会检查 cache 目录下已有文件的完整性,若确认无误,则会直接使用该安装文件进行安装。

安装过程中,若出现编译错误,通常是由于依赖包未满足,需要在安装依赖包后重新执行该命令。

更新数据库

在安装 Python 或者其他带有可执行文件的模块之后,需要对数据库进行更新:

				
1
				
$ pyenv rehash

查看当前已安装的 python 版本

				
1
2
3
				
$ pyenv versions
* system (set by /home/seisman/.pyenv/version)
anaconda3-4.1.0

其中的星号表示当前正在使用的是系统自带的 python。

设置全局的 python 版本

				
1
2
3
4
				
$ pyenv global anaconda3-4.1.0
$ pyenv versions
system
* anaconda3-4.1.0 (set by /home/seisman/.pyenv/version)

当前全局的 python 版本已经变成了 anaconda3-4.1.0。也可以使用 pyenv local 或 pyenv shell 临时改变 python 版本。

确认 python 版本

				
1
2
3
4
5
				
$ python
Python 3.5.2 (Anaconda 4.1.0, Sep 10 2014, 17:10:18)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

使用 python

  • 输入 python 即可使用新版本的 python;
  • 系统自带的脚本会以 /usr/bin/python 的方式直接调用老版本的 python,因而不会对系统脚本产生影响;
  • 使用 pip 安装第三方模块时会自动按照到当前的python版本下,不会和系统模块发生冲突。
  • 使用 pip 安装模块后,可能需要执行 pyenv rehash 更新数据库;

pyenv 其他功能

  1. pyenv uninstall 卸载某个版本
  2. pyenv update 更新 pyenv 及其插件

参考

  1. https://github.com/yyuu/pyenv

Python定时任务框架APScheduler

 python  Python定时任务框架APScheduler已关闭评论
3月 242017
 

转自:http://blog.csdn.net/chosen0ne/article/details/7842421

        APScheduler是基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能,使用起来十分方便。提供了基于日期、固定时间间隔以及crontab类型的任务,并且可以持久化任务。基于这些功能,我们可以很方便的实现一个python定时任务系统,写python还是要比Java舒服多了。

1. 安装

        安装过程很简单,可以基于easy_install和源码。

[plain] view plain copy

 print?

  1. easy_install apscheduler  

        或者下载源码,运行命令:

[plain] view plain copy

 print?

  1. python setup.py install  

2. cron job例子

        APScheduler是进程内的调度器,可以定时触发具体的函数,并且可以访问应用的所有变量和函数。在web应用中通过APScheduler实现定时任务是很方便的。下面看例子:

[python] view plain copy

 print?

  1. from apscheduler.scheduler import Scheduler  
  2.   
  3. schedudler = Scheduler(daemonic = False)  
  4.  
  5. @schedudler.cron_schedule(second=‘*’, day_of_week=‘0-4’, hour=‘9-12,13-15’)  
  6. def quote_send_sh_job():  
  7.     print ‘a simple cron job start at’, datetime.datetime.now()  
  8.   
  9. schedudler.start()  

        上面通过装饰器定义了cron job,可以通过函数scheduler.add_cron_job添加,用装饰器更方便。Scheduler构造函数中传入daemonic参数,表示执行线程是非守护的,在Schduler的文档中推荐使用非守护线程:

[plain] view plain copy

 print?

  1. Jobs are always executed in non-daemonic threads.  

        具体cron job的配置参看doc,基本上与Quartz一致。

        在添加job时还有一个比较重要的参数max_instances,指定一个job的并发实例数,默认值是1。默认情况下,如果一个job准备执行,但是该job的前一个实例尚未执行完,则后一个job会失败,可以通过这个参数来改变这种情况。

3. Store

        APScheduler提供了jobstore用于存储job的执行信息,默认使用的是RAMJobStore,还提供了SQLAlchemyJobStore、ShelveJobStore和MongoDBJobStore。APScheduler允许同时使用多个jobstore,通过别名(alias)区分,在添加job时需要指定具体的jobstore的别名,否则使用的是别名是default的jobstore,即RAMJobStore。下面以MongoDBJobStore举例说明。

[python] view plain copy

 print?

  1. import pymongo  
  2. from apscheduler.scheduler import Scheduler  
  3. from apscheduler.jobstores.mongodb_store import MongoDBJobStore  
  4. import time  
  5.   
  6. sched = Scheduler(daemonic = False)  
  7.   
  8. mongo = pymongo.Connection(host=‘127.0.0.1’, port=27017)  
  9. store = MongoDBJobStore(connection=mongo)  
  10. sched.add_jobstore(store, ‘mongo’)        # 别名是mongo  
  11.  
  12. @sched.cron_schedule(second=‘*’, day_of_week=‘0-4’, hour=‘9-12,13-15’, jobstore=‘mongo’)        # 向别名为mongo的jobstore添加job  
  13. def job():  
  14.         print ‘a job’  
  15.         time.sleep(1)  
  16.   
  17. sched.start()  

        注意start必须在添加job动作之后调用,否则会抛错。默认会把job信息保存在apscheduler数据库下的jobs表:

[plain] view plain copy

 print?

  1. > db.jobs.findOne()  
  2. {  
  3.         “_id” : ObjectId(“502202d1443c1557fa8b8d66”),  
  4.         “runs” : 20,  
  5.         “name” : “job”,  
  6.         “misfire_grace_time” : 1,  
  7.         “coalesce” : true,  
  8.         “args” : BinData(0,”gAJdcQEu”),  
  9.         “next_run_time” : ISODate(“2012-08-08T14:10:46Z”),  
  10.         “max_instances” : 1,  
  11.         “max_runs” : null,  
  12.         “trigger” : BinData(0,”gAJjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3JvbgpDcm9uVHJpZ2dlcgpxASmBcQJ9cQMoVQZmaWVsZHNxBF1xBShjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5maWVsZHMKQmFzZUZpZWxkCnEGKYFxB31xCChVCmlzX2RlZmF1bHRxCYhVC2V4cHJlc3Npb25zcQpdcQtjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5leHByZXNzaW9ucwpBbGxFeHByZXNzaW9uCnEMKYFxDX1xDlUEc3RlcHEPTnNiYVUEbmFtZXEQVQR5ZWFycRF1YmgGKYFxEn1xEyhoCYhoCl1xFGgMKYFxFX1xFmgPTnNiYWgQVQVtb250aHEXdWJjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5maWVsZHMKRGF5T2ZNb250aEZpZWxkCnEYKYFxGX1xGihoCYhoCl1xG2gMKYFxHH1xHWgPTnNiYWgQVQNkYXlxHnViY2Fwc2NoZWR1bGVyLnRyaWdnZXJzLmNyb24uZmllbGRzCldlZWtGaWVsZApxHymBcSB9cSEoaAmIaApdcSJoDCmBcSN9cSRoD05zYmFoEFUEd2Vla3EldWJjYXBzY2hlZHVsZXIudHJpZ2dlcnMuY3Jvbi5maWVsZHMKRGF5T2ZXZWVrRmllbGQKcSYpgXEnfXEoKGgJiWgKXXEpY2Fwc2NoZWR1bGVyLnRyaWdnZXJzLmNyb24uZXhwcmVzc2lvbnMKUmFuZ2VFeHByZXNzaW9uCnEqKYFxK31xLChoD05VBGxhc3RxLUsEVQVmaXJzdHEuSwB1YmFoEFULZGF5X29mX3dlZWtxL3ViaAYpgXEwfXExKGgJiWgKXXEyKGgqKYFxM31xNChoD05oLUsMaC5LCXViaCopgXE1fXE2KGgPTmgtSw9oLksNdWJlaBBVBGhvdXJxN3ViaAYpgXE4fXE5KGgJiGgKXXE6aAwpgXE7fXE8aA9Oc2JhaBBVBm1pbnV0ZXE9dWJoBimBcT59cT8oaAmJaApdcUBoDCmBcUF9cUJoD05zYmFoEFUGc2Vjb25kcUN1YmVVCnN0YXJ0X2RhdGVxRE51Yi4=”),  
  13.         “func_ref” : “__main__:job”,  
  14.         “kwargs” : BinData(0,”gAJ9cQEu”)  
  15. }  

        上面就是存储的具体信息。

4.异常处理

        当job抛出异常时,APScheduler会默默的把他吞掉,不提供任何提示,这不是一种好的实践,我们必须知晓程序的任何差错。APScheduler提供注册listener,可以监听一些事件,包括:job抛出异常、job没有来得及执行等。

Constant Event class Triggered when…
EVENT_SCHEDULER_START SchedulerEvent The scheduler is started
EVENT_SCHEDULER_SHUTDOWN SchedulerEvent The scheduler is shut down
EVENT_JOBSTORE_ADDED JobStoreEvent A job store is added to the scheduler
EVENT_JOBSTORE_REMOVED JobStoreEvent A job store is removed from the scheduler
EVENT_JOBSTORE_JOB_ADDED JobStoreEvent A job is added to a job store
EVENT_JOBSTORE_JOB_REMOVED JobStoreEvent A job is removed from a job store
EVENT_JOB_EXECUTED JobEvent A job is executed successfully
EVENT_JOB_ERROR JobEvent A job raised an exception during execution
EVENT_JOB_MISSED JobEvent A job’s execution time is missed

        看下面的例子,监听异常和miss事件,这里用logging模块打印日志,logger.exception()可以打印出异常堆栈信息。

[python] view plain copy

 print?

  1. def err_listener(ev):  
  2.     err_logger = logging.getLogger(‘schedErrJob’)  
  3.     if ev.exception:  
  4.         err_logger.exception(‘%s error.’, str(ev.job))  
  5.     else:  
  6.         err_logger.info(‘%s miss’, str(ev.job))  
  7.   
  8. schedudler.add_listener(err_listener, apscheduler.events.EVENT_JOB_ERROR | apscheduler.events.EVENT_JOB_MISSED)  

        事件的属性包括:

  • job – the job instance in question
  • scheduled_run_time – the time when the job was scheduled to be run
  • retval – the return value of the successfully executed job
  • exception – the exception raised by the job
  • traceback – the traceback object associated with the exception

        最后,需要注意一点当job不以daemon模式运行时,并且APScheduler也不是daemon的,那么在关闭脚本时,Ctrl + C是不奏效的,必须kill才可以。可以通过命令实现关闭脚本:

[plain] view plain copy

 print?

  1. ps axu | grep {脚本名} | grep -v grep | awk ‘{print $2;}’ | xargs kill  

python下format函数介绍

 python  python下format函数介绍已关闭评论
3月 172017
 

转自:http://blog.csdn.net/handsomekang/article/details/9183303

自python2.6开始,新增了一种格式化字符串的函数str.format(),可谓威力十足。那么,他跟之前的%型格式化字符串相比,有什么优越的存在呢?让我们来揭开它羞答答的面纱。

语法

它通过{}和:来代替%。

“映射”示例

通过位置

In [1]: '{0},{1}'.format('kzc',18)  
Out[1]: 'kzc,18'  
In [2]: '{},{}'.format('kzc',18)  
Out[2]: 'kzc,18'  
In [3]: '{1},{0},{1}'.format('kzc',18)  
Out[3]: '18,kzc,18'

字符串的format函数可以接受不限个参数,位置可以不按顺序,可以不用或者用多次,不过2.6不能为空{},2.7才可以。
通过关键字参数

In [5]: '{name},{age}'.format(age=18,name='kzc')  
Out[5]: 'kzc,18'

通过对象属性

class Person:  
    def __init__(self,name,age):  
        self.name,self.age = name,age  
        def __str__(self):  
            return 'This guy is {self.name},is {self.age} old'.format(self=self)
In [2]: str(Person('kzc',18))  
Out[2]: 'This guy is kzc,is 18 old'

通过下标

In [7]: p=['kzc',18]
In [8]: '{0[0]},{0[1]}'.format(p)
Out[8]: 'kzc,18'

有了这些便捷的“映射”方式,我们就有了偷懒利器。基本的Python知识告诉我们,list和tuple可以通过“打散”成普通参数给函数,而dict可以打散成关键字参数给函数(通过*)。所以可以轻松的传个list/tuple/dict给format函数。非常灵活。

格式限定符

它有着丰富的的“格式限定符”(语法是{}中带:号),比如:

填充与对齐
填充常跟对齐一起使用
^、<、>分别是居中、左对齐、右对齐,后面带宽度
:号后面带填充的字符,只能是一个字符,不指定的话默认是用空格填充
比如

In [15]: '{:>8}'.format('189')
Out[15]: '     189'
In [16]: '{:0>8}'.format('189')
Out[16]: '00000189'
In [17]: '{:a>8}'.format('189')
Out[17]: 'aaaaa189'

精度与类型f
精度常跟类型f一起使用

In [44]: '{:.2f}'.format(321.33345)
Out[44]: '321.33'

其中.2表示长度为2的精度,f表示float类型。

其他类型
主要就是进制了,b、d、o、x分别是二进制、十进制、八进制、十六进制。

In [54]: '{:b}'.format(17)
Out[54]: '10001'
In [55]: '{:d}'.format(17)
Out[55]: '17'
In [56]: '{:o}'.format(17)
Out[56]: '21'
In [57]: '{:x}'.format(17)
Out[57]: '11'

用,号还能用来做金额的千位分隔符。

In [47]: '{:,}'.format(1234567890)
Out[47]: '1,234,567,890'

展示类型有很多。2.6的文档里有完整的列表。这里列出一些示例。 'b' - 二进制。将数字以2为基数进行输出。 'c' - 字符。在打印之前将整数转换成对应的Unicode字符串。 'd' - 十进制整数。将数字以10为基数进行输出。 'o' - 八进制。将数字以8为基数进行输出。 'x' - 十六进制。将数字以16为基数进行输出,9以上的位数用小写字母。 'e' - 幂符号。用科学计数法打印数字。用'e'表示幂。 'g' - 一般格式。将数值以fixed-point格式输出。当数值特别大的时候,用幂形式打印。 'n' - 数字。当值为整数时和'd'相同,值为浮点数时和'g'相同。不同的是它会根据区域设置插入数字分隔符。 '%' - 百分数。将数值乘以100然后以fixed-point('f')格式打印,值后面会有一个百分号。 类和类型可以定义一个__format__()方法来控制怎样格式化自己。它会接受一个格式化指示符作为参数: def __format__(self, format_spec):  if isinstance(format_spec, unicode):   return unicode(str(self))  else:   return str(self) 还有一个内置的format()方法可以用来格式化一个值。它会调用类型的__format__()方法,并将格式化指示符作为参数传进去。 >>> format(75.6564, '.2f')  '75.66' 

Ubuntu14.04下Python(cx Oracle)访问Oracle解决方案( PyCharm wrong notification: no module named cx_Oracle)

 python  Ubuntu14.04下Python(cx Oracle)访问Oracle解决方案( PyCharm wrong notification: no module named cx_Oracle)已关闭评论
2月 272017
 

转自:http://blog.itpub.net/26031462/viewspace-1117480/


第一步:下载安装cx_Oracle

下载地址:http://sourceforge.net/projects/cx-oracle/files/5.1.2/下载cx_Oracle的rmp安装文件,注意下载版本最好和Oracle、Python环境保持一致,我当前的环境是Oracle 11g和Python2.7,因此下载的是cx_Oracle-5.1.2-11g-py27-1.x86_64rpm。

不需按RPM方式去安装,直接解压从中取出cx_Oracle.so文件(只需要这个),复制到Python环境的dist-packages目录,我的机器是/usr/local/lib/python2.7/dist-packages/。

解压命令:

>>rpm2cpio file.rpm | cpio -div

第二步:下载安装Oracle instant client

下载地址:http://www.oracle.com/technetwork/indexes/downloads/index.html,从Database栏目的Instant Client链接进入,按当前系统选择对应的下载,我选择的是Instant Client for Linux x86-64

解压下载文件oracle-instantclient11.2-basic-11.2.0.3.0-1.x86_64.rpm ,路径很长实际上只需要其中的so共享库文件,将所有so文件复制到一个单独路径即可,我将他们复制到/opt/oracle-instantclient11.2/lib。

应该有5个文件:

>>pwd
    /opt/oracle-instantclient11.2/lib
>> ls
    libclntsh.so.11.1  libnnz11.so  libocci.so.11.1  libociei.so  libocijdbc11.so

 

第三步:检查并安装libaio1

sudo apt-get install libaio1

 

第四步:配置环境变量

>>cd ~
  >>sudo vim .bashrc

把 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/oracle-instantclient11.2/lib 这行放在里面,保存退出。

最后:测试一下

$ python
>>>import cx_Oracle
>>>conn = cx_Oracle.connect(’username/[email protected]:port/servicename’)
>>>cursor = conn.cursor()
>>>...

一个简单应用:

#! /usr/bin/python
#coding=UTF-8

import cx_Oracle

def hello():
    '''Hello cx_Oracle示例:
    
    1)打印数据库版本信息.
    2)查询表数据.'''
    
    conn = cx_Oracle.connect("codomain/[email protected]:1521/oracle1")
    cur = conn.cursor()
    try:
        print "Oracle Version:%s" % conn.version
        print "Table test rows:"
        cur.execute('select * from test')
        for row in cur:
            print row
    finally:
        cur.close()
        conn.close()

hello() 


按上面步骤安装完成后

测试发现使用终端执行命令行时正常, 

但脚本在pycharm下使用
import cx_Oracle 

总是提示: 

 no module named cx_Oracle

最后发现需要在/etc/ld.so.conf.d目录下自己配置一个.conf 文件,指向上面文章中复制到的/opt/oraclexxx目录, 再执行下ldconfig即可

Xpath语法及python 中lxml库的用法

 python  Xpath语法及python 中lxml库的用法已关闭评论
10月 242016
 

参考来源

lxml用法源自 lxml python 官方文档,更多内容请直接参阅官方文档,本文对其进行翻译与整理。

lxml

XPath语法参考 w3school

w3school

安装

利用 pip 安装即可

XPath语法

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。

节点关系

(1)父(Parent)

每个元素以及属性都有一个父。

在下面的例子中,book 元素是 title、author、year 以及 price 元素的父:

(2)子(Children)

元素节点可有零个、一个或多个子。

在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子:

(3)同胞(Sibling)

拥有相同的父的节点

在下面的例子中,title、author、year 以及 price 元素都是同胞:

(4)先辈(Ancestor)

某节点的父、父的父,等等。

在下面的例子中,title 元素的先辈是 book 元素和 bookstore 元素:

(5)后代(Descendant)

某个节点的子,子的子,等等。

在下面的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素:

选取节点

XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。

下面列出了最有用的路径表达式:

表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。

实例

在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:

路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。

谓语被嵌在方括号中。

实例

在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。

选取若干路径

通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式 结果
//book/title | //book/price 选取 book 元素的所有 title 和 price 元素。
//title | //price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

XPath 运算符

下面列出了可用在 XPath 表达式中的运算符:

运算符 描述 实例 返回值
| 计算两个节点集 //book | //cd 返回所有拥有 book 和 cd 元素的节点集
+ 加法 6 + 4 10
减法 6 – 4 2
* 乘法 6 * 4 24
div 除法 8 div 4 2
= 等于 price=9.80 如果 price 是 9.80,则返回 true。如果 price 是 9.90,则返回 false。
!= 不等于 price!=9.80 如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。
< 小于 price<9.80 如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。
<= 小于或等于 price<=9.80 如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。
> 大于 price>9.80 如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。
>= 大于或等于 price>=9.80 如果 price 是 9.90,则返回 true。如果 price 是 9.70,则返回 false。
or price=9.80 or price=9.70 如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。
and price>9.00 and price<9.90 如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。
mod 计算除法的余数 5 mod 2 1

lxml用法

初步使用

首先我们利用它来解析 HTML 代码,先来一个小例子来感受一下它的基本用法。

首先我们使用 lxml 的 etree 库,然后利用 etree.HTML 初始化,然后我们将其打印出来。

其中,这里体现了 lxml 的一个非常实用的功能就是自动修正 html 代码,大家应该注意到了,最后一个 li 标签,其实我把尾标签删掉了,是不闭合的。不过,lxml 因为继承了 libxml2 的特性,具有自动修正 HTML 代码的功能。

所以输出结果是这样的

不仅补全了 li 标签,还添加了 body,html 标签。

文件读取

除了直接读取字符串,还支持从文件读取内容。比如我们新建一个文件叫做 hello.html,内容为

利用 parse 方法来读取文件。

同样可以得到相同的结果。

XPath实例测试

依然以上一段程序为例

(1)获取所有的 <li> 标签

运行结果

可见,etree.parse 的类型是 ElementTree,通过调用 xpath 以后,得到了一个列表,包含了 5 个 <li> 元素,每个元素都是 Element 类型

(2)获取 <li> 标签的所有 class

运行结果

(3)获取 <li> 标签下 href 为 link1.html 的 <a> 标签

运行结果

(4)获取 <li> 标签下的所有 <span> 标签

注意这么写是不对的

因为 / 是用来获取子元素的,而 <span> 并不是 <li> 的子元素,所以,要用双斜杠

运行结果

(5)获取 <li> 标签下的所有 class,不包括 <li>

运行结果

(6)获取最后一个 <li> 的 <a> 的 href

运行结果

(7)获取倒数第二个元素的内容

运行结果

(8)获取 class 为 bold 的标签名

运行结果

通过以上实例的练习,相信大家对 XPath 的基本用法有了基本的了解。也可以利用 text 方法来获取元素的内容。

大家多加练习!

结语

XPath 是一个非常好用的解析方法,同时也作为爬虫学习的基础,在后面的 selenium 以及 scrapy 框架中都会涉及到这部分知识,希望大家可以把它的语法掌握清楚,为后面的深入研究做好铺垫。

转自:https://cuiqingcai.com/2621.html

用lxml解析HTML

 python  用lxml解析HTML已关闭评论
10月 212016
 

先演示一段获取页面链接代码示例:

#coding=utf-8

from lxml import etree

html = ”’

<html>
<head>
<meta name=”content-type” content=”text/html; charset=utf-8″ />
<title>友情链接查询 – 站长工具</title>
<!– uRj0Ak8VLEPhjWhg3m9z4EjXJwc –>
<meta name=”Keywords” content=”友情链接查询” />
<meta name=”Description” content=”友情链接查询” />

</head>
<body>
<h1 class=”heading”>Top News</h1>
<p style=”font-size: 200%”>World News only on this page</p>
Ah, and here’s some more text, by the way.
<p>… and this is a parsed fragment …</p>

<a href=”http://www.cydf.org.cn/” rel=”nofollow” target=”_blank”>青少年发展基金会</a> 
<a href=”http://www.4399.com/flash/32979.htm” target=”_blank”>洛克王国</a> 
<a href=”http://www.4399.com/flash/35538.htm” target=”_blank”>奥拉星</a> 
<a href=”http://game.3533.com/game/” target=”_blank”>手机游戏</a>
<a href=”http://game.3533.com/tupian/” target=”_blank”>手机壁纸</a>
<a href=”http://www.4399.com/” target=”_blank”>4399小游戏</a> 
<a href=”http://www.91wan.com/” target=”_blank”>91wan游戏</a>

</body>
</html>

”’

page = etree.HTML(html.lower().decode(‘utf-8’))

hrefs = page.xpath(u”//a”)

for href in hrefs:

print href.attrib

 

打印出的结果为:

{‘href’: ‘http://www.cydf.org.cn/’, ‘target’: ‘_blank’, ‘rel’: ‘nofollow’}
{‘href’: ‘http://www.4399.com/flash/32979.htm’, ‘target’: ‘_blank’}
{‘href’: ‘http://www.4399.com/flash/35538.htm’, ‘target’: ‘_blank’}
{‘href’: ‘http://game.3533.com/game/’, ‘target’: ‘_blank’}
{‘href’: ‘http://game.3533.com/tupian/’, ‘target’: ‘_blank’}
{‘href’: ‘http://www.4399.com/’, ‘target’: ‘_blank’}
{‘href’: ‘http://www.91wan.com/’, ‘target’: ‘_blank’}

如果要取得<a></a>之间的内容,

for href in hrefs:

print href.text

结果为:

青少年发展基金会
洛克王国
奥拉星
手机游戏
手机壁纸
4399小游戏
91wan游戏

 

使用lxml前注意事项:先确保html经过了utf-8解码,即code = html.decode(‘utf-8’, ‘ignore’),否则会出现解析出错情况。因为中文被编码成utf-8之后变成 ‘/u2541’ 之类的形式,lxml一遇到 “/”就会认为其标签结束。

 

XPATH基本上是用一种类似目录树的方法来描述在XML文档中的路径。比如用“/”来作为上下层级间的分隔。第一个“/”表示文档的根节点(注意,不是指文档最外层的tag节点,而是指文档本身)。比如对于一个HTML文件来说,最外层的节点应该是”/html”。

定位某一个HTML标签,可以使用类似文件路径里的绝对路径,如page.xpath(u”/html/body/p”),它会找到body这个节点下所有的p标签;也可以使用类似文件路径里的相对路径,可以这样使用:page.xpath(u”//p”),它会找到整个html代码里的所有p标签:

<p style=”font-size: 200%”>World News only on this page</p>
Ah, and here’s some more text, by the way.
<p>… and this is a parsed fragment …</p>

注意:XPATH返回的不一定就是唯一的节点,而是符合条件的所有节点。如上所示,只要是body里的p标签,不管是body的第一级节点,还是第二级,第三级节点,都会被取出来。

如果想进一步缩小范围,直接定位到“<p style=”font-size: 200%”>World News only on this page</p>”要怎么做呢?这就需要增加过滤条件。过滤的方法就是用“[”“]”把过滤条件加上。lxml里有个过滤语法:

p = page.xpath(u”/html/body/p[@style=’font-size: 200%’]”)

或者:p = page.xpath(u”//p[@style=’font-size:200%’]”)

这样就取出了bodystylefont-size:200%p节点,注意:这个p变量是一个lxml.etree._Element对象列表p[0].text结果为World News only on this page,即标签之间的值;p[0].values()结果为font-size: 200%,即所有属性值。其中 @style表示属性style,类似地还可以使用如@name, @id, @value, @href, @src, @class….

如果标签里面没有属性怎么办?那就可以用text(),position()等函数来过滤,函数text()的意思则是取得节点包含的文本。比如:<div>hello<p>world</p>< /div>中,用“div[text()=’hello’]”即可取得这个div,而world则是p的text()。函数position()的意思是取得节点的位置。比如“li[position()=2]”表示取得第二个li节点,它也可以被省略为“li[2]”。

不过要注意的是数字定位和过滤 条件的顺序。比如“ul/li[5][@name=’hello’]”表示取ul下第五项li,并且其name必须是hello,否则返回空。而如果用 “ul/li[@name=’hello’][5]”的意思就不同,它表示寻找ul下第五个name为”hello“的li节点。

此外,“*”可以代替所有的节点名,比如用”/html/body/*/span”可以取出body下第二级的所有span,而不管它上一级是div还是p或是其它什么东东。

而 “descendant::”前缀可以指代任意多层的中间节点,它也可以被省略成一个“/”。比如在整个HTML文档中查找id为“leftmenu”的 div,可以用“/descendant::div[@id=’leftmenu’]”,也可以简单地使用“ //div[@id=’leftmenu’]”。

text = page.xpath(u”/descendant::*[text()]”)表示任意多层的中间节点下任意标签之间的内容,也即实现蜘蛛抓取页面内容功能。以下内容使用text属性是取不到的:

复制代码
<div class="news"> 1. <b>无流量站点清理公告</b>&nbsp;&nbsp;2013-02-22<br /> 取不到的内容 </div> <div class="news"> 2. <strong>无流量站点清理公告</strong>&nbsp;&nbsp;2013-02-22<br />
取不到的内容
</div> <div class="news"> 3. <span>无流量站点清理公告</span>&nbsp;&nbsp;2013-02-22<br />
取不到的内容
</div> <div class="news"> 4. <u>无流量站点清理公告</u>&nbsp;&nbsp;2013-02-22<br />
取不到的内容
</div>
复制代码

这些“取不到的内容”使用这个是取不到的。怎么办呢?别担心,lxml还有一个属性叫做“tail”,它的意思是结束节点前面的内容,也就是说在“<br />”与“</div>”之间的内容。它的源码里面的意思是“text after end tag”

至于“following-sibling::”前缀就如其名所说,表示同一层的下一个节点。”following-sibling::*”就是任意下一个节点,而“following-sibling::ul”就是下一个ul节点。

如果script与style标签之间的内容影响解析页面,或者页面很不规则,可以使用lxml.html.clean模块。模块 lxml.html.clean提供 一个Cleaner 类来清理 HTML 页。它支持删除嵌入或脚本内容、 特殊标记、 CSS 样式注释或者更多。

cleaner = Cleaner(style=True, scripts=True,page_structure=False, safe_attrs_only=False)

print cleaner.clean_html(html)

注意,page_structure,safe_attrs_only为False时保证页面的完整性,否则,这个Cleaner会把你的html结构与标签里的属性都给清理了。使用Cleaner类要十分小心,小心擦枪走火。

 

忽略大小写可以:

page = etree.HTML(html)
keyword_tag = page.xpath(“//meta[translate(@name,’ABCDEFGHJIKLMNOPQRSTUVWXYZ’, ‘abcdefghjiklmnopqrstuvwxyz’)=’keywords’]”)

 

这里有详细的Cleaner类初始化参数说明:http://lxml.de/api/lxml.html.clean.Cleaner-class.html

转自:http://www.cnblogs.com/descusr/archive/2012/06/20/2557075.html

Python中Lock与RLock(递归锁)和Condition

 python  Python中Lock与RLock(递归锁)和Condition已关闭评论
9月 202016
 

在threading模块中,定义两种类型的琐:threading.Lock和threading.RLock。它们之间有一点细微的区别,通过比较下面两段代码来说明:
import threading  
lock = threading.Lock() #Lock对象  
lock.acquire()  
lock.acquire()  #产生了死琐。  
lock.release()  

lock.release()  

import threading  
rLock = threading.RLock()  #RLock对象  
rLock.acquire()  
rLock.acquire() #在同一线程内,程序不会堵塞。  
rLock.release()  
rLock.release()  

这两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。


threading.Condition
可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):
Condition.wait([timeout]):  
wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。
Condition.notify():
唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。
Condition.notify_all()
Condition.notifyAll()
唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

附方法说明(RLock部分贴出了英语官方资料):

Lock.acquire([blocking]) 
获取一把锁,阻塞的或者非阻塞的。

当调用时blocking参数设置为True(默认值),将阻塞直至锁变成unblocked,然后设置它的状态为locked并返回True。

当调用时blocking参数设置为False,将不会阻塞。If a call with blocking set to True would block, return False immediately; otherwise, set the lock to locked and return True.

Lock.release() 
释放一把锁。

当锁是locked时,重置它为unlocked,然后返回。如果其它任何线程正在阻塞等待锁变成unblocked,将只允许它们中一个继续。

在一把没有锁住的锁上调用时,引发一个ThreadError 。 
没有返回值。

RLock对象: 
一个可重入所示一个同步原语,它可以被相同的线程获得多次。Internally, it uses the concepts of “owning thread” and “recursion level” in addition to the locked/unlocked state used by primitive locks. In the locked state, some thread owns the lock; in the unlocked state, no thread owns it.

To lock the lock, a thread calls its acquire() method; this returns once the thread owns the lock. To unlock the lock, a thread calls its release() method. acquire()/release() call pairs may be nested; only the final release() (the release() of the outermost pair) resets the lock to unlocked and allows another thread blocked in acquire() to proceed.

RLock.acquire([blocking=1]) 
Acquire a lock, blocking or non-blocking.

When invoked without arguments: if this thread already owns the lock, increment the recursion level by one, and return immediately. Otherwise, if another thread owns the lock, block until the lock is unlocked. Once the lock is unlocked (not owned by any thread), then grab ownership, set the recursion level to one, and return. If more than one thread is blocked waiting until the lock is unlocked, only one at a time will be able to grab ownership of the lock. There is no return value in this case.

When invoked with the blocking argument set to true, do the same thing as when called without arguments, and return true.

When invoked with the blocking argument set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true.

RLock.release() 
Release a lock, decrementing the recursion level. If after the decrement it is zero, reset the lock to unlocked (not owned by any thread), and if any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed. If after the decrement the recursion level is still nonzero, the lock remains locked and owned by the calling thread.

Only call this method when the calling thread owns the lock. A RuntimeError is raised if this method is called when the lock is unlocked. 
There is no return value.

python with 语句研究

 python  python with 语句研究已关闭评论
9月 202016
 

python中with功能介绍的比较清楚的资料,分享下:

[python] view plain copy

  1. import sys  
  2. class test:  
  3.     def __enter__(self):  
  4.         print “enter”  
  5.         return 1  
  6.     def __exit__(self,*args):  
  7.         print “exit”  
  8.         return True  
  9.   
  10. with test() as t:  
  11.     print “t is not the result of test().it is __enter__ returned”  
  12.     print “t is 1,yes,it is {0}”.format(t)  
  13.     #raise NameError(“hi here”)  
  14.     #sys.exit()  
  15.     print “Never here”  

在使用锁机制时, 经常会用到with 语句

[python] view plain copy

  1. import threading  
  2.   
  3. _lock = threading.Lock()  
  4. with  _lock:  
  5.     …  

如果有一個類包含  __enter__ 方法和 __exit__ 方法,像這樣:

[python] view plain copy

  1. class  controlled_execution:  
  2.        def__enter__(self):  
  3.               set things up  
  4.               return thing  
  5.         def__exit__(self, type, value, traceback):  
  6.               tear things down  

那麼它就可以和with一起使用,像這樣:

with controlled_execution() as thing:
         some code
    當with語句被執行的時候,python對表達式進行求值,對求值的結果(叫做“內容守護者”)調用__enter__方法,並把__enter__
方法的返回值賦給as後面的變量。然後python會執行接下來的代碼段,並且無論這段代碼幹了什麼,都會執行“內容守護者”的__exit__
方法。

作爲額外的紅利,__exit__方法還能夠在有exception的時候看到exception,並且壓制它或者對它做出必要的反應。要壓制exception,只需要返回一個true。比如,下面的__exit__方法吞掉了任何的TypeError,但是讓所有其他的exceptions通過:

[python] view plain copy

  1. def __exit__(self, type, value, traceback):  
  2. return isinstance(value, TypeError)在Python2.5中,file object擁有__enter__和__exit__方法,前者僅僅是返回object自己,而後者則關閉這個文件:  
  3.     >>> f = open(“x.txt”)  
  4.     >>> f  
  5.     <open file ‘x.txt’, mode ‘r’ at 0x00AE82F0>  
  6.     >>> f.__enter__()  
  7.     <open file ‘x.txt’, mode ‘r’ at 0x00AE82F0>  
  8.     >>> f.read(1)  
  9. ‘X’  
  10.     >>> f.__exit__(NoneNoneNone)  
  11.     >>> f.read(1)  
  12.     Traceback (most recent call last):  
  13.       File “<stdin>”, line 1in <module>  
  14.     ValueError: I/O operation on closed file  
  15. 這樣要打開一個文件,處理它的內容,並且保證關閉它,你就可以簡簡單單地這樣做:  
  16. with open(“x.txt”) as f:  
  17.     data = f.read()  
  18.     do something with data我的補充:  
  19. 數據庫的連接好像也可以和with一起使用,我在一本書上看到以下內容:  
  20. conn = sqlite.connect(“somedb”)  
  21. with conn:  
  22.     conn.execute(“insert into sometable values (?,?)”,(“foo”,“bar”))  
  23. 在這個例子中,commit()是在所有with數據塊中的語句執行完畢並且沒有錯誤之後自動執行的,如果出現任何的異常,將執行rollback()  
  24. 操作,再次提示異常。  

转自:http://blog.csdn.net/playerl/article/details/7648699

python的Random模块学习

 python  python的Random模块学习已关闭评论
9月 092016
 

python中的random模块功能太强了,记录下:

在使用python生成随机数时,肯定会想到random模块。random模块实现了各种分布的伪随机(Pseudo-Random)数生成,我们这次来学习下Python的random模块。

对于整数来说,random模块很简单,这个也是很常用的伪随机生成使用方法;但是对于序列(Sequence)来说,random模块能够随机选取序列元素、生成序列的随机分布,或者随机不重复抽样等。

random模块实现的分布主要包括:uniform、normal(Gaussian)、lognormal、negative exponential、gamma、beta等;还有个von Mises,这个是产生角度分布,算法思想可以参考wiki:http://en.wikipedia.org/wiki/Von_Mises_distribution

 

在random模块中,定义了如下几个常量: 

Python代码  收藏代码

  1. NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0)  
  2. TWOPI = 2.0*_pi  
  3. LOG4 = _log(4.0)  
  4. SG_MAGICCONST = 1.0 + _log(4.5)  
  5. BPF = 53        # Number of bits in a float  
  6. RECIP_BPF = 2**-BPF  

  

我们先看下random模块定义的方法: 

Python代码  收藏代码

  1. >>> import random;  
  2. >>> for method in dir(random):  
  3. …   print method;  
  4. …   

  

定义了三个类: 

Python代码  收藏代码

  1. Random:  
  2. SystemRandom:  
  3. WichmannHill :  

这三个类都能产生随机数,其中Random是常用的随机数产生算法,我们主要讨论的随机数产生都是该类的方法;WichmannHill和SystemRandom都继承了Random类,WichmannHill的random方法使用了和Random类相似的随机方法,该算法主要依赖于seed值,有兴趣的同学可以看下理论,我看实现难度不大,但是理论估计是有点难度;SystemRandom是使用操作系统的random产生函数,如unix依赖于/dev/urandom,windows依赖于CryptGenRandom等。 

 

下面我们来看下random模块提供的方法: 

Python代码  收藏代码

  1. random.seed([x]):   

设置random包的seed值,该值对于生成随机数至为重要,如果你不设置的话,默认取系统时间。

  

Python代码  收藏代码

  1. random.random()   

返回随机数,值范围是[0.0,1.0),该方法在后面的各种分布中多次出现,所以该随机数生成算法是random模块的基础。我们来看下random函数的源码: 

Python代码  收藏代码

  1. def random(self):  
  2.    x, y, z = self._seed  
  3.    x = (171 * x) % 30269  
  4.    y = (172 * y) % 30307  
  5.    z = (170 * z) % 30323  
  6.    self._seed = x, y, z  
  7.    return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0   

该算法实现看起来简单,如果想深入理解这个随机数算法的原理,可以参考An efficient and portable pseudo-random number generator(Applied Statistics 31 (1982) 188-190)这篇文章,该文章后面的算法实现和random的源码略有不同,文章参考这里:http://www2.imperial.ac.uk/~hohs/S9/2007-2008/wichmannhill.pdf

  

Python代码  收藏代码

  1. random.expovariate(lambd)  

指数分布

 

Python代码  收藏代码

  1. random.gammavariate(alpha, beta)  

Gamma分布,要求alpha>0且beta>0,注意这个不是Gamma函数。当然在计算过程中用到了Gamma函数。Gamma分布的详细信息参考wiki:http://en.wikipedia.org/wiki/Gamma_distribution

 

 

Python代码  收藏代码

  1. random.gauss(mu, sigma)  
  2. random.normalvariate(mu, sigma)   

这两个都是产生Gauss分布,两者采用不同的思路产生,前者使用统计意义上的计算,后者是依据标准的正态分布定义产生。前者生成速度还要快点,不过在多线程场景下使用要自己加锁控制并发。 

 

Python代码  收藏代码

  1. random.lognormvariate(mu, sigma):  

对数级别的正态分布。

 

Python代码  收藏代码

  1. random.betavariate(alpha, beta)  

Beta Distribution,要求alpha>0beta>0,依赖于gamma分布,通过gamma分布函数生成。

 

Python代码  收藏代码

  1. random.triangular(low, high, mode)  

产生三角分布函数,关于Triangular Distribution的详细信息见http://en.wikipedia.org/wiki/Triangular_distributionwiki里面有比较详细的讨论;看源码会发现该函数的生成同样依赖于random()函数。

 

Python代码  收藏代码

  1. random.uniform(a, b)  

产生[a,b]的均匀分布,该分布产生利用了random()函数,实际上产生的值为a+(b-a)*random()

 

Python代码  收藏代码

  1. random.paretovariate(alpha):Pareto Distribution  
  2. random.vonmisesvariate(mu, kappa):Von Mises Distribution,是针对角度的分布。  
  3. random.weibullvariate(alpha, beta):Weibull Distribution<span> </span>  

这三个分布稍显专业,平时都不怎么用。

 

将Python作用到Sequence上,可以看下下面几个函数的效果

Python代码  收藏代码

  1. random.choice(seq)  
  2. random.sample(population, k)  
  3. random.shuffle(x[, random])  

 

choice函数从seq中随机选择一个元素,sample函数从元素列表中选取k个不重复元素,shuffle函数则对元素列表进行一次随机排列。看下示例:

Python代码  收藏代码

  1. >>> bits=[‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’]  
  2. >>> random.choice(bits)  
  3. ‘a’  
  4. >>> random.choice(bits)  
  5. ‘c’  
  6. >>> random.sample(bits,3)  
  7. [‘c’‘b’‘e’]  
  8. >>> random.sample(bits,3)  
  9. [‘g’‘a’‘c’]  
  10. >>> random.shuffle(bits)  
  11. >>> bits  
  12. [‘a’‘f’‘d’‘g’‘b’‘e’‘c’]  

 

Python代码  收藏代码

  1. random.random()  
  2. random.randrange(stop)  
  3. random.randrange(start, stop[, step])  
  4. random.randint(a, b)  
  5. random.getrandbits(k)<span> </span>  

random函数产生[0.0,1.0)的随机数,这个在上面提到过;randrange函数是在提到的range(start,end,step)中随机选择;randint函数是在[a,b]中选择,注意两边都是闭区间;getrandbits函数实在bit级别上进行控制,控制每个bit上的随机量。

Python代码  收藏代码

  1. >>> random.random()  
  2. 0.6216895046152143  
  3. >>> random.randrange(10)  
  4. 7  
  5. >>> random.randrange(5,10)  
  6. 9  
  7. >>> random.randrange(5,10)  
  8. 6  
  9. >>> random.randrange(5,10)  
  10. 7  
  11. >>> random.randrange(5,10)  
  12. 5  
  13. >>> random.randrange(5,10,2)  
  14. 5  
  15. >>> random.randrange(5,10,2)  
  16. 9  
  17. >>> random.randrange(5,10,2)  
  18. 7  
  19. >>> random.randint(1,100)  
  20. 49  
  21. >>> random.randint(1,100)  
  22. 22  
  23. >>> random.getrandbits(5)  
  24. 27  
  25. >>> random.getrandbits(5)  
  26. 27  
  27. >>> random.getrandbits(5)  
  28. 7  
  29. >>> random.getrandbits(50)  
  30. 259336269183598  
  31. >>> random.getrandbits(500)  
  32. 2123294400168802339423947306484820684208555438132242308767915648686014450077945137455581839262813894933829601172344940098461036686745618482209213922214  
  33. >>> random.getrandbits(5000)  
  34. 4034754137539484179299467597527391507546381474148526154395421207380075606134559180138703425120094793323534549803288574253400061961405474748312233157619180389178319042116709667737968426875719453232825587709299171195574278743656906955409390042725992518977600085740467686975785820692459295094963664868994212901792068886664992509467663579527691907093450609832530263379958186539108800219479153927035711354075963574379567702705107895056023508996779148121923936388548341378859868882424925192771844170677816283953086457527992241139927429905498724725234373412588522642913731667566323782617498119281849336962492061749751663018412752756985945190973968626062918960920916813960732895100632389147211487593464557043805295027860687336511022864551102551287702441650416601162438483314529829096068674259579299557425952074299390480479779787510272694343411355085195312144186003575867190677050695130041384874117375485556935211062489182801151796266461330635349790915122810079710159825931951294785611281623200060903422400093055307371277330083371368887743322247273016355323686859209112857576218973944225428147564652781736490029302922410573312453153416182209839876163339188176414458934726982720923448475009661073041932910018380017325457354357313544645084438508127883399927917698522570586118494954794329286952111267534963812167557444992442451658941414640398737575936221194957286718271011604437241627690160697999192659641775460024935972380618868777518058797753473526196799809754689345865056290961953738953134889706900308020180214258  

 

Python代码  收藏代码

  1. random.getstate()  
  2. random.setstate(state)<span> </span>  

staterandom包内部的一个状态表示,[VERSION,_seed, gauss_next]数组表示,如果你想设置state,请将VERSION设置为1

 

Python代码  收藏代码

  1. random.jumpahead(n)  

random内部维护了生成随机数的流程,jumpahead函数会重置函数生成流程,使得能够在同样的状态下生成下一步的随机函数,不受已经生成的随机数的影响。这个函数在单线程情况下影响不大,但是对于多线程,能够控制在每个线程中随机数生成的初始状态一致。在stackoverflow上有个帖子http://stackoverflow.com/questions/2546039/how-should-i-use-random-jumpahead-in-python比较详细的解释了这个问题,在多线程情况下使用随机数时需要这个的问题在后面的帖子中也有提到,可以详细看下。

 

random包提供的内容还是挺丰富的,除去产生随机数外,对于Sequence的操作也能较好的减小工作量,特别是choicesampleshuffle函数提供的功能。

 

既然提到了random函数,我们在深入理解下random函数的生成。在前面提到,unix系统下random的生成依赖于/dev/urandom,实际上,另外一个产生随机数的文件是/dev/random。两者产生的随机数的原理是利用当前系统的熵池来计算出固定一定数量的随机比特,然后将这些比特作为字节流返回。熵池就是当前系统的环境噪音,熵指的是一个系统的混乱程度,系统噪音可以通过很多参数来评估,如内存的使用,文件的使用量,不同类型的进程数量等等。两者的不同点是后者在不能产生随机数会阻塞(block),而前者不会。所以使用/dev/random比使用/dev/urandom产生的随机数要慢,但是随机性要好。如果使用随机数要求不是特别高的话,/dev/urandom产生随机数足够。

 

关于python的随机数random模块的学习结束。在这里一定要区分random模块和Random类。后者是random模块中定义的类,准确的说,random模块中提供的方法都是Random类中的方法;如果你想使用SystemRandom和WichmannHill类,就需要自己初始化。  

来自:http://isilic.iteye.com/blog/1842316

python中文件及目录的获取方法

 python  python中文件及目录的获取方法已关闭评论
8月 232016
 

1) 获得脚本文件目录绝对路径

os.path.abspath(os.path.dirname(__file__))

2)获得上级目录

os.path.dirname(fileOrDir)

3)获得脚本文件名

os.path.basename(__file__)

4)获得当前工作目录

os.getcwd()

5) 目录连接

os.path.join(dir1, file1)

6)匹配文件

glob.glob(“dir/test*.log”)

python操作日期和时间的方法

 python  python操作日期和时间的方法已关闭评论
8月 162016
 

python操作日期和时间的方法

不管何时何地,只要我们编程时遇到了跟时间有关的问题,都要想到 datetime 和 time 标准库模块,今天我们就用它内部的方法,详解python操作日期和时间的方法。
1.将字符串的时间转换为时间戳

复制代码代码如下:
方法:
a = “2013-10-10 23:40:00”
#将其转换为时间数组
import time
timeArray = time.strptime(a, “%Y-%m-%d %H:%M:%S”)
#转换为时间戳:
timeStamp = int(time.mktime(timeArray))
timeStamp == 1381419600

2.格式更改
如a = “2013-10-10 23:40:00”,想改为 a = “2013/10/10 23:40:00”
方法:先转换为时间数组,然后转换为其他格式

复制代码代码如下:
timeArray = time.strptime(a, “%Y-%m-%d %H:%M:%S”)
otherStyleTime = time.strftime(“%Y/%m/%d %H:%M:%S”, timeArray)

3.时间戳转换为指定格式日期
方法一:利用localtime()转换为时间数组,然后格式化为需要的格式,如:

复制代码代码如下:
timeStamp = 1381419600
timeArray = time.localtime(timeStamp)
otherStyleTime = time.strftime(“%Y-%m-%d %H:%M:%S”, timeArray)
otherStyletime == “2013-10-10 23:40:00”

方法二:

复制代码代码如下:
import datetime
timeStamp = 1381419600
dateArray = datetime.datetime.utcfromtimestamp(timeStamp)
otherStyleTime = dateArray.strftime(“%Y-%m-%d %H:%M:%S”)
otherStyletime == “2013-10-10 23:40:00”

4.获取当前时间并转换为指定日期格式
方法一:

复制代码代码如下:
import time
#获得当前时间时间戳
now = int(time.time())  ->这是时间戳
#转换为其他日期格式,如:”%Y-%m-%d %H:%M:%S”
timeArray = time.localtime(timeStamp)
otherStyleTime = time.strftime(“%Y-%m-%d %H:%M:%S”, timeArray)

方法二:

复制代码代码如下:
import datetime
#获得当前时间
now = datetime.datetime.now()  ->这是时间数组格式
#转换为指定的格式:
otherStyleTime = now.strftime(“%Y-%m-%d %H:%M:%S”)

5.获得三天前的时间的方法

复制代码代码如下:
import time
import datetime
#先获得时间数组格式的日期
threeDayAgo = (datetime.datetime.now() – datetime.timedelta(days = 3))
#转换为时间戳:
timeStamp = int(time.mktime(threeDayAgo.timetuple()))
#转换为其他字符串格式:
otherStyleTime = threeDayAgo.strftime(“%Y-%m-%d %H:%M:%S”)
注:timedelta()的参数有:days,hours,seconds,microseconds

6.给定时间戳,计算该时间的几天前时间

复制代码代码如下:
timeStamp = 1381419600
#先转换为datetime
import datetime
import time
dateArray = datetime.datetime.utcfromtimestamp(timeStamp)
threeDayAgo = dateArray – datetime.timedelta(days = 3)
#参考5,可以转换为其他的任意格式了

7、用Python计算昨天和明天的日期

复制代码代码如下:
>>> import datetime #导入日期时间模块
>>> today = datetime.date.today() #获得今天的日期
>>> print today #输出今天日期
2014-01-04 
>>> yesterday = today – datetime.timedelta(days=1) #用今天日期减掉时间差,参数为1天,获得昨天的日期
>>> print yesterday
2014-01-03 
>>> tomorrow = today + datetime.timedelta(days=1) #用今天日期加上时间差,参数为1天,获得明天的日期
>>> print tomorrow
2014-01-05 
>>>
>>> print “昨天:%s, 今天:%s, 明天:%s” % (yesterday, today, tomorrow) #字符串拼接在一起输出,这3天的日期

昨天:2014-01-03, 今天:2014-01-04, 明天:2014-01-05
8、python里使用time模块来获取当前的时间

复制代码代码如下:

#!/usr/bin/python
import time
print (time.strftime(“%H:%M:%S”))
## 12 hour format ##
print (time.strftime(“%I:%M:%S”))
#:输出
#18:11:30
#6:11:30

9、打印出当前的日期的python程序

复制代码代码如下:
!/usr/bin/python

import time
## dd/mm/yyyy格式
print (time.strftime(“%d/%m/%Y”))

#输出:
11/03/2014

10、使用datetime模块来获取当前的日期和时间

复制代码代码如下:
#!/usr/bin/python
import datetime
i = datetime.datetime.now()
print (“当前的日期和时间是 %s” % i)
print (“ISO格式的日期和时间是 %s” % i.isoformat() )
print (“当前的年份是 %s” %i.year)
print (“当前的月份是 %s” %i.month)
print (“当前的日期是  %s” %i.day)
print (“dd/mm/yyyy 格式是  %s/%s/%s” % (i.day, i.month, i.year) )
print (“当前小时是 %s” %i.hour)
print (“当前分钟是 %s” %i.minute)
print (“当前秒是  %s” %i.second)

附:日期和时间的格式化参数

复制代码代码如下:

%a 星期几的简写
%A 星期几的全称
%b 月分的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年分,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日做为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号

转自:http://www.jb51.net/article/47957.htm

2.5版yield之学习心得

 python  2.5版yield之学习心得已关闭评论
8月 102016
 

转自:http://pnig0s1992.blog.51cto.com/393390/397646/

yield的用法真是要好好体会!!!

在 shhgs 发布了关于《 Py 2.5 what’s new 之 yield》之后,原来我不是特别关注 yield 的用法,因为对于2.3中加入的yield相对来说功能简单,它是作为一个 generator 不可缺少的一条语句,只要包含它的函数即是一个 generator 。但在2.3中,generator 不能重入,不能在运行过程中修改,不能引发异常,你要么是顺序调用,要么就创建一个新的 generator。而且 generator 中的 yield 只是一个语句。但到了 2.5 版之后,情况发生了很在的变化。

在 shhgs 的文章中对于 yield 并没有做太多的描述,也因此让我在理解上产生了许多问题,于是我仔细地研究了 What’s new 和 PEP 342 文档,有了一些体会,描述在下面。

这里不说为什么要对 yield 进行修改,只说功能。

1. yield 成为了表达式,它不再是语句,但可以放在单独的行上。原文:

Redefine “yield” to be an expression, rather than a statement. The current yield statement would become a yield expression whose value is thrown away.

可以看到,如果你还是写成语句形式的话,其实还是一个表达式,只是它的值被扔掉了。

那么一个 yield 表达式可以这样写:

x = yield i
y = x + (yield x)

那么这种机制到底是如何工作的呢?在2.3版很容易理解,你完全可以把 yield 语句理解为一个 “return” 语句,只不过 “return” 完后,函数并不结束,而是断续运行,直到再次遇到 yield 语句。那么到了 2.5 版不仅仅是一个 “return” 语句那么简单了,让我们看完下面关于 send() 的说明再描述它吧。

2. 增加了 send(msg) 方法,因此你可以使用它向 generator 发送消息。原文:

Add a new send() method for generator-iterators, which resumes the generator and “sends” a value that becomes the result of the current yield-expression. The send() method returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value.

执行一个 send(msg) 会恢复 generator 的运行,然后发送的值将成为当前 yield 表达式的返回值。然后 send() 会返回下一个被 generator yield 的值,如果没有下一个可以 yield 的值则引发一个异常。

那么可以看过这其实包含了一次运行,从将msg赋给当前被停住的 yield 表达式开始,到下一个 yield 语句结束,然后返回下一个yield语句的参数,然后再挂起,等待下一次的调用。理解起来的确很复杂,不知道你明白了没有。

那么让我们开始想象一下,把 yield 转变为易于理解的东西吧。

我们可以把 yield 想象成下面的伪代码:

x = yield i ==> put(i); x = wait_and_get()

可以看到,可以理解为先是一个 put(i),这个 i 就是 yield 表达式后面的参数,如果 yield 没有参数,则表示 None。它表示将 i 放到一个全局缓冲区中,相当于返回了一个值。

wait_and_get() 可以理解为一个阻塞调用,它等待着外界来唤醒它,并且可以返回一个值。

经过这种转换就容易理解多了。让我们来看一个例子:

>>> def g(): 
    print ’step 1′ 
    x = yield ‘hello’ 
    print ’step 2′, ‘x=’, x 
    y = 5 + (yield x) 
    print ’step 3′, ‘y=’, y 

很简单,每执行一步都显示一个状态,并且打印出相关变量的值,让我们执行一下看一看。

>>> f = g()
>>> f.next()
step 1
‘hello’

看见什么了。当我们执行 next() 时,代码执行到 x = yield ‘hello’ 就停住了,并且返回了 yield 后面的 ‘hello’。如果我们把上面的程序替换成伪代码看一看是什么样子:

def g():
    print ’step 1′
    put(‘hello’)    #x = yield ‘hello’
    x = wait_and get()
    print ’stpe 2′, ’x=’, x
    put(x)
    y = 5 + wait_and_get()
    print ’step 3′, ‘y=’, y

可以从伪代码看出,第一次调用 next() 时,先返回一个 ‘hello’, 然后程序挂起在 x = wait_and_get() 上,与我们执行的结果相同。

让我们继续:

>>> f.send(5)
step 2 x= 5
5

这次我们使用了 send(5) 而不是 next() 了。要注意 next() 在 2.5 中只算是 send(None) 的一种表现方式。正如伪代码演示的,send()一个值,先是激活 wait_and_get() ,并且通过它返回 send(5) 的参数5,于是 x 的值是 5,然后打印 ’step 2′,再返回 x 的值5,然后程序挂起在 y = 5 + wait_and_get() 上,与运行结果一致。

如果我们继续:

>>> f.send(2)
step 3 y= 7

Traceback (most recent call last): 
  File “<pyshell#13>”, line 1, in <module> 
    f.send(2) 
StopIteration

可以看到先是激活 wait_and_get(),并且通过它返回 send(2) 的参数 2,因此 y 的值是 7,然后执行下面的打印语句,但因为后面没有下一个 yield 语句了,因此程序无法挂起,于是就抛出异常来。

从上面的伪代码的示例和运行结果的分析,我想你应该对 yield 比较清楚了。还有一些要注意的:

  • next()相当于send(None)
  • yield后面没有参数表示返回为None

在文档中有几句话很重要:

Because generator-iterators begin execution at the top of the generator’s function body, there is no yield expression to receive a value when the generator has just been created. Therefore, calling send() with a non-None argument is prohibited when the generator iterator has just started, and a TypeError is raised if this occurs (presumably due to a logic error of some kind). Thus, before you can communicate with a coroutine you must first call next() or send(None) to advance its execution to the first yield expression.

意思是说,第一次调用时要么使用 next() ,要么使用 send(None) ,不能使用 send() 来发送一个非 None 的值,原因就是第一次没有一个 yield 表达式来接受这个值。如果你转为伪代码就很好理解。以上例来说明,转换后第一句是一个 put() 而不是wait_and_get(),因此第一次执行只能返回,而不能接受数据。如果你真的发送了一个非 None 的值,会引发一个 TypeError 的异常,让我们试一试:

>>> f = g() 
>>> f.send(5)

Traceback (most recent call last): 
  File “<pyshell#15>”, line 1, in <module> 
    f.send(5) 
TypeError: can’t send non-None value to a just-started generator

看到了吧,果然出错了。

3. 增加了 throw() 方法,可以用来从 generator 内部来引发异常,从而控制 generator 的执行。试验一下:

>>> f = g() 
>>> f.send(None) 
step 1 
‘hello’ 
>>> f.throw(GeneratorExit)

Traceback (most recent call last): 
  File “<pyshell#17>”, line 1, in <module> 
    f.throw(GeneratorExit) 
  File “<pyshell#6>”, line 3, in g 
    x = yield ‘hello’ 
GeneratorExit 
>>> f.send(5)

Traceback (most recent call last): 
  File “<pyshell#18>”, line 1, in <module> 
    f.send(5) 
StopIteration

可以看出,第一次执行后,我执行了一个f.throw(GeneratorExit),于是这个异常被引发。如果再次执行f.send(5),可以看出 generator 已经被停止了。GeneratorExit 是新增加的一个异常类,关于它的说明:

A new standard exception is defined, GeneratorExit, inheriting from Exception. A generator should handle this by re-raising it (or just not catching it) or by raising StopIteration.

可以看出,增加它的目的就是让 generator 有机会执行一些退出时的清理工作。这一点在 PEP 342 后面的 thumbnail 的例子中用到了。

4. 增加了 close 方法。它用来关闭一个 generator ,它的伪代码如下(从文档中抄来):

def close(self): 
    try: 
        self.throw(GeneratorExit) 
    except (GeneratorExit, StopIteration): 
        pass 
    else: 
        raise RuntimeError(“generator ignored GeneratorExit”) 
# Other exceptions are not caught

因此可以看出,首先向自身引发一个 GeneratorExit 异常,如果 generator 引发了 GeneratorExit 或 StopIteration 异常,则关闭成功。如果 generator 返回了一个值,则引发 RuntimeError 异常。如果是其它的异常则不作处理,相当于向上层繁殖,由上层代码来处理。关于它的例子在 PEP 342 中的 thumbnail 的例子中也有描述。

还有其它几点变化,不再做更深入的描述。

关于 PEP 342 中的例子也很值得玩味。简单说一些,其实我也些也不是很懂也就是明白个大概其吧。

文档中一共有4个例子,其实是两个例子构成。

1,2两个例子完成了一个 thunmbnail 的处理。第一个例子 consumer 其实是一个 decorator ,它实现了对一个 generator 的封装,主要就是用来调用一次 next() 。为什么,因为这样调一次下一次就可以使用 send() 一个非 None 的值了,这样后面的代码在使用 generator 可以直接使用 send() 非 None 值来处理了。第二个例子完成对一系列的图片的缩略图的处理。这里每个图片的处理做成了一个 generator,对于图片文件的处理又是一个顶层的 generator ,在这个顶层的 generator 来调用每个图片处理的 generator。同时这个例子还实现了当异常退出时的一种保护工作:处理完正在处理的图片,然后退出。

3,4两个例子完成了一个 echo 服务器的演示。3完成了一个调度器,4是在3的基础上将listen处理和socket联通后的handle处理都转为可调度的 generator ,在调度器中进行调度。同时可以看到 socket 使用的是非阻塞的处理。

通过以上的学习,我深深地感受到 yield 的确很精巧,这一点还是在与 shhgs 语音交流之后才有更深的体会,许多东西可以通过 generator 表现得更优美和精巧,是一个非常值得玩味的东西。以至于 shhgs 感觉到在 2.5 中 yield 比 with 的意义要大。希望大家一同体会。

不过说实在的,yield 的东西的确有些难于理解,要仔细体会才行。

python中subprocess模块使用简介

 python  python中subprocess模块使用简介已关闭评论
8月 052016
 

subprocess.Popen用来创建子进程。

1)Popen启动新的进程与父进程并行执行,默认父进程不等待新进程结束。

复制代码代码如下:

def TestPopen():
  import subprocess
  p=subprocess.Popen(“dir”,shell=True)
  for i in range(250) :
    print (“other things”)

2)p.wait函数使得父进程等待新创建的进程运行结束,然后再继续父进程的其他任务。且此时可以在p.returncode中得到新进程的返回值。

复制代码代码如下:

def TestWait():
  import subprocess
  import datetime
  print (datetime.datetime.now())
  p=subprocess.Popen(“sleep 10”,shell=True)
  p.wait()
  print (p.returncode)
  print (datetime.datetime.now())

3) p.poll函数可以用来检测新创建的进程是否结束。

复制代码代码如下:

def TestPoll():
  import subprocess
  import datetime
  import time
  print (datetime.datetime.now())
  p=subprocess.Popen(“sleep 10”,shell=True)
  t = 1
  while(t <= 5):
    time.sleep(1)
    p.poll()
    print (p.returncode)
    t+=1
  print (datetime.datetime.now())

4) p.kill或p.terminate用来结束创建的新进程,在windows系统上相当于调用TerminateProcess(),在posix系统上相当于发送信号SIGTERM和SIGKILL。

复制代码代码如下:

def TestKillAndTerminate():
    p=subprocess.Popen(“notepad.exe”)
    t = 1
    while(t <= 5):
      time.sleep(1)
      t +=1
    p.kill()
    #p.terminate()
    print (“new process was killed”)

5) p.communicate可以与新进程交互,但是必须要在popen构造时候将管道重定向。

复制代码代码如下:

def TestCommunicate():
  import subprocess
  cmd = “dir”
  p=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  (stdoutdata, stderrdata) = p.communicate()
  
  if p.returncode != 0:
        print (cmd + “error !”)
  #defaultly the return stdoutdata is bytes, need convert to str and utf8
  for r in str(stdoutdata,encoding=’utf8′ ).split(“\n”):
    print (r)
  print (p.returncode)


def TestCommunicate2():
  import subprocess
  cmd = “dir”
  #universal_newlines=True, it means by text way to open stdout and stderr
  p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  curline = p.stdout.readline()

  while(curline != “”):
        print (curline)
        curline = p.stdout.readline()
  p.wait()
  print (p.returncode)

6) call函数可以认为是对popen和wait的分装,直接对call函数传入要执行的命令行,将命令行的退出code返回。

复制代码代码如下:

def TestCall():
  retcode = subprocess.call(“c:\\test.bat”)
  print (retcode)

7)subprocess.getoutput 和 subprocess.getstatusoutput ,基本上等价于subprocess.call函数,但是可以返回output,或者同时返回退出code和output。

但是可惜的是好像不能在windows平台使用,在windows上有如下错误:'{‘ is not recognized as an internal or external command, operable program or batch file. 

复制代码代码如下:

def TestGetOutput():
  outp = subprocess.getoutput(“ls -la”)
  print (outp)

def TestGetStatusOutput():
  (status, outp) = subprocess.getstatusoutput(‘ls -la’)
  print (status)
  print (outp)

8)总结

popen的参数,第一个为字符串(或者也可以为多个非命名的参数),表示你要执行的命令和命令的参数;后面的均为命名参数;shell=True,表示你前面的传入的命令将在shell下执行,如果你的命令是个可执行文件或bat,不需要指定此参数;stdout=subprocess.PIPE用来将新进程的输出重定向,stderr=subprocess.STDOUT将新进程的错误输出重定向到stdout,stdin=subprocess.PIPE用来将新进程的输入重定向;universal_newlines=True表示以text的方式打开stdout和stderr。

 其他的不推荐使用的模块:

os.system
os.spawn*
os.popen*
popen2.*
commands.*

转自:http://www.jb51.net/article/57725.htm