supervisord管理python进程时print(stdout)日志输出不及时,甚至有缺失问题解决

 python, supervisord  supervisord管理python进程时print(stdout)日志输出不及时,甚至有缺失问题解决已关闭评论
12月 192019
 

使用supervisord管理python进程,代码中print()打印的日志在使用tail -f查看时输出总是不及时,甚至有缺失问题,网络上有下面的几种方式解决:

If you are also using Supervisor to monitor and heal your long running Python projects and observed that output of your program is not being logged to stdout_logfile, it is because Python print statement does not automatically flush output to STDOUT.

One solution is using sys.stdout.flush() frequently to flush the output or if you are using Python 3.3, print(msg, flush=True) is another solution. However, a better solution is to run python with -u parameter (unbuffered mode).

以上总结方法:

  1. 频繁使用sys.stdout.flush()
  2. python3.3以后版本,print使用print(msg, flush=True)
  3. supervisord配置文件里command命令行添加-u参数(这个是最推荐的方法)

举例:

[program:analysis]
command = python -u AnalysisTest.py -port=70%(process_num)02d

python输出有颜色和背景色的文字(\033[显示方式;前景色;背景色m, \033[0m )

 python  python输出有颜色和背景色的文字(\033[显示方式;前景色;背景色m, \033[0m )已关闭评论
11月 212019
 

python中经常有输出文字的需求,特别是如果输出的文字带颜色或者文字有背景色的化更能突出重点,在运维时特别有用,那如何使输出文字带颜色和背景色呢?

#格式:
设置颜色开始 :\033[显示方式;前景色;背景色m

例如:
\033[31;43;1m #—红底黄字高亮显示
\033[0m     #—采用终端默认设置,即缺省颜色,一般可以在文字显示后,添加在末尾以恢复默认

#说明:
前景色:
30 黑色
31  红色
32 绿色
33 黃色
34 蓝色
35 紫红色
36 青蓝色
37 白色

背景色:
40 黑色
41 红色
42 绿色
43 黃色
44 蓝色
45 紫红色
46 青蓝色
47 白色

显示方式:

0 终端默认设置
1 高亮显示
4 使用下划线
5 闪烁
7 反白显示

 

大家可以发现: ‘;’前后的三个参数:显示方式,前景色,背景色是可选参数,可以只写其中的某一个或者某两个;由于表示三个参数不同含义的数值都是唯一没有重复的,所以三个参数的书写先后顺序没有固定要求,系统都可识别,所以参数的前后顺序实际是没有关系,但还是建议大家按规则来。

 

以下举个例子,看下效果(大家特别体会下结尾有和没有“\033[0m”的效果):

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

print("\033[1;33m 我是1;33m的显示效果   \033[3;31m")
print('我是是上一行结尾的3;31m颜色输出效果 ')
print("\n")

print("==========前景色==========")
print("\033[30;1mHello, Welcome To Python! " + "#黑字")   #黑
print("\033[31;1mHello, Welcome To Python! " + "#红字")   #红
print("\033[32;1mHello, Welcome To Python! " + "#绿字")   #绿
print("\033[33;1mHello, Welcome To Python! " + "#黄字")   #黄
print("\033[34;1mHello, Welcome To Python! \033[0m" + "#蓝字")   #蓝
print("\033[35;1mHello, Welcome To Python! \033[0m" + "#紫字")   #紫
print("\033[36;1mHello, Welcome To Python! \033[0m" + "#青字") #青
print("\033[37;1mHello, Welcome To Python! \033[0m" + "#白字") #白
print("==========背景色==========")
print("\033[40;1mHello, Welcome To Python! \033[0m" + "#黑底")   #黑
print("\033[41;1mHello, Welcome To Python! " + "#红底")   #红
print("\033[42;1mHello, Welcome To Python! " + "#绿底")   #绿
print("\033[43;1mHello, Welcome To Python! \033[0m" + "#黄底")   #黄
print("\033[44;1mHello, Welcome To Python! \033[0m" +"#蓝底")   #蓝
print("\033[45;1mHello, Welcome To Python! \033[0m" + "#紫底")   #紫
print("\033[46;1mHello, Welcome To Python! \033[0m" + "#青底")   #青
print("\033[47;1mHello, Welcome To Python! \033[0m" + "#白底")   #白
print("=======结合前景色背景色==========")
print("\033[31;43;1mHello, Welcome To Python! \033[0m" + "#红字黄底")   #红字黄底
print("\033[43;31;1mHello, Welcome To Python! \033[0m" + "#红字黄底(有意调换)")   #红字黄底
print("\033[35;42;1mHello, Welcome To Python! \033[0m" + "#紫字绿底")   #紫字绿底
print("=======结合前景色背景色显示方式==========")
print("\033[30;47;1mHello, Welcome To Python! \033[0m" + "#高亮显示")   #高亮显示
print("\033[30;47;4mHello, Welcome To Python! \033[0m" + "#使用下划线")   #使用下划线


输出效果如下:

Python mac运行 pygame 空白, 图片不显示内容 解决方案

 mac  Python mac运行 pygame 空白, 图片不显示内容 解决方案已关闭评论
10月 092019
 

问题描述: 运行pygame含图片相关的程序,图像不显示。

错误产生环境:macOS MOjave

问题原因:Pygame与MacOS Mojave 不兼容 #见 https://github.com/pygame/pygame/issues/555

可以使用下面一行语句测试是否是这个原因,运行系统示例代码,打开一个窗口,可以听到声音和音乐,但一直是黑色屏幕或白色屏幕表面
python -m pygame.examples.aliens

网上的解决方案:

  1. 将操作系统降级为macOS High Sierra
  2. 安装Miniconda虚拟环境运行pygame

以上方法都比较坑,其实如果为了现在可运行pygame程序,可以使用下面的方法:暂时先安装pygame 2.0的dev版本,等后续2.0正式版本出来后再更新。

以下命令安装pygame 2.0.0.dev4版本:

python3 -m pip install pygame==2.0.0.dev4 –pre –user

再运行原来的程序,done!!!

Python模板-Mako语法介绍

 python  Python模板-Mako语法介绍已关闭评论
9月 052019
 

资源

官网 http://www.makotemplates.org/

文档 http://docs.makotemplates.org/en/latest/

文档翻译 Mako模板入门 http://help.42qu.com/code/mako.html

安装

pip install mako

HelloWorld

from mako.template import Template

mytemplate = Template("hello world!")
print mytemplate.render()

-------------------------

from mako.template import Template
print Template("hello ${data}!").render(data="world")

语法

输出变量 ${x}

数学计算 ${1+1}
the contents within the ${} tag are evaluated by Python directly, so full expressions are OK

filter
${"test"|u}
${"test"|u,trim}
内置filter列表
    u : URL escaping, provided by urllib.quote_plus(string.encode('utf-8'))
    h : HTML escaping, provided by markupsafe.escape(string)
    x : XML escaping
    trim : whitespace trimming, provided by string.strip()
    entity : produces HTML entity references for applicable strings, derived from htmlentitydefs
    unicode (str on Python 3): produces a Python unicode string (this function is applied by default)
    decode.<some encoding> : decode input into a Python unicode with the specified encoding
    n : disable all default filtering; only filters specified in the local expression tag will be applied.

分支
% if x == 5:
    abcd
% endif

循环
% for a in ['1', '2', '3']:
    % if a == '1':
      abc
    % elif a == '2':
      def
    % else:
      gh
    % endif
$ endfor

Python语法
this is a template
<%
    x = db.get_resource('foo')
    y = [z.element for z in x if x.frobnizzle==5]
%>
% for elem in y:
    element: ${elem}
% endfor

换行

加 / 强制不换行


设置变量
% for item in ('apple', 'banana'):
    <%
        isBanana = False
    %>
    % if item == 'banana':
    <%
        isBanana = True
    %>
    %endif
    % if isBanana:
        <span> Bought a banana</span>
    %endif
%endfor

注释

## 这是一个注释.
...text ...

多行
<%doc>
这里是注释
更多注释
</%doc>

模块级别语句

<% %> 的一个变体是 <%! %>,代表模块级别的代码块。其中的代码会在模板的模块级别执行,而不是在模板的 rendering 函数中。

<%!
import mylib
import re

def filter(text):
    return re.sub(r'^@', '', text)
%>

标签

定义了当前模板的总体特性,包括缓存参数,以及模板被调用时期待的参数列表(非必须)
<%page args="x, y, z='default'"/>
<%page cached="True" cache_type="memory"/>


<%include file="header.html"/>
hello world
<%include file="footer.html"/>

%def 标签用于定义包含一系列内容的一个 Python 函数,此函数在当前模板的其他某个地方被调用到
<%def name="myfunc(x)">
this is myfunc, x is ${x}
</%def>
${myfunc(7)}

<%block filter="h">
some <html> stuff.
</%block>
<%block name="header">
    <h2><%block name="title"/></h2>
</%block>

Mako 中的 %namespace 等价于 Python 里的 import 语句。它允许访问其他模板文件的所有 rendering 函数和元数据
<%namespace file="functions.html" import="*"/>

<%inherit file="base.html"/>

处理多行注释:
<%doc>
    these are comments
    more comments
</%doc>

该标签使得 Mako 的词法器对模板指令的常规解析动作停止,并以纯文本的形式返回其整个内容部分
<%text filter="h">
heres some fake mako ${syntax}
<%def name="x()">${x}</%def>
</%text>

有时你想中途停止执行一个模板或者 <%def> 方法,只返回已经收集到的文本信息,可以通过在 Python 代码块中使用 return 语句来完成

% if not len(records):
    No records found.
    <% return %>
% endif

文件template

为提高性能,从文件中加载的 Template, 可以将它产生的模块的源代码以普通 python 模块文件的形式(.py),

缓存到文件系统中。只要加一个参数 module_directory 即可做到这一点:

from mako.template import Template

mytemplate = Template(filename='/docs/mytmpl.txt', module_directory='/tmp/mako_modules')
print mytemplate.render()

当上述代码被 render 的时候,会创建文件 /tmp/mako_modules/docs/mytmpl.txt.py.

下一次 Template 对象被用同样参数调用的时候,就会直接重用该模块文件。

文件TemplateLookup

#有一个对 header.txt 文件的包含引用。而从何处去查找 header.txt, 则由 TemplateLookup 指明,是 "/docs" 目录
from mako.template import Template
from mako.lookup import TemplateLookup

mylookup = TemplateLookup(directories=['/docs'])
mytemplate = Template("""<%include file="header.txt"/> hello world!""", lookup=mylookup)


--------------

#可以直接通过 TemplateLookup 来获取模板对象,利用 TemplateLookup 的 get_template 方法,
#并传递模板的 URI 作为参数
mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
mytemplate = mylookup.get_template("foo.txt")
print mytemplate.render()

-------------
参数
mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace', , collection_size=500)
TemplateLookup 同时也会在内存中缓存一组模板,所以并不是每一次请求都会导致模板的重新编译和模块重新加载。默认 TemplateLookup 的大小没有限制,但你可以通过 collection_size 参数来限制它
以上的 lookup 会持续加载模板到内存中,直到达到 500 的时候,它就会清除掉一定比例的模板缓存项,根据“最近最少访问”原则

另一个 TemplateLookup 相关的标志是  filesystem_checks. 默认为 True,
每一次 get_template() 方法返回模板后,原始的模板文件的 revision time 会和上次加载模板的时间做对比,
如果文件更新,则会加载其内容,并重新编译该模板。
在生产环境下,设置 filesystem_checks 为 False 可以带来一定的性能提升(和具体的文件系统有关)

自己创建context

from mako.template import Template
from mako.runtime import Context
from StringIO import StringIO

mytemplate = Template("hello, ${name}!")
buf = StringIO()
ctx = Context(buf, name="jack")
mytemplate.render_context(ctx)
print buf.getvalue()

其他

1.解决mako中文乱码问题

TemplateLookup(... , output_encoding='utf-8', ...)
Template(..., input_encoding='utf-8')
又在mako的模板文件的首行添加
## -*- encoding:utf8 -*-

单星号与双星号(*和**)在python函数中的应用

 python  单星号与双星号(*和**)在python函数中的应用已关闭评论
9月 042019
 

想不到单星号还能用于解压参数列表!!

在python的函数中经常能看到输入的参数前面有一个或者两个星号:例如

这两种用法其实都是用来将任意个数的参数导入到python函数中。

单星号(*):*args
将所以参数以元组(tuple)的形式导入:
例如:

双星号(**):**kwargs
将参数以字典的形式导入

此外,单星号的另一个用法是解压参数列表:(这种用法让人惊艳!)

当然这两个用法可以同时出现在一个函数中:例如

centos 7.6 下python2.7 安装 MySQL-python问题解决

 python  centos 7.6 下python2.7 安装 MySQL-python问题解决已关闭评论
5月 162019
 

centos7.6 下python2.7版本使用pip install MySQL-python可能出现下面错误:

可能问题一:  ERROR: Complete output from command python setup.py egg_info:
ERROR: sh: mysql_config: 未找到命令

解决办法: yum install mysql-devel

 

再次安装,没问题最好, 如果出现下面问题:

 可能问题二:_mysql.c:29:20: 致命错误:Python.h:没有那个文件或目录
#include “Python.h”

解决办法: yum install python-devel

 

再次安装 : pip install MySQL-python

问题解决!

 

python之turtle库使用介绍

 python  python之turtle库使用介绍已关闭评论
11月 192018
 

turtle库真是太强大了。转自:https://blog.csdn.net/zengxiantao1994/article/details/76588580/

        Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x、纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行的路径上绘制了图形。

turtle绘图的基础知识:
1. 画布(canvas)

        画布就是turtle为我们展开用于绘图区域,我们可以设置它的大小和初始位置。

        设置画布大小

         turtle.screensize(canvwidth=None, canvheight=None, bg=None),参数分别为画布的宽(单位像素), 高, 背景颜色。

        如:turtle.screensize(800,600, “green”)

               turtle.screensize() #返回默认大小(400, 300)

        turtle.setup(width=0.5, height=0.75, startx=None, starty=None),参数:width, height: 输入宽和高为整数时, 表示像素; 为小数时, 表示占据电脑屏幕的比例,(startx, starty): 这一坐标表示矩形窗口左上角顶点的位置, 如果为空,则窗口位于屏幕中心。

        如:turtle.setup(width=0.6,height=0.6)

               turtle.setup(width=800,height=800, startx=100, starty=100)

2. 画笔

2.1 画笔的状态

        在画布上,默认有一个坐标原点为画布中心的坐标轴,坐标原点上有一只面朝x轴正方向小乌龟。这里我们描述小乌龟时使用了两个词语:坐标原点(位置),面朝x轴正方向(方向), turtle绘图中,就是使用位置方向描述小乌龟(画笔)的状态。

2.2 画笔的属性

        画笔(画笔的属性,颜色、画线的宽度等)

        1) turtle.pensize():设置画笔的宽度;

        2) turtle.pencolor():没有参数传入,返回当前画笔颜色,传入参数设置画笔颜色,可以是字符串如”green”, “red”,也可以是RGB 3元组。

        3) turtle.speed(speed):设置画笔移动速度,画笔绘制的速度范围[0,10]整数,数字越大越快。

2.3 绘图命令

         操纵海龟绘图有着许多的命令,这些命令可以划分为3种:一种为运动命令,一种为画笔控制命令,还有一种是全局控制命令。

(1)    画笔运动命令

命令

说明

turtle.forward(distance)

向当前画笔方向移动distance像素长度

turtle.backward(distance)

向当前画笔相反方向移动distance像素长度

turtle.right(degree)

顺时针移动degree°

turtle.left(degree)

逆时针移动degree°

turtle.pendown()

移动时绘制图形,缺省时也为绘制

turtle.goto(x,y)

将画笔移动到坐标为x,y的位置

turtle.penup()

提起笔移动,不绘制图形,用于另起一个地方绘制

turtle.circle()

画圆,半径为正(负),表示圆心在画笔的左边(右边)画圆

setx( )

将当前x轴移动到指定位置

sety( )

将当前y轴移动到指定位置

setheading(angle)

设置当前朝向为angle角度

home()

设置当前画笔位置为原点,朝向东。

dot(r)

绘制一个指定直径和颜色的圆点

 

(2)     画笔控制命令

命令

说明

turtle.fillcolor(colorstring)

绘制图形的填充颜色

turtle.color(color1, color2)

同时设置pencolor=color1, fillcolor=color2

turtle.filling()

返回当前是否在填充状态

turtle.begin_fill()

准备开始填充图形

turtle.end_fill()

填充完成

turtle.hideturtle()

隐藏画笔的turtle形状

turtle.showturtle()

显示画笔的turtle形状

 

(3)    全局控制命令

命令

说明

turtle.clear()

清空turtle窗口,但是turtle的位置和状态不会改变

turtle.reset()

清空窗口,重置turtle状态为起始状态

turtle.undo()

撤销上一个turtle动作

turtle.isvisible()

返回当前turtle是否可见

stamp()

复制当前图形

turtle.write(s [,font=(“font-name”,font_size,”font_type”)])

写文本,s为文本内容,font是字体的参数,分别为字体名称,大小和类型;font为可选项,font参数也是可选项

 

(4)    其他命令

命令

说明

turtle.mainloop()或turtle.done()

启动事件循环 -调用Tkinter的mainloop函数。

必须是乌龟图形程序中的最后一个语句。

turtle.mode(mode=None)

设置乌龟模式(“standard”,“logo”或“world”)并执行重置。如果没有给出模式,则返回当前模式。

模式

初始龟标题

正角度

standard

向右(东)

逆时针

logo

向上(北)

顺时针

turtle.delay(delay=None)

设置或返回以毫秒为单位的绘图延迟。

turtle.begin_poly()

开始记录多边形的顶点。当前的乌龟位置是多边形的第一个顶点。

turtle.end_poly()

停止记录多边形的顶点。当前的乌龟位置是多边形的最后一个顶点。将与第一个顶点相连。

turtle.get_poly()

返回最后记录的多边形。

 

3. 命令详解

        3.1 turtle.circle(radius, extent=None, steps=None)

        描述:以给定半径画圆

        参数:

        radius(半径):半径为正(负),表示圆心在画笔的左边(右边)画圆;

        extent(弧度) (optional);

        steps (optional) (做半径为radius的圆的内切正多边形,多边形边数为steps)。

举例:

circle(50) # 整圆;

circle(50,steps=3) # 三角形;

circle(120, 180) # 半圆

 

实例:

1、太阳花

# coding=utf-8
import turtle
import time

# 同时设置pencolor=color1, fillcolor=color2
turtle.color(“red”, “yellow”)

turtle.begin_fill()
for _ in range(50):
  turtle.forward(200)
  turtle.left(170)
turtle.end_fill()

turtle.mainloop()

2、五角星

# coding=utf-8
import turtle
import time

turtle.pensize(5)
turtle.pencolor(“yellow”)
turtle.fillcolor(“red”)

turtle.begin_fill()
for _ in range(5):
  turtle.forward(200)
  turtle.right(144)
turtle.end_fill()
time.sleep(2)
 
turtle.penup()
turtle.goto(-150,-120)
turtle.color(“violet”)
turtle.write(“Done”, font=(‘Arial’, 40, ‘normal’))

turtle.mainloop()

3、时钟程序

# coding=utf-8
 
import turtle
from datetime import *
 
# 抬起画笔,向前运动一段距离放下
def Skip(step):
    turtle.penup()
    turtle.forward(step)
    turtle.pendown()
 
def mkHand(name, length):
    # 注册Turtle形状,建立表针Turtle
    turtle.reset()
    Skip(-length * 0.1)
    # 开始记录多边形的顶点。当前的乌龟位置是多边形的第一个顶点。
    turtle.begin_poly()
    turtle.forward(length * 1.1)
    # 停止记录多边形的顶点。当前的乌龟位置是多边形的最后一个顶点。将与第一个顶点相连。
    turtle.end_poly()
    # 返回最后记录的多边形。
    handForm = turtle.get_poly()
    turtle.register_shape(name, handForm)
 
def Init():
    global secHand, minHand, hurHand, printer
    # 重置Turtle指向北
    turtle.mode(“logo”)
    # 建立三个表针Turtle并初始化
    mkHand(“secHand”, 135)
    mkHand(“minHand”, 125)
    mkHand(“hurHand”, 90)
    secHand = turtle.Turtle()
    secHand.shape(“secHand”)
    minHand = turtle.Turtle()
    minHand.shape(“minHand”)
    hurHand = turtle.Turtle()
    hurHand.shape(“hurHand”)
   
    for hand in secHand, minHand, hurHand:
        hand.shapesize(1, 1, 3)
        hand.speed(0)
   
    # 建立输出文字Turtle
    printer = turtle.Turtle()
    # 隐藏画笔的turtle形状
    printer.hideturtle()
    printer.penup()
    
def SetupClock(radius):
    # 建立表的外框
    turtle.reset()
    turtle.pensize(7)
    for i in range(60):
        Skip(radius)
        if i % 5 == 0:
            turtle.forward(20)
            Skip(-radius – 20)
           
            Skip(radius + 20)
            if i == 0:
                turtle.write(int(12), align=”center”, font=(“Courier”, 14, “bold”))
            elif i == 30:
                Skip(25)
                turtle.write(int(i/5), align=”center”, font=(“Courier”, 14, “bold”))
                Skip(-25)
            elif (i == 25 or i == 35):
                Skip(20)
                turtle.write(int(i/5), align=”center”, font=(“Courier”, 14, “bold”))
                Skip(-20)
            else:
                turtle.write(int(i/5), align=”center”, font=(“Courier”, 14, “bold”))
            Skip(-radius – 20)
        else:
            turtle.dot(5)
            Skip(-radius)
        turtle.right(6)
        
def Week(t):   
    week = [“星期一”, “星期二”, “星期三”,
            “星期四”, “星期五”, “星期六”, “星期日”]
    return week[t.weekday()]
 
def Date(t):
    y = t.year
    m = t.month
    d = t.day
    return “%s %d%d” % (y, m, d)
 
def Tick():
    # 绘制表针的动态显示
    t = datetime.today()
    second = t.second + t.microsecond * 0.000001
    minute = t.minute + second / 60.0
    hour = t.hour + minute / 60.0
    secHand.setheading(6 * second)
    minHand.setheading(6 * minute)
    hurHand.setheading(30 * hour)
    
    turtle.tracer(False) 
    printer.forward(65)
    printer.write(Week(t), align=”center”,
                  font=(“Courier”, 14, “bold”))
    printer.back(130)
    printer.write(Date(t), align=”center”,
                  font=(“Courier”, 14, “bold”))
    printer.home()
    turtle.tracer(True)
 
    # 100ms后继续调用tick
    turtle.ontimer(Tick, 100)
 
def main():
    # 打开/关闭龟动画,并为更新图纸设置延迟。
    turtle.tracer(False)
    Init()
    SetupClock(160)
    turtle.tracer(True)
    Tick()
    turtle.mainloop()
 
if __name__ == “__main__”:
    main()

效果让人惊叹。

python中 getopt 使用

 python  python中 getopt 使用已关闭评论
4月 242018
 
python中 getopt 模块,
该模块是专门用来处理命令行参数的

函数getopt(args, shortopts, longopts = [])
参数args一般是sys.argv[1:]
shortopts  短格式 (-) 

longopts 长格式(--) 

命令行中输入:
python test.py -i 127.0.0.1 -p 80 55 66

python test.py –ip=127.0.0.1 –port=80 55 66

下面的代码:

try:
options,args = getopt.getopt(sys.argv[1:],”hp:i:”,[“help”,”ip=”,”port=”])
except getopt.GetoptError:
sys.exit()

for name,value in options:
if name in (“-h”,”–help”):
usage()
if name in (“-i”,”–ip”):
print ‘ip is—-‘,value
if name in (“-p”,”–port”)

print 'port is----',value

options,args = getopt.getopt(sys.argv[1:],"hp:i:",["help","ip=","port="])

“hp:i:”
短格式 — h 后面没有冒号:表示后面不带参数,p:和 i:后面有冒号表示后面需要参数

[“help”,”ip=”,”port=”]

长格式 — help后面没有等号=,表示后面不带参数,其他三个有=,表示后面需要参数

返回值 options 是个包含元祖的列表,每个元祖是分析出来的格式信息,比如 [(‘-i’,’127.0.0.1′),(‘-p’,’80’)] ;
 args 是个列表,包含那些没有‘-’或‘–’的参数,比如:[’55’,’66’]

注意:定义命令行参数时,要先定义带’-‘选项的参数,再定义没有‘-’的参数

Python模块搜索路径简介

 python, 开发  Python模块搜索路径简介已关闭评论
2月 142018
 

由于某些原因,在使用 import 时,Python 找不到相应的模块。这时,解释器就会发牢骚 – ImportError。
那么,Python 如何知道在哪里搜索模块的路径呢?
模块搜索路径
当导入名为 hello 的模块时,解释器首先搜索具有该名称的内置模块。如果没有找到,将在变量 sys.path 给出的目录列表中搜索名为 hello.py 的文件。
sys.path 从这些位置初始化:
包含输入脚本的目录(或当前目录,当没有指定文件时)
PYTHONPATH(目录名列表,与 shell 变量 PATH 语法相同)
与安装相关的默认值
>>> import sys
>>> sys.path
[”, ‘/usr/local/lib/python35.zip’, ‘/usr/local/lib/python3.5’, ‘/usr/local/lib/python3.5/plat-linux’,
 ‘/usr/local/lib/python3.5/lib-dynload’, ‘/usr/local/lib/python3.5/site-packages’]
注意: ” 表示当前目录(当前脚本所在的路径)
例如,在 /home/wang/workspace 中创建一个名为 hello.py 的模块,内容如下:
print(‘Hello’)
然后,试图加载该模块:
>>> import os
>>> 
>>> os.getcwd() # 获取当前目录
‘/home/wang’
>>> 
>>> import hello.py

ImportError: No module named ‘hello’
很遗憾,由于 sys.path 中没有包含 /home/wang/workspace 这个路径,所以找不到 hello 模块,从而引发 ImportError。
添加模块搜索路径
为了解决上述问题,需要添加模块搜索路径,可以使用以下几种方式:
1.动态增加路径 
临时生效,对于不经常使用的模块,这通常是最好的方式,因为不必用所有次要模块的路径来污染 PYTHONPATH。
2.修改 PYTHONPATH 变量 
永久生效,对于在许多程序中都使用的模块,可以采用这种方式。这将改变所有 Python 应用的搜索路径,因为启动 Python 时,它会读取这个变量,甚至不同版本的 Python 都会受影响。
3.增加 .pth 文件 
永久生效,这是最简单的、也是推荐的方式。Python 在遍历已知的库文件目录过程中,如果遇到 .pth 文件,便会将其中的路径加入到 sys.path 中,于是 .pth 中所指定的路径就可以被 Python 运行环境找到了。

方法一:动态增加路径
通过 sys 模块的 append() 方法在 Python 环境中增加搜索路径:
>>> import sys
>>> sys.path.append(‘/home/wang/workspace’)
现在,查看搜索路径:
>>> sys.path
[”, ‘/usr/local/lib/python35.zip’, ‘/usr/local/lib/python3.5’, ‘/usr/local/lib/python3.5/plat-linux’,
 ‘/usr/local/lib/python3.5/lib-dynload’, ‘/usr/local/lib/python3.5/site-packages’, ‘/home/wang/workspace’]
>>> 
>>> import hello
Hello
可以看到,路径被成功添加进去了,再次执行导入可以正常使用。

方法二:修改 PYTHONPATH 变量
打开并编辑 bashrc:
$ vim ~/.bashrc
将以下内容附加到文件末尾:
export PYTHONPATH=$PYTHONPATH:/home/wang/workspace
不要忘记重新加载 shell,方法是退出并重新启动,或者在命令行重新加载配置文件:
$ source ~/.bashrc # 或者 . ~/.bashrc

方法三:增加 .pth 文件
查看sys.path中列出的site-packages和dist-packages路径, 比如:在上例中 /usr/local/lib/python3.5/site-packages 下添加一个扩展名为 .pth 的配置文件(例如:extras.pth),内容为要添加的路径:
/home/wang/workspace

使用Gevent编写Python并发程序

 python  使用Gevent编写Python并发程序已关闭评论
1月 242018
 

转自:http://www.missshi.cn/api/view/blog/59a6b2e8e519f50d040000fe

众所周知,Python是非常擅长网络爬虫的。

而对于一个大规模的网络爬虫而言,使用常规的Python编程会使得效率极其低效。

本文主要讲解如何在Python中利用Gevent来大幅提高程序运行的效率。

让我们从一个标准的Python顺序执行代码开始吧!

一段正常运行的Python代码如下:

  1. import requests
  2. import time
  3.  
  4. def request_url(url):
  5.     """
  6.     # 访问一个url并得到响应结果
  7.     :param url:
  8.     :return:
  9.     """
  10.     response = requests.get(url)
  11.     return response.content
  12.  
  13. if __name__ == "__main__":
  14.     # 准备一个待访问的url列表,该列表共包含4 * 10 = 40个url
  15.     url_list = ['https://github.com/',
  16.                 'http://www.missshi.cn:8888/',
  17.                 'https://www.python.org/',
  18.                 'https://www.yahoo.com/'] * 10
  19.     response_list = []
  20.     begin_time = time.time()  #记录当前时间
  21.     for url in url_list:
  22.         print url
  23.         response_content = request_url(url)
  24.         response_list.append(response_content)
  25.     end_time = time.time()  #记录结束时间
  26.     used_time = end_time - begin_time  #计算消耗时间
  27.     print used_time

运行该程序时,我们可以发现它会依次遍历url_list中的每一个url。

在上一个请求得到响应后,再去发送下一个请求。

在我本地调试时,访问40个url的总耗时为33.207s。

而这其中,绝大部分的时间都是在等待接口的响应结果。

Gevent又称之为协程,它是一个有助于大幅度提高网络传输应用型服务的性能。

Gevent的主要实现原理是在运行一个任务时,如果遇到IO或网络相关的操作,会在发送请求后切换到别的任务去处理,而不是在原任务中等待接收响应。这样一来,对于一个大量网络请求的任务而言,它可能起到很好的并发效果。

首先,我们通过一个简单的示例程序了解一下Gevent库的使用。

  1. import gevent
  2.  
  3. def function1(str1, str2):
  4.     print "************"
  5.     print str1
  6.     print str2
  7.  
  8. if __name__ == "__main__":
  9.     task_list = [] #准备一个任务列表
  10.     for i in range(5):
  11.         str1 = "string1_" + str(i)
  12.         str2 = "string2_" + str(i)
  13.         task_list.append(gevent.spawn(function1, str1, str2))  #向任务列表中添加任务
  14.     result = gevent.joinall(task_list)

对于gevent而言,我们需要准备一个任务列表。

任务列表中每一个元素都是一个gevent.spawn()对象。

其中,gevent.spawn()函数可以接收一至多个参数。

第一个参数为任务需要执行的函数,后续的参数为函数对应的输入参数。

最终,当我们得到完成的任务列表后,可以调用gevent.joinall()来执行该列表中的任务。

运行该程序,我们可以得到如下结果:

  1. ************
  2. string1_0
  3. string2_0
  4. ************
  5. string1_1
  6. string2_1
  7. ************
  8. string1_2
  9. string2_2
  10. ************
  11. string1_3
  12. string2_3
  13. ************
  14. string1_4
  15. string2_4

通过观察结果,我们不难发现,该程序仍然是顺序执行的所有的任务,而没有在不同的任务中进行切换。

那么是什么原因呢?

1. 没有包含IO或网络操作,因此没有自动触发切换任务。

2. 也没有手工触发切换进程。

首先,我们先来学习如何手工触发切换任务:

只需要添加一行代码gevent.sleep()后,得到的代码如下:

  1. import gevent
  2.  
  3. def function1(str1, str2):
  4.     print "************"
  5.     print str1
  6.     gevent.sleep()  #添加一行代码
  7.     print str2
  8.  
  9. if __name__ == "__main__":
  10.     task_list = []
  11.     for i in range(5):
  12.         str1 = "string1_" + str(i)
  13.         str2 = "string2_" + str(i)
  14.         task_list.append(gevent.spawn(function1, str1, str2))
  15.     result = gevent.joinall(task_list)

重新运行程序后观察结果:

  1. ************
  2. string1_0
  3. ************
  4. string1_1
  5. ************
  6. string1_2
  7. ************
  8. string1_3
  9. ************
  10. string1_4
  11. string2_0
  12. string2_1
  13. string2_2
  14. string2_3
  15. string2_4

观察结果后,我们可以发现程序在运行到gevent.sleep()后,不会继续在当前任务中执行,而是切换至别的任务中运行。

当然,在应用代码中,我们很少会手工触发gevent.sleep()来切换任务。

而是通过引入一些相关的函数,可以自动起到在面临网络请求的任务时,自动切换任务。

具体的实现方法我们根据如下代码来进行讲解:

  1. import gevent
  2. import requests
  3. import time
  4.  
  5. def request_url(url):
  6.     """
  7.     # 访问一个url并得到响应结果
  8.     :param url:
  9.     :return:
  10.     """
  11.     from gevent import monkey
  12.     monkey.patch_socket()  #引入猴子补丁
  13.     print url
  14.     response = requests.get(url)
  15.     print "response of url:", url
  16.     return response.content
  17.  
  18. if __name__ == "__main__":
  19.     url_list = ['https://github.com/',
  20.                 'http://www.missshi.cn:8888/',
  21.                 'https://www.python.org/',
  22.                 'https://www.yahoo.com/'] * 10
  23.     task_list = []
  24.     response_list = []
  25.     begin_time = time.time()
  26.     for url in url_list:
  27.         task_list.append(gevent.spawn(request_url, url))
  28.     result = gevent.joinall(task_list)
  29.     end_time = time.time()
  30.     used_time = end_time - begin_time
  31.     print used_time

需要注意的是,当我们引入猴子补丁后,会对已经以后的方法进行改写。

因此,不建议在全局范围内引入猴子补丁,最好是在哪部分为并发执行函数,则在哪部分引入猴子补丁。

在引入猴子补丁后,当运行到网络请求时,则会切换至其他任务继续执行,而不是在当前任务中继续等待。

最后,我们来讲解一下针对任务列表中的任务,在执行完成后如何获取并发任务的返回值。

  1. if __name__ == "__main__":
  2.     url_list = ['https://github.com/',
  3.                 'http://www.missshi.cn:8888/',
  4.                 'https://www.python.org/',
  5.                 'https://www.yahoo.com/'] * 10
  6.     task_list = []
  7.     response_list = []
  8.     begin_time = time.time()
  9.     for url in url_list:
  10.         task_list.append(gevent.spawn(request_url, url))
  11.     result = gevent.joinall(task_list)
  12.     response_list = [element.value for element in result]  #从result中获取每个请求的Response
  13.     end_time = time.time()
  14.     used_time = end_time - begin_time
  15.     print used_time

对于gevent.joinall()函数而言,得到的结果是一个迭代器。

其中,迭代器中每一个元素都包含一个属性value,其对应值为每个任务函数的返回值。