<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>易博云天 &#187; Python</title>
	<atom:link href="http://www.eavea.com/blog/index.php/tag/python/feed" rel="self" type="application/rss+xml" />
	<link>http://www.eavea.com/blog</link>
	<description>专注技术：学习、交流、分享、免费，每天进步一点点！</description>
	<lastBuildDate>Mon, 13 Mar 2023 07:04:16 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.6.1</generator>
		<item>
		<title>【Python实战】实时获取tcpdump输出</title>
		<link>http://www.eavea.com/blog/index.php/pythonshizhanshishihuoqutcpdumpshuchu.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonshizhanshishihuoqutcpdumpshuchu.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:37:49 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[抓包]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=56</guid>
		<description><![CDATA[【Python实战】实时获取tcpdump输出 Python实时获取tcpdump输出。 一、背景 今天有个小 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python实战】实时获取tcpdump输出</div>
<blockquote><p>Python实时获取tcpdump输出。</p></blockquote>
<h2 id="toc-heading-1">一、背景</h2>
<p>今天有个小需求，要确认客户端有没有往服务端发送udp包，但为了减轻工作量，不想每次到机器上手动执行tcpdump抓包命令。<br />
于是就写了个脚本来释放人力。</p>
<h2 id="toc-heading-2">二、代码实现</h2>
<p>整个脚本我还加了一些其他功能：时间戳、发送端IP提取，数据包分析，数据持久化等。这里都先去掉，仅记录下简单的实时获取tcpdump输出功能。<br />
代码如下：</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

# sudo tcpdump -tt -l -nn -c 5 -i enp4s0 udp port 514 or 51414

import subprocess

cmd = ['sudo', 'tcpdump', '-tt', '-l', '-nn', '-c', '5', '-i', 'enp4s0', 'udp', 'port', '514', 'or', '51414']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)

while True:
    line = proc.stdout.readline()
    line = line.strip()
    if not line:
        print('tcpdump finished...')
        break
    print(line)
</code></pre>
<p>输出如下（实时）：</p>
<div>bash<i></i><i></i></div>
<pre><code>wenyuanblog@localhost:/home/test/script# python tcpdump_udp.py 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp4s0, link-type EN10MB (Ethernet), capture size 262144 bytes
1499774951.124178 IP 192.168.10.210.41974 &gt; 192.168.10.251.514: UDP, length 139
1499774953.125664 IP 192.168.10.210.54995 &gt; 192.168.10.251.51414: UDP, length 139
1499774956.128498 IP 192.168.10.210.56748 &gt; 192.168.10.251.514: UDP, length 139
1499774958.129918 IP 192.168.10.210.53883 &gt; 192.168.10.251.51414: UDP, length 139
1499774961.132921 IP 192.168.10.210.58803 &gt; 192.168.10.251.514: UDP, length 139
5 packets captured
6 packets received by filter
0 packets dropped by kernel
tcpdump finished...
</code></pre>
<p>以上代码相当于手动执行了 <code>sudo tcpdump -tt -l -nn -c 5 -i enp4s0 udp port 514 or 51414</code> 这条命令。<br />
注意参数-l很重要（行显）。</p>
<h2 id="toc-heading-3">三、代码实现（更新）</h2>
<p>上面的代码能实现tcpdump的功能，但是有一个问题：没有做超时保护。即当程序执行时间过长时kill该进程（这里使用ctrl+c的方式）。<br />
要实现这个功能有很多种方案，例如定时器+多线程等，这里仅演示一种方案，代码如下：</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

# sudo tcpdump -tt -l -nn -c 50 -i enp4s0 udp port 514 or 51414

import subprocess
import signal
import time
import os
import re
import json

class CmdServer:

    def __init__(self, cmd, timeout=120):
        '''
        :param cmd: 执行命令（列表形式）
        :param timeout: 任务超时时间（seconds，进程运行超过该时间，kill该进程）
        :param taskname: 任务名称（根据该任务名称记录命令输出信息）
        '''
        self.cmd = cmd
        self.timeout = timeout
        self.base_path = reduce(lambda x, y: os.path.dirname(x), range(1), os.path.abspath(__file__))
        self.output_path = os.path.join(self.base_path, 'data.json')
        self.udp_flow_list = []
        self.begin_time = int(time.time())

    # 执行tcpdump任务
    def run(self):
        if os.path.exists(self.output_path):
            with open(self.output_path, 'r') as f:
                self.udp_flow_list = json.load(f)

        proc = subprocess.Popen(self.cmd, stdout=subprocess.PIPE)
        stdout = ''

        while proc.poll() == None:
            current_time = int(time.time())
            if current_time - self.begin_time &gt;= self.timeout:
                print('tcpdump timeout...')
                proc.send_signal(signal.SIGINT)
                stdout = proc.stdout.read()

        if proc.poll() is not None and not stdout:
            print('tcpdump finished...')
            stdout = proc.stdout.read()

        stdout_list = stdout.split('\n')
        if stdout_list:
            self._merge_data(stdout_list)
            self._save_data()

    # 数据合并（新增/更新）
    def _merge_data(self, stdout_list):
        for line in stdout_list:
            line = line.strip()
            if not line:
                continue
            timestamp = int(float(line.split('IP')[0].strip())) * 1000
            # 源
            src_ip_port_list = re.findall(r'IP(.+?)&gt;', line)
            if not src_ip_port_list:
                continue
            src_ip_port_str = src_ip_port_list[0].strip()
            src_ip = '.'.join(src_ip_port_str.split('.')[0:4])
            # 目的
            dst_ip_port_list = re.findall(r'&gt;(.+?):', line)
            if not dst_ip_port_list:
                continue
            dst_ip_port_str = dst_ip_port_list[0].strip()
            dst_port = dst_ip_port_str.split('.')[-1]

            # 新增/更新latest_timestamp
            src_item = filter(lambda x: src_ip == x['src_ip'], self.udp_flow_list)
            if src_item:
                src_item[0]['dst_port'] = dst_port
                src_item[0]['latest_timestamp'] = timestamp
            else:
                self.udp_flow_list.append(dict(
                    src_ip=src_ip,
                    dst_port=dst_port,
                    latest_timestamp=timestamp
                ))

    # 保存数据
    def _save_data(self):
        # 写入文件
        with open(self.output_path, 'w') as f:
            json.dump(self.udp_flow_list, f, encoding="utf-8", ensure_ascii=False)

if __name__ == '__main__':
    cmd = ['sudo', 'tcpdump', '-tt', '-l', '-nn', '-c', '5', '-i', 'enp4s0', 'udp', 'port', '514', 'or', '51414']
    cmd_server = CmdServer(cmd, 10)
    cmd_server.run()
</code></pre>
<h2 id="toc-heading-4">四、总结</h2>
<p>比较简单，仅仅是记录下。如果想基于Python的tcpdump做一些业务上的逻辑，可以参考下面的“参考链接”。<br />
参考<br />
<a href="https://blog.csdn.net/wskzgz/article/details/83822780" target="_0" rel="external nofollow noopener noreferrer">https://blog.csdn.net/wskzgz/article/details/83822780</a><br />
<a href="https://blog.csdn.net/wangqiuyun/article/details/46966839" target="_0" rel="external nofollow noopener noreferrer">https://blog.csdn.net/wangqiuyun/article/details/46966839</a><br />
<a href="http://www.cnblogs.com/idvcn/p/8716066.html" target="_0" rel="external nofollow noopener noreferrer">http://www.cnblogs.com/idvcn/p/8716066.html</a><br />
<a href="https://blog.csdn.net/kobeyan/article/details/4344192" target="_0" rel="external nofollow noopener noreferrer">https://blog.csdn.net/kobeyan/article/details/4344192</a><br />
<a href="https://blog.csdn.net/xhw88398569/article/details/48022967" target="_0" rel="external nofollow noopener noreferrer">https://blog.csdn.net/xhw88398569/article/details/48022967</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonshizhanshishihuoqutcpdumpshuchu.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python实战】单变量异常值检测</title>
		<link>http://www.eavea.com/blog/index.php/pythonshizhandanbianliangyichangzhijiance.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonshizhandanbianliangyichangzhijiance.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:36:20 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[数据处理]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=55</guid>
		<description><![CDATA[【Python实战】单变量异常值检测 异常值检测是数据预处理阶段重要的环节，这篇文章介绍下对于单变量异常值检测 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python实战】单变量异常值检测</div>
<blockquote><p>异常值检测是数据预处理阶段重要的环节，这篇文章介绍下对于单变量异常值检测的常用方法，通过Python代码实现。</p></blockquote>
<h2 id="toc-heading-1">一、什么是异常值</h2>
<p>异常值是在数据集中与其他观察值有很大差距的数据点，它的存在，会对随后的计算结果产生不适当的影响，因此检测异常值并加以适当的处理是十分必要的。</p>
<h2 id="toc-heading-2">二、异常值的处理</h2>
<p>异常值并不都是坏的，了解这一点非常重要。只是简单地从数据中删除异常值，而不考虑它们如何影响结果的话，可能会导致灾难。</p>
<blockquote><p>“异常值不一定是坏事。这些只是与其他模式不一致的观察。但事实上异常值非常有趣。例如，如果在生物实验中，某只老鼠没有死亡而其他老鼠都死了，去了解为什么将会非常有趣。这可能会带来新的科学发现。因此，检测异常值非常重要。” —— Pierre Lafaye de Micheaux，统计师</p></blockquote>
<p>对于异常值，一般有如下几种处理：</p>
<ul>
<li>删除含有异常值的记录（是否删除根据实际情况考虑）</li>
<li>将异常值视为缺失值，利用缺失值的处理方法进行处理</li>
<li>平均值修正（前后两个观测值的平均值）</li>
<li>不处理（直接在具有异常值的数据集上进行挖掘）</li>
</ul>
<h2 id="toc-heading-3">三、异常值的类型</h2>
<p>异常值有两种类型：单变量和多变量（Univariate and Multivariate）。单变量异常值是仅由一个变量中的极值组成的数据点，而多变量异常值是至少两个变量的组合异常分数。假设您有三个不同的变量 &#8211; X，Y，Z。如果您在三维空间中绘制这些变量的图形，它们应该形成一种云。位于此云之外的所有数据点都将是多变量异常值。</p>
<p>举个例子：做客户分析，发现客户的年平均收入是80万美元。但是，有两个客户的年收入是4美元和420万美元。这两个客户的年收入明显不同于其他人，那这两个观察结果将被视为异常值，并且是单变量异常值，当我们看到单变量的分布时，可以找到这些异常值。</p>
<p>再举个例子：身高和体重之间的关系。我们对“身高”和“体重”有单变量和双变量分布，如下图所示。</p>
<div><img alt="height_weight_outliers.png" src="https://www.wenyuanblog.com/medias/blogimages/height_weight_outliers.png" data-original="/medias/blogimages/height_weight_outliers.png" /></div>
<p>看箱线图（box plot后面会介绍）没有任何异常值，再看散点图（scatter plot），有两个值在一个特定的身高和体重的平均值以下。可见多变量异常值是n维空间中的异常值，必须通过多维度的分布才能体现出来。</p>
<p>&nbsp;</p>
<p>如果对异常值不太了解，可以阅读这篇<a title="数据探索指南" href="https://www.analyticsvidhya.com/blog/2016/01/guide-data-exploration/?utm_source=outlierdetectionpyod&amp;utm_medium=blog" target="_0" rel="external nofollow noopener noreferrer">《数据探索指南》</a>，上述部分解释也是从中摘录的。<br />
下面，我主要记录下单变量异常值检测的Python实现。</p>
<h2 id="toc-heading-4">四、常用异常检测方法</h2>
<p>原则上模拟数据集需要样本量足够大，这里仅是演示算法，所以就手动写了有限的样本。<br />
异常值的测量标准有很多，比较常见的是描述性统计法、三西格玛法（3σ法）、箱线图等：</p>
<h3 id="toc-heading-5">1. 描述性统计</h3>
<p>基于常识或经验，假定我们认为大于10的数值是不符合常理的。</p>
<p>下面用Python代码实现用描述性统计求异常值：</p>
<pre><code># -*- coding: utf-8 -*-

data = [2.78, 1.79, 4.73, 3.81, 2.78, 1.80, 4.81, 2.79, 1.78, 3.32, 10.8, 100.0]
threshold = 10

# 定义描述性统计识别异常值函数
def descriptive_statistics(data):
    return list(filter(lambda x: x &gt; threshold, data))

outliers = descriptive_statistics(data)
print('异常值共有：{0}个，分别是：{1}'.format(len(outliers), outliers))

# 输出：异常值共有：2个，分别是：[10.8, 100.0]
</code></pre>
<h3 id="toc-heading-6">2. 三西格玛（3σ）</h3>
<p>当数据服从正态分布时，99%的数值应该位于距离均值3个标准差之内的距离，P(|x−μ|&gt;3σ)≤0.003，当数值超出这个距离，可以认为它是异常值。<br />
正态分布状况下，数值分布表：</p>
<table>
<thead>
<tr>
<th>数值分布</th>
<th>在数据中的占比</th>
</tr>
</thead>
<tbody>
<tr>
<td>(μ-σ,μ+σ)</td>
<td>0.6827</td>
</tr>
<tr>
<td>(μ-2σ,μ+2σ)</td>
<td>0.9545</td>
</tr>
<tr>
<td>(μ-3σ,μ+3σ)</td>
<td>0.9973</td>
</tr>
</tbody>
</table>
<p>注：在正态分布中σ代表标准差，μ代表均值，x=μ为图形的对称轴</p>
<p>下面用Python代码实现用三西格玛求异常值：</p>
<pre><code># -*- coding: utf-8 -*-

import pandas as pd
import numpy as np

data = [2.78, 1.79, 4.73, 3.81, 2.78, 1.80, 4.81, 2.79, 1.78, 3.32, 10.8, 100.0]

# 定义3σ法则识别异常值函数
def three_sigma(data_series):
    rule = (data_series.mean() - 3 * data_series.std() &gt; data_series) | (data_series.mean() + 3 * data_series.std() &lt; data_series)
    index = np.arange(data_series.shape[0])[rule]
    outliers = data_series.iloc[index]
    return outliers.tolist()

data_series = pd.Series(data)
outliers = three_sigma(data_series)
print('异常值共有：{0}个，分别是：{1}'.format(len(outliers), outliers))

# 输出：异常值共有：1个，分别是：[100.0]
</code></pre>
<h3 id="toc-heading-7">3. 箱线图（box plot）</h3>
<p>和3σ原则相比，箱线图依据实际数据绘制，真实、直观地表现出了数据分布的本来面貌，且没有对数据作任何限制性要求（3σ原则要求数据服从正态分布或近似服从正态分布）。<br />
其判断异常值的标准以四分位数和四分位距为基础。四分位数给出了数据分布的中心、散布和形状的某种指示，具有一定的鲁棒性，即25%的数据可以变得任意远而不会很大地扰动四分位数，所以异常值通常不能对这个标准施加影响。鉴于此，箱线图识别异常值的结果比较客观，因此在识别异常值方面具有一定的优越性。<br />
箱线图提供了识别异常值的一个标准，即：<br />
上界 = Q3 + 1.5IQR<br />
下界 = Q1 &#8211; 1.5IQR<br />
小于下界或大于上界的值即为异常值。<br />
其中，<br />
Q3称为上四分位数（75%），表示全部观察值中只有四分之一的数据取值比它大；<br />
Q1称为下四分位数（25%），表示全部观察值中只有四分之一的数据取值比它小；<br />
IQR称为四分位数差，这里就是 Q3-Q1；<br />
1.5其实是个参数λ，这个参数通常取1.5（类似于正态分布中的μ±λ）</p>
<p>文字描述可能比较绕，下面用图片来解释下。<br />
<img alt="box_plot.png" src="https://www.wenyuanblog.com/medias/blogimages/box_plot.png" data-original="/medias/blogimages/box_plot.png" /></p>
<blockquote><p>第一四分位数 (Q1)，又称“较小四分位数”，等于该样本中所有数值由小到大排列后第25%的数字。<br />
第二四分位数 (Q2)，又称“中位数”，等于该样本中所有数值由小到大排列后第50%的数字。<br />
第三四分位数 (Q3)，又称“较大四分位数”，等于该样本中所有数值由小到大排列后第75%的数字。<br />
Q3与Q1的差距又称四分位距（InterQuartile Range,IQR）。</p></blockquote>
<p>四分位数的计算参见<a href="https://baike.baidu.com/item/四分位数" target="_0" rel="external nofollow noopener noreferrer">四分位数</a>和<a href="https://blog.csdn.net/ningyanggege/article/details/82625947" target="_0" rel="external nofollow noopener noreferrer">四分位数的计算</a></p>
<p>下面用Python代码实现用箱线图求异常值：</p>
<pre><code># -*- coding: utf-8 -*-

import pandas as pd

data = [2.78, 1.79, 4.73, 3.81, 2.78, 1.80, 4.81, 2.79, 1.78, 3.32, 10.8, 100.0]

# 定义箱线图识别异常值函数
def box_plot(data_series):
    q_abnormal_low = data_series.quantile(0.25) - 1.5 * (data_series.quantile(0.75) - data_series.quantile(0.25))
    q_abnormal_up = data_series.quantile(0.75) + 1.5 * (data_series.quantile(0.75) - data_series.quantile(0.25))
    index = (data_series &lt; q_abnormal_low) | (data_series &gt; q_abnormal_up)
    outliers = data_series.loc[index]
    return outliers.tolist()

sorted_data = sorted(data)
data_series = pd.Series(sorted_data)
outliers = box_plot(data_series)
print('异常值共有：{0}个，分别是：{1}'.format(len(outliers), outliers))

# 输出：异常值共有：2个，分别是：[10.8, 100.0]
</code></pre>
<h2 id="toc-heading-8">五、总结</h2>
<p>以上是最基础的几种单变量异常值检测方法，没有最好的，只有对当前数据场景最合适的。<br />
后期如果涉及机器学习的数据预处理，我会继续学习和研究多变量异常值的检测，相信会有更有意思的一些算法等着我去学习。<br />
参考<br />
异常检测的N种方法，阿里工程师都盘出来了：<a href="https://mp.weixin.qq.com/s/w7SbAHxZsmHqFtTG8ZAXNg" target="_0" rel="external nofollow noopener noreferrer">https://mp.weixin.qq.com/s/w7SbAHxZsmHqFtTG8ZAXNg</a><br />
数据探索指南：<a href="https://www.analyticsvidhya.com/blog/2016/01/guide-data-exploration/?utm_source=outlierdetectionpyod&amp;utm_medium=blog" target="_0" rel="external nofollow noopener noreferrer">https://www.analyticsvidhya.com/blog/2016/01/guide-data-exploration/?utm_source=outlierdetectionpyod&amp;utm_medium=blog</a><br />
Tukey method：<a href="https://en.wikipedia.org/wiki/Tukey%27s_range_test" target="_0" rel="external nofollow noopener noreferrer">https://en.wikipedia.org/wiki/Tukey%27s_range_test</a><br />
图基（Tukey）检验：一种值得倍加推崇的检验方法：<a href="http://blog.sina.com.cn/s/blog_60be90250100eojy.html" target="_0" rel="external nofollow noopener noreferrer">http://blog.sina.com.cn/s/blog_60be90250100eojy.html</a><br />
如何从大量数据中找出异常值：<a href="https://blog.csdn.net/wangyangzhizhou/article/details/83854951" target="_0" rel="external nofollow noopener noreferrer">https://blog.csdn.net/wangyangzhizhou/article/details/83854951</a><br />
概率论与数理统计 第四版 浙江大学出版社：<a href="https://book.douban.com/subject/3165271/" target="_0" rel="external nofollow noopener noreferrer">https://book.douban.com/subject/3165271/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonshizhandanbianliangyichangzhijiance.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python进阶】经典排序算法</title>
		<link>http://www.eavea.com/blog/index.php/pythonjinjiejingdianpaixusuanfa.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonjinjiejingdianpaixusuanfa.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:33:28 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=54</guid>
		<description><![CDATA[【Python进阶】经典排序算法 Python实现七种经典排序算法。 一、冒泡排序 介绍 冒泡排序是排序算法中 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python进阶】经典排序算法</div>
<blockquote><p>Python实现七种经典排序算法。</p></blockquote>
<h2 id="toc-heading-1">一、冒泡排序</h2>
<h3 id="toc-heading-2">介绍</h3>
<ul>
<li>冒泡排序是排序算法中较为简单的一种，英文称为 Bubble Sort。它遍历所有的数据，每次对相邻元素进行两两比较，如果顺序和预先规定的顺序不一致，则进行位置交换；这样一次遍历会将最大或最小的数据上浮到顶端，之后再重复同样的操作，直到所有的数据有序。</li>
<li>如果有n个数据，那么需要的比较次数，所以当数据量很大时，冒泡算法的效率并不高。</li>
<li>当输入的数据是反序时，花的时间最长，当输入的数据是正序时，时间最短。</li>
</ul>
<h3 id="toc-heading-3">步骤</h3>
<ol>
<li>从前往后依次比较相邻的元素。如果前一个元素比后一个二元素大，交换二者位置。（数列遍历一遍后，最大数被移动到末尾)。</li>
<li>重复步骤1（已确定位置的数据不需要再参与排序）。</li>
<li>完成排序。</li>
</ol>
<h3 id="toc-heading-4">实现</h3>
<p>动画演示</p>
<div><img alt="bubble_sort.gif" src="https://www.wenyuanblog.com/medias/blogimages/bubble_sort.gif" data-original="/medias/blogimages/bubble_sort.gif" /></div>
<p>python代码实现</p>
<p>&nbsp;</p>
<pre><code>    def bubble_sort(alist):
        for i in range(len(alist)-1,0,-1):
            for j in range(i):
                if alist[j]&gt;alist[j+1]:
                    alist[j],alist[j+1]=alist[j+1],alist[j]
</code></pre>
<p>优化：某一趟遍历如果没有数据交换，则说明已经排好序了，因此不用再进行迭代了。用一个标记记录这个状态即可。设置标志位flag，如果发生了交换flag设置为true；如果没有交换就设置为false。 这样当一轮比较结束后如果flag仍为false，即：这一轮没有发生交换，说明数据的顺序已经排好，没有必要继续进行下去,排序结束。</p>
<h2 id="toc-heading-5">二、选择排序</h2>
<h3 id="toc-heading-6">介绍</h3>
<ul>
<li>选择排序简单直观，英文称为 Selection Sort，先在数据中找出最大或最小的元素，放到序列的起始；然后再从余下的数据中继续寻找最大或最小的元素，依次放到排序序列中，直到所有数据样本排序完成。很显然，选择排序也是一个费时的排序算法，无论什么数据，都需要 O(n²) 的时间复杂度，不适宜大量数据的排序。</li>
<li>选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上，则它不会被移动。选择排序每次交换一对元素，它们当中至少有一个将被移到其最终位置上，因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动元素的排序方法中，选择排序属于非常好的一种。</li>
</ul>
<h3 id="toc-heading-7">步骤</h3>
<ol>
<li>首先在未排序序列中找到最小（大）元素，存放到排序序列的起始位置 。</li>
<li>再从剩余未排序元素中继续寻找最小（大）元素，然后放到已排序序列的末尾。</li>
<li>重复步骤2，直到所有元素均排序完毕。</li>
</ol>
<h3 id="toc-heading-8">实现</h3>
<p>动画演示<br />
<img alt="selection_sort.gif" src="https://www.wenyuanblog.com/medias/blogimages/selection_sort.gif" data-original="/medias/blogimages/selection_sort.gif" /><br />
python代码实现</p>
<pre><code>def select_sort(alist)：
    for i in range(len(alist)-1):
        min_index=i
        for j in range(i+1,len(alist)):
            if alist[j]&lt;alist[min_index]:
               min_index=j
        if min_index!=i:
             alist[i],alist[min_index] = alist[min_index],alsit[i]
</code></pre>
<h2 id="toc-heading-9">三、插入排序</h2>
<h3 id="toc-heading-10">介绍</h3>
<ul>
<li>插入排序英文称为 Insertion Sort，它通过构建有序序列，对于未排序的数据序列，在已排序序列中从后向前扫描，找到相应的位置并插入，类似打扑克牌时的码牌。插入排序有一种优化的算法，可以进行拆半插入。</li>
<li>基本思路是先将待排序序列的第一个元素看做一个有序序列，把第二个元素到最后一个元素当成是未排序序列；然后从头到尾依次扫描未排序序列，将扫描到的每个元素插入有序序列的适当位置，直到所有数据都完成排序；如果待插入的元素与有序序列中的某个元素相等，则将待插入元素插入到相等元素的后面。</li>
</ul>
<h3 id="toc-heading-11">步骤</h3>
<ol>
<li>将第一待排序序列第一个元素看做一个有序序列，把第二个元素到最后一个元素当成是未排序序列。</li>
<li>从头到尾依次扫描未排序序列，将扫描到的每个元素插入有序序列的适当位置。（如果待插入的元素与有序序列中的某个元素相等，则将待插入元素插入到相等元素的后面）。</li>
</ol>
<h3 id="toc-heading-12">实现</h3>
<p>动画演示<br />
<img alt="insertion_sort.gif" src="https://www.wenyuanblog.com/medias/blogimages/insertion_sort.gif" data-original="/medias/blogimages/insertion_sort.gif" /><br />
python代码实现</p>
<pre><code>def insert_sort(alist):
    for i in range(1,len(alsit)):
        for j in range(i,0,-1):
            if alist[j]&lt;alist[j-1]:
                alist[j-1],alist[j]=alist[j],alist[j-1]
</code></pre>
<h2 id="toc-heading-13">四、快速排序</h2>
<h3 id="toc-heading-14">介绍</h3>
<ul>
<li>快速排序，英文称为 Quicksort，又称划分交换排序 partition-exchange sort，简称快排。</li>
<li>快速排序使用分治策略来把一个序列分为两个子序列。首先从数列中挑出一个元素，并将这个元素称为「基准」pivot。重新排序数列，所有比基准值小的元素摆放在基准前面，所有比基准值大的元素摆在基准后面，相同的数可以到任何一边。在这个分区结束之后，该基准就处于数列的中间位置。这个称为分区partition操作。之后，在子序列中继续重复这个方法，直到最后整个数据序列排序完成。</li>
<li>在平均状况下，排序n个项目要 O(nlogn) 次比较。在最坏状况下则需要 O(n²) 次比较，但这种状况并不常见。事实上，快速排序通常明显比其他算法更快，因为它的内部循环可以在大部分的架构上很有效率地达成。</li>
</ul>
<h3 id="toc-heading-15">步骤</h3>
<ol>
<li>从数列中挑出一个元素，称为”基准”(pivot)。</li>
<li>重新排序数列，所有元素比基准值小的摆放在基准前面，所有元素比基准值大的摆在基准的后面（相同的数可以到任一边）。在这个分区结束之后，该基准就处于数列的中间位置。这个称为分区（partition）操作。</li>
<li>递归地（recursive）把小于基准值元素的子数列和大于基准值元素的子数列排序。</li>
</ol>
<p>递归的最底部情形，是数列的大小是零或一，也就是永远都已经被排序好了。虽然一直递归下去，但是这个算法总会结束，因为在每次的迭代（iteration）中，它至少会把一个元素摆到它最后的位置去。</p>
<h3 id="toc-heading-16">实现</h3>
<p>动画演示<br />
<img alt="quick_sort.gif" src="https://www.wenyuanblog.com/medias/blogimages/quick_sort.gif" data-original="/medias/blogimages/quick_sort.gif" /><br />
python代码实现</p>
<pre><code>def quick_sort(alist,start,end):
    if start&gt;=end:
        return
    pivot= alist[start]
    low = start
    high = end
    while low &lt; high:
        while low &lt; high and pivot &lt; alist[high]:
            high-=1
       alist[low] = alist[high]
       while low &lt; high and alist[low] &lt; pivot:
           low+=1
       alist[high] = alist[low]
   alsit[low] = pivot
   quick_sort(alist,start,low-1)
   quick_sort(alist,low+1,end)
</code></pre>
<h2 id="toc-heading-17">五、希尔排序</h2>
<h3 id="toc-heading-18">介绍</h3>
<ul>
<li>希尔排序也称递减增量排序，是插入排序的一种改进版本，英文称为 Shell Sort，效率虽高，但它是一种不稳定的排序算法。</li>
<li>插入排序在对几乎已经排好序的数据操作时，效果是非常好的；但是插入排序每次只能移动一位数据，因此插入排序效率比较低。</li>
<li>希尔排序在插入排序的基础上进行了改进，它的基本思路是先将整个数据序列分割成若干子序列分别进行直接插入排序，待整个序列中的记录基本有序时，再对全部数据进行依次直接插入排序。</li>
</ul>
<h3 id="toc-heading-19">步骤</h3>
<ol>
<li>将元素分为n列，并对每列进行插入排序。</li>
<li>将n列元素按行进行合并。</li>
<li>重复步骤1-2，其中元素的列数为上次的一半。</li>
</ol>
<h3 id="toc-heading-20">实现</h3>
<p>动画演示<br />
<img alt="shell_sort.gif" src="https://www.wenyuanblog.com/medias/blogimages/shell_sort.gif" data-original="/medias/blogimages/shell_sort.gif" /><br />
python代码实现</p>
<pre><code>def shell_sort(alist):
    gap=len(alist)//2
    while gap&gt;0:
        for i in range(gap,len(alist)):
            j=i
            while (j-gap)&gt;=0 and alist[j-gap]&gt;alist[j]:
                alist[j-gap],alsit[j]=alist[j],alist[j-gap]
                j-=gap
         gap//=2 
</code></pre>
<h2 id="toc-heading-21">六、归并排序</h2>
<h3 id="toc-heading-22">介绍</h3>
<ul>
<li>归并排序英文称为 Merge Sort，它是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组，再合并数组。</li>
<li>将数组分解最小之后，然后合并两个有序数组，基本思路是比较两个数组的最前面的数，谁小就先取谁，取了后相应的指针就往后移一位。然后再比较，直至一个数组为空，最后把另一个数组的剩余部分复制过来即可。</li>
<li>归并排序严格遵循从左到右或从右到左的顺序合并子数据序列, 它不会改变相同数据之间的相对顺序, 因此归并排序是一种稳定的排序算法。</li>
</ul>
<h3 id="toc-heading-23">步骤</h3>
<ol>
<li>归分解，将数组分解成left和right。如果这两个数组内部数据是有序的（转向步骤2-4）；如果无序，则对数组进行二分，直至分解出的小组只有一个元素，此时认为该小组内部有序。</li>
<li>合并两个有序数组，比较两个数组的最前面的数，谁小就先取谁，该数组的指针往后移一位。</li>
<li>重复步骤2，直至一个数组为空。</li>
<li>最后把另一个数组的剩余部分复制过来即可。</li>
</ol>
<h3 id="toc-heading-24">实现</h3>
<p>动画演示<br />
<img alt="merge_sort.gif" src="https://www.wenyuanblog.com/medias/blogimages/merge_sort.gif" data-original="/medias/blogimages/merge_sort.gif" /><br />
python代码实现</p>
<pre><code>def merge_sort(alist):
    if len(alist)&lt;=1:
        return alist
    mid = len(alist)//2
    left=merge_sort(alsit[:mid])
    right=merge_sort(alist[mid:])
    return sort(left,right)
def sort(left,right):
    l,r=0,0
    result=[]
    while l&lt;len(left) and r&lt;len(right):
        if left[l]&lt;=right[r]:
            result.append(left[l])
            l+=1
        else:
            result.append(right[r])
            r+=1
    result+=left[l:]
    result+=right[r:]
return result
</code></pre>
<h2 id="toc-heading-25">七、堆排序</h2>
<h3 id="toc-heading-26">介绍</h3>
<ul>
<li>堆排序，英文称 Heapsort，是指利用堆这种数据结构所设计的一种排序算法。堆排序在 top K问题中使用比较频繁。堆排序是采用二叉堆的数据结构来实现的，虽然实质上还是一维数组。二叉堆是一个近似完全二叉树。</li>
<li>二叉堆具有以下性质：
<ul>
<li>父节点的键值总是大于或等于（小于或等于）任何一个子节点的键值。</li>
<li>每个节点的左右子树都是一个二叉堆（都是最大堆或最小堆）。</li>
</ul>
</li>
</ul>
<h3 id="toc-heading-27">步骤</h3>
<ol>
<li>根据初始数组取构建一个完全二叉树，保证所有的父节点比子节点的数值大。</li>
<li>每次交换第一个和最后一个元素，输出最后一个元素（最大值），然后把剩下元素重新调整为最大堆。</li>
</ol>
<h3 id="toc-heading-28">实现</h3>
<p>动画演示<br />
<img alt="heap_sort.gif" src="https://www.wenyuanblog.com/medias/blogimages/heap_sort.gif" data-original="/medias/blogimages/heap_sort.gif" /><br />
python代码实现</p>
<pre><code>def heap_sort(alist):
    n = len(alist)
    first = int(n/2-1)
    for start in range(first,-1,-1):
        max_heapify(alist,start,n-1)
    for end in range(n-1,0,-1):
        alist[end],alist[0]=alist[0],alist[end]
        max_heapify(alist,0,end-1)
    return alsit

def max_heapify(alist,start,end):
    root = start
    while True:
        child = root*2+1
        if child&gt;end :
            break
        if child+1&lt;=end and alist[child]&lt;alist[child+1]:
            child+=1
        if alist[root]&lt;alist[child]:
            alist[root],alist[child]=alist[child],alist[root]
            root=child
        else:
            break
</code></pre>
<h2 id="toc-heading-29">总结：常见排序算法效率比较</h2>
<p><img alt="sorting_algorithms_compare.png" src="https://www.wenyuanblog.com/medias/blogimages/sorting_algorithms_compare.png" data-original="/medias/blogimages/sorting_algorithms_compare.png" /><br />
参考<br />
<a href="https://github.com/hustcc/JS-Sorting-Algorithm" target="_0" rel="external nofollow noopener noreferrer">https://github.com/hustcc/JS-Sorting-Algorithm</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonjinjiejingdianpaixusuanfa.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python进阶】Pythonic风格整理</title>
		<link>http://www.eavea.com/blog/index.php/pythonjinjiepythonicfenggezhengli.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonjinjiepythonicfenggezhengli.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:29:29 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=53</guid>
		<description><![CDATA[【Python进阶】Pythonic风格整理 所谓Pythonic，就是代码风格符合Python的特点，合理使 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python进阶】Pythonic风格整理</div>
<blockquote><p>所谓Pythonic，就是代码风格符合Python的特点，合理使用“语法糖”，使代码简洁优美，更具可读性，便于维护和修改。</p></blockquote>
<h2 id="toc-heading-1">一、Python之禅</h2>
<p>Python 里有个小彩蛋：<br />
在 Python Shell 里输入 <code>import this</code></p>
<div><img alt="the_zen_of_python.png" src="https://www.wenyuanblog.com/medias/blogimages/the_zen_of_python.png" data-original="/medias/blogimages/the_zen_of_python.png" /></div>
<p>这段话被称作“<strong>Python 之禅</strong>”（<strong>The Zen of Python</strong>），它列举了一些 Python 所推崇的理念，比如：</p>
<p>&nbsp;</p>
<blockquote><p>优美胜于丑陋<br />
明确胜于隐晦<br />
简单胜于复杂<br />
…<br />
可读性很重要<br />
不要忽略错误<br />
面对不确定时，拒绝猜测<br />
现在做好过不做，但盲目动手不如不做<br />
如果你的实现很难说清楚，那是个坏想法；反之亦然<br />
…</p></blockquote>
<p>我们看一些有经验的工程师写的代码，很容易看出来是出自一个“老手”，那是因为他们的代码比较<strong>Pythonic</strong>，遵循了一个比较好的代码风格。<br />
“Python 之禅”并不仅限于 Python，很多理念是编程普适的。<br />
下面我列举了一些比较Pythonic的语法实现，主要是从一些大佬的项目中学习并整理的。<br />
<strong>普通写法</strong>：能实现功能的写法<br />
<strong>代码优化</strong>：使用Python“语法糖”或其他更具Python风格的写法，使代码更优雅</p>
<h2 id="toc-heading-2">二、代码对比</h2>
<h3 id="toc-heading-3">1. 实现对列表元素的遍历访问</h3>
<p>普通写法</p>
<pre><code>In [1]: lst = ['www.','wenyuanblog','.com']
In [2]: for i in range(len(lst)):
   ...:     print(lst[i])
   ...:     
www.
wenyuanblog
.com
</code></pre>
<p>代码优化</p>
<pre><code>In [1]: lst = ['www.','wenyuanblog','.com']
In [2]: for i in lst:
   ...:     print(i)
   ...:     
www.
wenyuanblog
.com
</code></pre>
<h3 id="toc-heading-4">2. 交换两个变量的值</h3>
<p>普通写法</p>
<pre><code>In [1]: a = 'hello'
In [2]: b = 'world'
In [3]: temp = a
In [4]: a = b
In [5]: b = temp
In [6]: print(a, b)
('world', 'hello')
</code></pre>
<p>代码优化</p>
<pre><code>In [1]: a = 'hello'
In [2]: b = 'world'
In [3]: a, b = b, a
In [4]: print(a, b)
('world', 'hello')
</code></pre>
<h3 id="toc-heading-5">3. 拼接字符串</h3>
<p>普通写法</p>
<pre><code>In [1]: letters = ['w', 'e', 'n', 'y', 'u', 'a', 'n', 'b', 'l', 'o', 'g', '.', 'c', 'o', 'm']
In [2]: homepage = ''
In [3]: for letter in letters:
   ...:     homepage += letter
   ...:     
In [4]: print(homepage)
wenyuanblog.com
</code></pre>
<p>代码优化</p>
<pre><code>In [1]: letters = ['w', 'e', 'n', 'y', 'u', 'a', 'n', 'b', 'l', 'o', 'g', '.', 'c', 'o', 'm']
In [2]: print(''.join(letters))
wenyuanblog.com
</code></pre>
<h3 id="toc-heading-6">4. 取出列表中大于 0 的元素，生成新列表</h3>
<p>普通写法</p>
<pre><code>In [1]: lst = [1, 2, 3, 0, 6]
In [2]: new_lst = []
In [3]: for i in lst:
   ....:     if i &gt; 0:
   ....:         new_lst.append(i)
   ....:         
In [4]: print(new_lst)
[1, 2, 3, 6]
</code></pre>
<p>代码优化：列表解析式</p>
<pre><code>In [1]: lst = [1, 2, 3, 0, 6]
In [2]: new_lst = [i for i in lst if i &gt; 0]
In [3]: print(new_lst)
[1, 2, 3, 6]
</code></pre>
<p>代码优化：生成器（用于数据量很大，但对新列表仅仅是遍历操作，并不需要一个列表对象的场景）</p>
<pre><code>In [1]: lst = [1, 2, 3, 0, 6]
In [2]: new_lst = (i for i in lst if i &gt; 0)
In [3]: for i in new_lst:
   ....:     print(i)
   ....:     
1
2
3
6
</code></pre>
<h3 id="toc-heading-7">5. 判断一个值是否为True、空列表、None</h3>
<p>普通写法</p>
<pre><code>if x == True:
    pass
if len(y) == 0:
    pass
if z == None:
    pass
</code></pre>
<p>代码优化</p>
<pre><code>if x:
    pass
if not y:
    pass
if z is None:
    pass
</code></pre>
<h3 id="toc-heading-8">6. 根据键名获取字典中对应的值</h3>
<p>普通写法<br />
这样的问题在于，如果 key 不存在，代码就报错跳出。</p>
<pre><code>value = dct[key]
</code></pre>
<p>代码优化<br />
改用 get 方法，不存在时会得到 None，或者指定的默认值（这里是 0）。</p>
<pre><code>value = dct.get(key, 0)
</code></pre>
<h3 id="toc-heading-9">7. 持续更新ing</h3>
<p>普通写法</p>
<pre></pre>
<p>代码优化</p>
<pre></pre>
<h2 id="toc-heading-10">三、总结</h2>
<p>篇幅所限，以上仅仅是一些比较具有代表性的例子。但凡事要有度，过分追求 Pythonic 的写法也可能导致代码的可读性下降。比如有人喜欢把很多功能写在一个语句中，这反倒不 Pythonic 了。所以，我们需要有一些设计的原则，但又不必拘泥于具体的形式，否则就钻入牛角尖了。<br />
平时还是要多看官方库、优秀项目，学习别人的代码。但首先还是要先实现功能，尤其时间紧张的时候，我都会先把功能做出来，然后再去学习、比对、思考，最终优化代码。相信写到足够的代码量后，我们自然而然能“悟道”了。<br />
另外，对于代码本身，Python 有一套书写规范，叫做 PEP8。里面约定了很多细节，比如哪里该空格、注释怎么写、什么地方该换行、如何命名等等。网上搜一下就能找到，还有中文版，务必找时间看一看。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonjinjiepythonicfenggezhengli.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python基础】Matplotlib模块</title>
		<link>http://www.eavea.com/blog/index.php/pythonjichumatplotlibmokuai.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonjichumatplotlibmokuai.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:27:56 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=52</guid>
		<description><![CDATA[【Python基础】Matplotlib模块 Python中的绘图库-Matplotlib。 一、Matplo [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python基础】Matplotlib模块</div>
<blockquote><p>Python中的绘图库-Matplotlib。</p></blockquote>
<h2 id="一、Matplotlib简介与安装">一、Matplotlib简介与安装</h2>
<p>Matplotlib也就是Matrix Plot Library，顾名思义，是Python的绘图库。它可与NumPy一起使用，提供了一种有效的MATLAB开源替代方案。它也可以和图形工具包一起使用，如PyQt和wxPython。<br />
安装方式：执行命令 <code>pip install matplotlib</code><br />
一般常用的是它的子包PyPlot，提供类似MATLAB的绘图框架。</p>
<h2 id="二、使用方法">二、使用方法</h2>
<ol>
<li>绘制一条直线 y = 3 * x + 4，其中 x 在(-2, 2)，取100个点平均分布</li>
</ol>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import numpy as np

# 创建数据
x = np.linspace(-2, 2, 100)
y = 3 * x + 4

# 创建图像
plt.plot(x, y)

# 显示图像
plt.show()
</code></pre>
<ol start="2">
<li>在一张图里绘制多个子图</li>
</ol>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.ticker import NullFormatter

"""
多个子图
"""

# 为了能够复现
np.random.seed(1)

y = np.random.normal(loc=0.5, scale=0.4, size=1000)
y = y[(y &gt; 0) &amp; (y &lt; 1)]
y.sort()
x = np.arange(len(y))

plt.figure(1)

# linear
# 使用.subplot()方法创建子图，221表示2行2列第1个位置
plt.subplot(221)
plt.plot(x, y)
plt.yscale('linear')
plt.title('linear')
plt.grid(True)

# log
plt.subplot(222)
plt.plot(x, y)
plt.yscale('log')
plt.title('log')
plt.grid(True)

# symmetric log
plt.subplot(223)
plt.plot(x, y - y.mean())
plt.yscale('symlog', linthreshy=0.01)
plt.title('symlog')
plt.grid(True)

# logit
plt.subplot(224)
plt.plot(x, y)
plt.yscale('logit')
plt.title('logit')
plt.grid(True)
plt.gca().yaxis.set_minor_formatter(NullFormatter())
plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25,
                    wspace=0.35)

plt.show()
</code></pre>
<ol start="3">
<li>绘制一个碗状的3D图形，着色使用彩虹色</li>
</ol>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

"""
碗状图形
"""

fig = plt.figure(figsize=(8, 5))
ax1 = Axes3D(fig)

alpha = 0.8
r = np.linspace(-alpha, alpha, 100)
X, Y = np.meshgrid(r, r)
l = 1. / (1 + np.exp(-(X ** 2 + Y ** 2)))

ax1.plot_wireframe(X, Y, l)
ax1.plot_surface(X, Y, l, cmap=plt.get_cmap("rainbow"))  # 彩虹配色
ax1.set_title("Bowl shape")

plt.show()
</code></pre>
<ol start="4">
<li>更多用法<br />
参见官网文档</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonjichumatplotlibmokuai.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python基础】SMTP发送邮件</title>
		<link>http://www.eavea.com/blog/index.php/pythonjichusmtpfasongyoujian.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonjichusmtpfasongyoujian.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:26:47 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=51</guid>
		<description><![CDATA[【Python基础】SMTP发送邮件 Python使用SMTP发送邮件。 一、准备 1. 开启邮箱的SMTP  [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python基础】SMTP发送邮件</div>
<blockquote><p>Python使用SMTP发送邮件。</p></blockquote>
<h2 id="toc-heading-1">一、准备</h2>
<h3 id="toc-heading-2">1. 开启邮箱的SMTP 服务</h3>
<p>这里使用第三方 SMTP 服务发送邮件，可以使用 QQ邮箱，163，Gmail 等的 SMTP 服务，但需要做以下配置，以QQ邮箱为例。<br />
登录QQ邮箱，依次点击最上方的 设置，然后点击 账户。</p>
<div><img alt="qq_smtp_setting_1.png" src="https://www.wenyuanblog.com/medias/blogimages/qq_smtp_setting_1.png" data-original="/medias/blogimages/qq_smtp_setting_1.png" /></div>
<p>往下翻页，找到 <strong>POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV</strong> 这一版块，开启 POP3/SMTP服务。（不同版本的QQ可能会不一样，总之就是找到QQ邮箱的“POP3/SMTP服务”开启按钮。）<br />
<img alt="qq_smtp_setting_2.png" src="https://www.wenyuanblog.com/medias/blogimages/qq_smtp_setting_2.png" data-original="/medias/blogimages/qq_smtp_setting_2.png" /><br />
成功开启QQ邮箱的SMTP服务后，我们会得到一串授权码，在后面的代码里，这串授权码就是我们邮箱的登录密码。开启SMTP服务可能需要进行手机验证，根据提示来就好。</p>
<p>&nbsp;</p>
<h3 id="toc-heading-3">2. 常用的邮件服务器配置</h3>
<p>下面整理了常用的邮件服务器名称、地址及SSL/非SSL协议端口号。<br />
<strong>网易163免费邮箱相关服务器信息：</strong></p>
<table>
<thead>
<tr>
<th>服务器名称</th>
<th>服务器地址</th>
<th>SSL协议端口号</th>
<th>非SSL协议端口号</th>
</tr>
</thead>
<tbody>
<tr>
<td>IMAP</td>
<td>imap.163.com</td>
<td>993</td>
<td>143</td>
</tr>
<tr>
<td>SMTP</td>
<td>smtp.163.com</td>
<td>454/994</td>
<td>25</td>
</tr>
<tr>
<td>POP3</td>
<td>pop.163.com</td>
<td>995</td>
<td>110</td>
</tr>
</tbody>
</table>
<p><strong>网易163企业邮箱相关服务器信息：</strong>（免费企业邮箱的smtp服务器名及端口号为：smtp.ym.163.com / 25）</p>
<table>
<thead>
<tr>
<th>服务器名称</th>
<th>服务器地址</th>
<th>SSL协议端口号</th>
<th>非SSL协议端口号</th>
</tr>
</thead>
<tbody>
<tr>
<td>IMAP</td>
<td>imap.qiye.163.com</td>
<td>993</td>
<td>143</td>
</tr>
<tr>
<td>SMTP</td>
<td>smtp.qiye.163.com</td>
<td>994</td>
<td>25</td>
</tr>
<tr>
<td>POP3</td>
<td>pop.qiye.163.com</td>
<td>995</td>
<td>110</td>
</tr>
</tbody>
</table>
<p><strong>网易126免费邮箱相关服务器信息：</strong></p>
<table>
<thead>
<tr>
<th>服务器名称</th>
<th>服务器地址</th>
<th>SSL协议端口号</th>
<th>非SSL协议端口号</th>
</tr>
</thead>
<tbody>
<tr>
<td>IMAP</td>
<td>imap.126.com</td>
<td>993</td>
<td>143</td>
</tr>
<tr>
<td>SMTP</td>
<td>smtp.126.com</td>
<td>465/994</td>
<td>25</td>
</tr>
<tr>
<td>POP3</td>
<td>pop.126.com</td>
<td>995</td>
<td>110</td>
</tr>
</tbody>
</table>
<p><strong>腾讯QQ免费邮箱相关服务器信息：</strong></p>
<table>
<thead>
<tr>
<th>服务器名称</th>
<th>服务器地址</th>
<th>SSL协议端口号</th>
<th>非SSL协议端口号</th>
</tr>
</thead>
<tbody>
<tr>
<td>IMAP</td>
<td>imap.qq.com</td>
<td>993</td>
<td>143</td>
</tr>
<tr>
<td>SMTP</td>
<td>smtp.qq.com</td>
<td>465/587</td>
<td>25</td>
</tr>
<tr>
<td>POP3</td>
<td>pop.qq.com</td>
<td>995</td>
<td>110</td>
</tr>
</tbody>
</table>
<p><strong>腾讯QQ企业邮箱相关服务器信息：</strong></p>
<table>
<thead>
<tr>
<th>服务器名称</th>
<th>服务器地址</th>
<th>SSL协议端口号</th>
<th>非SSL协议端口号</th>
</tr>
</thead>
<tbody>
<tr>
<td>IMAP</td>
<td>imap.exmail.qq.com</td>
<td>993</td>
<td>143</td>
</tr>
<tr>
<td>SMTP</td>
<td>smtp.exmail.qq.com</td>
<td>465/587</td>
<td>25</td>
</tr>
<tr>
<td>POP3</td>
<td>pop.exmail.qq.com</td>
<td>995</td>
<td>110</td>
</tr>
</tbody>
</table>
<p><strong>谷歌Gmail邮箱相关服务器信息：</strong></p>
<table>
<thead>
<tr>
<th>服务器名称</th>
<th>服务器地址</th>
<th>SSL协议端口号</th>
<th>非SSL协议端口号</th>
</tr>
</thead>
<tbody>
<tr>
<td>IMAP</td>
<td>imap.gmail.com</td>
<td>993</td>
<td>143</td>
</tr>
<tr>
<td>SMTP</td>
<td>smtp.gmail.com</td>
<td>465</td>
<td>25</td>
</tr>
<tr>
<td>POP3</td>
<td>pop.gmail.com</td>
<td>995</td>
<td>110</td>
</tr>
</tbody>
</table>
<h2 id="toc-heading-4">二、代码实现</h2>
<p>下面开始编写代码，注意QQ邮箱SMTP服务器地址：smtp.qq.com，ssl端口：465。</p>
<h3 id="toc-heading-5">1. 发送纯文本邮件</h3>
<p>以下实例你需要修改：发件人邮箱（你的QQ邮箱），密码，收件人邮箱（可发给自己）。</p>
<pre><code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import smtplib
from email.header import Header
from email.mime.text import MIMEText

# ----- 需要修改的参数 -----
# email相关
sender = 'wenyuanblog@qq.com'
password = 'hjenixkwghseowyxnclh12yx8je9l2au'
smtp_server = 'smtp.qq.com'
smtp_port = 465
receivers = ['recever1@163.com', 'recever1@qq.com']
# ------------------------

def send_email(subject, detail):
    now_time = time.strftime('%Y-%m-%d %H:%M:%S')
    mail_msg = """
    时间：{now_time}
    详情：{detail}
    """.format(subject=subject, now_time=now_time, detail=detail)

    msg = MIMEText(mail_msg, 'plain', 'utf-8')
    msg['From'] = Header('wenyuanblog汇报人 &lt;%s&gt;' % sender, 'utf-8')
    msg['To'] = Header('wenyuanblog订阅者', 'utf-8')
    msg['Subject'] = Header(subject, 'utf-8')

    try:
        smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
        # smtp.set_debuglevel(1)    # 打印和SMTP服务器交互的所有信息
        smtp.login(sender, password)
        smtp.sendmail(sender, receivers, msg.as_string())
        smtp.quit()
        print('邮件发送成功')
    except smtplib.SMTPException as e:
        print('Error: 无法发送邮件')
        print(e)

if __name__ == "__main__":
    email_title = 'Python SMTP 纯文本邮件测试'
    detail = """
    欢迎访问：www.wenyuanblog.com
    这里是我的博客站点，专注于Python、前端和机器学习技术的分享。
    """
    send_email(email_title, detail)
</code></pre>
<h3 id="toc-heading-6">2. 发送HTML格式的邮件</h3>
<p>以下实例你需要修改：发件人邮箱（你的QQ邮箱），密码，收件人邮箱（可发给自己）。</p>
<pre><code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import smtplib
from email.header import Header
from email.mime.text import MIMEText

# ----- 需要修改的参数 -----
# email相关
sender = 'wenyuanblog@qq.com'
password = 'hjenixkwghseowyxnclh12yx8je9l2au'
smtp_server = 'smtp.qq.com'
smtp_port = 465
receivers = ['recever1@163.com', 'recever1@qq.com']
# ------------------------

def send_email(subject, detail):
    now_time = time.strftime('%Y-%m-%d %H:%M:%S')
    mail_msg = """
    &lt;h1 style='margin-top:10px;margin-bottom:10px;text-align:center'&gt;{subject}&lt;/h1&gt;
    &lt;hr&gt;
    &lt;h2 style='margin-top:0;margin-bottom:10px'&gt;时间&lt;/h2&gt;
    &lt;div style='margin-left: 40px'&gt;{now_time}&lt;/div&gt;
    &lt;hr&gt;
    &lt;h2 style='margin-top:0;margin-bottom:10px'&gt;详情&lt;/h2&gt;
    &lt;div style='margin-left: 40px'&gt;{detail}&lt;/div&gt;
    &lt;hr&gt;
    """.format(subject=subject, now_time=now_time, detail=detail)

    msg = MIMEText(mail_msg, 'html', 'utf-8')
    msg['From'] = Header('wenyuanblog汇报人 &lt;%s&gt;' % sender, 'utf-8')
    msg['To'] = Header('wenyuanblog订阅者', 'utf-8')
    msg['Subject'] = Header(subject, 'utf-8')

    try:
        smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
        # smtp.set_debuglevel(1)    # 打印和SMTP服务器交互的所有信息
        smtp.login(sender, password)
        smtp.sendmail(sender, receivers, msg.as_string())
        smtp.quit()
        print('邮件发送成功')
    except smtplib.SMTPException as e:
        print('Error: 无法发送邮件')
        print(e)

if __name__ == "__main__":
    email_title = 'Python SMTP HTML格式邮件测试'
    detail = """
    &lt;div&gt;欢迎访问：&lt;a href="http://www.wenyuanblog.com" target="_blank"&gt;www.wenyuanblog.com&lt;/a&gt;&lt;/div&gt;
    &lt;div style='margin-bottom:5px'&gt;这里是我的博客站点，专注于Python、前端和机器学习技术的分享。&lt;/div&gt;
    """
    send_email(email_title, detail)
</code></pre>
<h3 id="toc-heading-7">2. 发送带附件的邮件</h3>
<p>以下实例你需要修改：发件人邮箱（你的QQ邮箱），密码，收件人邮箱（可发给自己）。</p>
<pre><code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

# ----- 需要修改的参数 -----
# email相关
sender = 'wenyuanblog@qq.com'
password = 'hjenixkwghseowyxnclh12yx8je9l2au'
smtp_server = 'smtp.qq.com'
smtp_port = 465
receivers = ['recever1@163.com', 'recever1@qq.com']
# ------------------------

def send_email(subject, detail, attach_list):
    now_time = time.strftime('%Y-%m-%d %H:%M:%S')
    mail_msg = """
    时间：{now_time}
    详情：{detail}
    """.format(subject=subject, now_time=now_time, detail=detail)

    # 创建一个带附件的实例
    msg = MIMEMultipart()
    # msg = MIMEText(mail_msg, 'plain', 'utf-8')
    msg['From'] = Header('wenyuanblog汇报人 &lt;%s&gt;' % sender, 'utf-8')
    msg['To'] = Header('wenyuanblog订阅者', 'utf-8')
    msg['Subject'] = Header(subject, 'utf-8')

    # 邮件正文内容
    msg.attach(MIMEText(mail_msg, 'plain', 'utf-8'))
    # 构造附件，传送指定目录下的文件
    for att_path in attach_list:
        att = MIMEText(open(att_path, 'rb').read(), 'base64', 'utf-8')
        att["Content-Type"] = 'application/octet-stream'
        # 这里的filename可以任意写，写什么名字，邮件中显示什么名字
        att["Content-Disposition"] = 'attachment; filename={filename}'.format(filename=att_path)
        msg.attach(att)

    try:
        smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
        # smtp.set_debuglevel(1)    # 打印和SMTP服务器交互的所有信息
        smtp.login(sender, password)
        smtp.sendmail(sender, receivers, msg.as_string())
        smtp.quit()
        print('邮件发送成功')
    except smtplib.SMTPException as e:
        print('Error: 无法发送邮件')
        print(e)

if __name__ == "__main__":
    email_title = 'Python SMTP 带附件邮件测试'
    detail = """
    欢迎访问：www.wenyuanblog.com
    这里是我的博客站点，专注于Python、前端和机器学习技术的分享。
    附件是网站源码，请查收。
    """
    attach_list = ['send_email.py', 'README.md']
    send_email(email_title, detail, attach_list)

</code></pre>
<h2 id="toc-heading-8">三、总结</h2>
<p>以上就是通过 Python SMTP 发送邮件的代码示例，一般情况下是够用了。还有一些图片email等特殊邮件，因为需要考虑到兼容性问题，有些邮箱默认不显示图片，个人感觉不太常用，就不整理了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonjichusmtpfasongyoujian.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python基础】subprocess模块</title>
		<link>http://www.eavea.com/blog/index.php/pythonjichusubprocessmokuai.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonjichusubprocessmokuai.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:25:33 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=50</guid>
		<description><![CDATA[【Python基础】subprocess模块 Python执行Linux的Shell命令方法总结。 一、简介  [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python基础】subprocess模块</div>
<blockquote><p>Python执行Linux的Shell命令方法总结。</p></blockquote>
<h2 id="toc-heading-1">一、简介</h2>
<p>工作中经常会遇到写工具脚本的需求，需要我们通过Python来执行shell命令。<br />
Python中可以执行shell命令的相关模块和函数有：<br />
●　<strong> os.system </strong><br />
●　<strong> os.spawn* </strong><br />
●　<strong> os.popen* </strong> –废弃<br />
●　<strong> popen2.* </strong> –废弃<br />
●　<strong> commands.* </strong> –废弃，3.x中被移除<br />
乍一看是不是很凌乱，怎么有那么多，选择恐惧症啊：到底哪个是主流呢？<br />
以前我比较常用的是 commands，用起来很方便，如下：</p>
<div>python<i></i><i></i></div>
<pre><code>import commands

result = commands.getoutput('cmd')
result = commands.getstatus('cmd')
result = commands.getstatusoutput('cmd')
</code></pre>
<p>随着Python版本的更新，上面有这么多模块，必然引起了代码的复杂与冗余。因此Python新引入了一个模块 subprocess。它将以上几个模块的功能集中到了一起。<br />
所以今后只需要 import subprocess 这一个即可。<br />
<strong>subprocess</strong> 的目的就是启动一个新的进程并且与之通信。</p>
<h2 id="toc-heading-2">二、subprocess常用的封装函数</h2>
<h3 id="toc-heading-3">1. subprocess.call()</h3>
<p>父进程等待子进程执行命令，返回子进程执行命令的状态码，如果出现错误，不进行报错。<br />
* 这里说的返回执行命令的状态码的意思是：如果我们通过一个变量 res = subprocess.call([‘dir’,shell=True]) 获取的执行结果，我们能获取到的是子进程执行命令执行结果的状态码，即res=0/1 执行成功或者不成功，并不代表说看不到执行结果，在Python的console界面中我们是能够看到命令结果的，只是获取不到。想获取执行的返回结果，就要看后面的check_output。<br />
* 不进行报错解释：如果我们执行的命令在执行时，操作系统不识别，系统会返回一个错误，如：abc命令不存在，这个结果会在console界面中显示出来，但是我们的Python解释器不会提示任何信息，如果想让Python解释器也进行报错，就要看后面的check_output。<br />
下面举一个例子，执行 <code>cat /etc/issue</code> 命令：</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

result = subprocess.call(['cat', '/etc/issue'], shell=False)
print(result)
</code></pre>
<p>注：shell默认为False，在Linux下，shell=False时, Popen调用os.execvp()执行args指定的程序；shell=True时，如果args是字符串，Popen直接调用系统的Shell来执行args指定的程序，如果args是一个序列，则args的第一项是定义程序命令字符串，其它项是调用系统Shell时的附加参数。<br />
在Windows下，不论shell的值如何，Popen调用CreateProcess()执行args指定的外部程序。如果args是一个序列，则先用list2cmdline()转化为字符串，但需要注意的是，并不是MS Windows下所有的程序都可以用list2cmdline来转化为命令行字符串。在windows下，调用脚本时要写上shell=True。<br />
输出结果：</p>
<div>bash<i></i><i></i></div>
<pre><code>Ubuntu 14.04.3 LTS \n \l

0
</code></pre>
<h3 id="toc-heading-4">2. subprocess.check_call()</h3>
<p>父进程等待子进程执行命令，返回执行命令的状态码，如果出现错误，进行报错【如果returncode不为0，则举出错误subprocess.CalledProcessError，该对象包含有returncode属性，可用try…except…来检查】。<br />
下面举一个例子，分别执行一条正确的命令和一条错误的命令：</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

print('执行一条正确的命令：')
result = subprocess.check_call(['cat', '/etc/issue'], shell=False)
print(result)

print('执行一条错误的命令：')
result = subprocess.check_call(['abc'], shell=False)
print(result)
</code></pre>
<p>输出结果：</p>
<div>bash<i></i><i></i></div>
<pre><code>执行一条正确的命令：
Ubuntu 14.04.3 LTS \n \l

0
执行一条错误的命令：
Traceback (most recent call last):
  File "subprocess_check_call.py", line 12, in &lt;module&gt;
    result = subprocess.check_call(['abc'], shell=False)
  File "/usr/lib/python2.7/subprocess.py", line 535, in check_call
    retcode = call(*popenargs, **kwargs)
  File "/usr/lib/python2.7/subprocess.py", line 522, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
</code></pre>
<h3 id="toc-heading-5">3. subprocess.check_output()</h3>
<p>父进程等待子进程执行命令，返回子进程向标准输出发送输出运行结果，检查退出信息，如果returncode不为0，则举出错误subprocess.CalledProcessError，该对象包含有returncode属性和output属性，output属性为标准输出的输出结果，可用try…except…来检查。<br />
下面举一个例子，执行 <code>ping -c 4 www.baidu.com</code> 命令：</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

result = subprocess.check_output(['ping', '-c', '4', 'www.baidu.com'], shell=False)
print(result)
</code></pre>
<p>输出结果：</p>
<div>bash<i></i><i></i></div>
<pre><code>PING www.a.shifen.com (180.97.33.107) 56(84) bytes of data.
64 bytes from 180.97.33.107: icmp_seq=1 ttl=55 time=5.52 ms
64 bytes from 180.97.33.107: icmp_seq=2 ttl=55 time=6.65 ms
64 bytes from 180.97.33.107: icmp_seq=3 ttl=55 time=6.18 ms
64 bytes from 180.97.33.107: icmp_seq=4 ttl=55 time=7.77 ms

--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 5.529/6.537/7.779/0.824 ms
</code></pre>
<p>可见，call/check_call 返回值均是命令的执行状态码，而 check_output 返回值是命令的执行结果。<br />
如果在执行相关命令时，命令后带有参数，将命令和所带的参数一起放在一个列表中传递给相关方法即可。</p>
<h3 id="toc-heading-6">4. subprocess.Popen()</h3>
<p>实际上，subprocess模块中只定义了一个类：Popen。上面的几个函数都是基于Popen()的封装(wrapper)。从Python2.4开始使用Popen来创建进程，用于连接到子进程的标准输入/输出/错误中去，还可以得到子进程的返回值。这些封装的目的在于让我们容易使用子进程。当我们想要更个性化我们的需求的时候，就要转向Popen类，该类生成的对象用来代表子进程。<br />
构造函数如下：</p>
<div>python<i></i><i></i></div>
<pre><code>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)
</code></pre>
<p>与上面的封装不同，Popen对象创建后，主程序不会自动等待子进程完成。我们必须调用对象的wait()方法，父进程才会等待（也就是阻塞block）。<br />
① 不等待的子进程</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

child = subprocess.Popen(['ping', '-c', '4', 'www.baidu.com'])
print('hello world')
</code></pre>
<p>输出结果：</p>
<div>bash<i></i><i></i></div>
<pre><code>wenyuanblog@localhost:~/home/test/script$ python subprocess_sub.py 
hello world
wenyuanblog@localhost:~/home/test/script$ PING www.a.shifen.com (180.97.33.107) 56(84) bytes of data.
64 bytes from 180.97.33.107: icmp_seq=1 ttl=55 time=6.28 ms
64 bytes from 180.97.33.107: icmp_seq=2 ttl=55 time=6.61 ms
64 bytes from 180.97.33.107: icmp_seq=3 ttl=55 time=6.30 ms
64 bytes from 180.97.33.107: icmp_seq=4 ttl=55 time=6.45 ms

--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 6.287/6.413/6.610/0.162 ms
</code></pre>
<p>可以看出，Python并没有等到child子进程执行的Popen操作完成就执行了print操作。<br />
② 添加子进程等待</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

# 创建一个子进程，进程名为child，执行操作ping -c 4 www.baidu.com
child = subprocess.Popen(['ping', '-c', '4', 'www.baidu.com'])
# 子进程等待
child.wait()
print('hello world')
</code></pre>
<p>输出结果：</p>
<div>bash<i></i><i></i></div>
<pre><code>wenyuanblog@localhost:~/home/test/script$ python subprocess_sub.py 
PING www.a.shifen.com (180.97.33.108) 56(84) bytes of data.
64 bytes from 180.97.33.108: icmp_seq=1 ttl=55 time=6.50 ms
64 bytes from 180.97.33.108: icmp_seq=2 ttl=55 time=5.88 ms
64 bytes from 180.97.33.108: icmp_seq=3 ttl=55 time=6.48 ms
64 bytes from 180.97.33.108: icmp_seq=4 ttl=55 time=6.74 ms

--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 5.887/6.404/6.740/0.325 ms
hello world
</code></pre>
<p>看出Python执行print操作是在child子进程操作完成以后才进行的。</p>
<p>此外，你还可以在父进程中对子进程进行其它操作，比如我们上面例子中的child对象：</p>
<div>python<i></i><i></i></div>
<pre><code>child.poll()  # 检查子进程状态
child.kill()  # 终止子进程
child.send_signal()  # 向子进程发送信号
child.terminate()  # 终止子进程
ps: 子进程的PID存储在child.pid
</code></pre>
<p><strong>子进程文本流控制</strong><br />
子进程的标准输入、标准输出和标准错误如下属性分别表示：<br />
child.stdin | child.stdout | child.stderr<br />
我们还可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误，并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起，构成管道（pipe），如下2个例子。<br />
例1：</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

# 将标准输出定向输出到subprocess.PIPE
child = subprocess.Popen(['cat','/etc/issue'],stdout=subprocess.PIPE)
# 使用 child.communicate() 也可
print(child.stdout.read())
</code></pre>
<p>输出结果：</p>
<div>bash<i></i><i></i></div>
<pre><code>Ubuntu 14.04.3 LTS \n \l
</code></pre>
<p>例2：</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

child1 = subprocess.Popen(['cat', '/etc/issue'], stdout=subprocess.PIPE)
child2 = subprocess.Popen(['date', '+%Y-%m-%d'], stdin=child1.stdout, stdout=subprocess.PIPE)

print(child2.communicate())
</code></pre>
<p>输出结果：</p>
<div>bash<i></i><i></i></div>
<pre><code>('2017-06-08\n', None)
</code></pre>
<p>subprocess.PIPE实际上为文本流提供一个缓存区。child1的stdout将文本输出到缓存区，随后child2的stdin从该PIPE中将文本读取走。child2的输出文本也被存放在PIPE中，直到communicate()方法从PIPE中读取出PIPE中的文本。<br />
注意：communicate()是Popen对象的一个方法，该方法会阻塞父进程，直到子进程完成。</p>
<p><strong>子进程命令解释</strong><br />
在上面的例子中我们创建子进程时，全部是调用Python进行解释，但Python并没有将所有命令全部解释，当Python不能进行解释时，就需要调用系统来进行执行。<br />
上面说过，带参数的命令，要使用列表的形式，其实我们也可以传字符串，只不过这时要传入shell=True，大概就是这个意思。</p>
<div>python<i></i><i></i></div>
<pre><code># -*- coding: utf-8 -*-
# !/usr/bin/env python

import subprocess

subprocess.Popen(['ls', '-l'])
subprocess.Popen(['ifconfig|grep 127.0.0.1'], shell=True)
</code></pre>
<h2 id="toc-heading-7">三、总结</h2>
<p>subprocess模块作为最新出的“集大成者”，还是很强大的。上面整理的是平时常用的功能。如果需要更进一步了解内部函数，可以查看官方文档。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonjichusubprocessmokuai.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python基础】文本文件读写</title>
		<link>http://www.eavea.com/blog/index.php/pythonjichuwenbenwenjianduxie.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonjichuwenbenwenjianduxie.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:18:31 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=48</guid>
		<description><![CDATA[【Python基础】文本文件读写 Python中常用文件读写方法汇总。 一、打开文件模式 打开文件模式列表：  [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python基础】文本文件读写</div>
<blockquote><p>Python中常用文件读写方法汇总。</p></blockquote>
<h2 id="toc-heading-1">一、打开文件模式</h2>
<p>打开文件模式列表：</p>
<table>
<thead>
<tr>
<th>模式</th>
<th>r</th>
<th>r+</th>
<th>w</th>
<th>w+</th>
<th>a</th>
<th>a+</th>
</tr>
</thead>
<tbody>
<tr>
<td>读</td>
<td>+</td>
<td>+</td>
<td></td>
<td>+</td>
<td></td>
<td>+</td>
</tr>
<tr>
<td>写</td>
<td></td>
<td>+</td>
<td>+</td>
<td>+</td>
<td>+</td>
<td>+</td>
</tr>
<tr>
<td>创建</td>
<td></td>
<td></td>
<td>+</td>
<td>+</td>
<td>+</td>
<td>+</td>
</tr>
<tr>
<td>覆盖</td>
<td></td>
<td></td>
<td>+</td>
<td>+</td>
<td></td>
<td></td>
</tr>
<tr>
<td>指针在开始</td>
<td>+</td>
<td>+</td>
<td>+</td>
<td>+</td>
<td></td>
<td></td>
</tr>
<tr>
<td>指针在结尾</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>+</td>
<td>+</td>
</tr>
</tbody>
</table>
<h2 id="toc-heading-2">二、读取文本文件</h2>
<p>python常用的读取文件函数有三种read()、readline()、readlines()</p>
<div><img alt="py_test_txtfile.png" src="https://www.wenyuanblog.com/medias/blogimages/py_test_txtfile.png" data-original="/medias/blogimages/py_test_txtfile.png" /></div>
<p>&nbsp;</p>
<h3 id="toc-heading-3">1. read() 一次性读全部内容</h3>
<p>read()会一次性读取文本中全部的内容，以字符串的形式返回结果</p>
<div>python<i></i><i></i></div>
<pre><code>with open('test.txt', 'r', encoding='utf-8') as f:  # 打开文件
    data = f.read()  # 读取文件
    print(data)
</code></pre>
<h3 id="toc-heading-4">2. readline() 读取第一行内容</h3>
<p>readline()只读取文本第一行的内容，以字符串的形式返回结果</p>
<div>python<i></i><i></i></div>
<pre><code>with open('test.txt', 'r', encoding='utf-8') as f:  # 打开文件
    data = f.readline()
    print(data)
</code></pre>
<h3 id="toc-heading-5">3. readlines() 列表</h3>
<p>readlines()会读取文本所有内容，并且以数列的格式返回结果，一般配合for in使用</p>
<div>python<i></i><i></i></div>
<pre><code>with open('test.txt', 'r', encoding='utf-8') as f:  # 打开文件
    data = f.readlines()
    print(data)
# 输出：['你好，我是第一行\n', '你好，我是第二行\n', '你好，我是第三行\n', '你好，我是第四行\n', '你好，我是第五行']
</code></pre>
<p>可见readlines会读到换行符，我们可以用如下方法去除：</p>
<div>python<i></i><i></i></div>
<pre><code>with open('test.txt', 'r', encoding='utf-8') as f:  # 打开文件
    for line in f.readlines():
        line = line.strip('\n')  # 去掉列表中每一个元素的换行符
        print(line)
</code></pre>
<h2 id="toc-heading-6">三、写入文本文件</h2>
<p>清空原来的内容，覆盖写入</p>
<div>python<i></i><i></i></div>
<pre><code>with open('test.txt', 'w', encoding='utf-8') as f:  # 打开文件
    f.write('测试写入一行')  # 这句话自带文件关闭功能，不需要再写f.close()
</code></pre>
<p>保留原来的内容，在末尾追加写入</p>
<div>python<i></i><i></i></div>
<pre><code>with open('test.txt', 'a', encoding='utf-8') as f:  # 打开文件
    f.write('测试写入一行')  # 这句话自带文件关闭功能，不需要再写f.close()</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonjichuwenbenwenjianduxie.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【Python基础】时间和日期模块</title>
		<link>http://www.eavea.com/blog/index.php/pythonjichushijianheriqimokuai.html</link>
		<comments>http://www.eavea.com/blog/index.php/pythonjichushijianheriqimokuai.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:15:36 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=46</guid>
		<description><![CDATA[【Python基础】时间和日期模块 Python中的time和datetime用法整理。 一、Python中时 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>【Python基础】时间和日期模块</div>
<blockquote><p>Python中的time和datetime用法整理。</p></blockquote>
<h2 id="toc-heading-1">一、Python中时间的四种类型</h2>
<ul>
<li>时间戳 float</li>
<li>时间元组 struct_time</li>
<li>时间字符串 string</li>
<li>时间对象 datetime，date，time</li>
</ul>
<h2 id="toc-heading-2">二、time模块</h2>
<div>python<i></i><i></i></div>
<pre><code># 导入包
import time
</code></pre>
<h3 id="toc-heading-3">1. 时间类型</h3>
<p>以时间戳（秒）形式，返回当前时间</p>
<div>python<i></i><i></i></div>
<pre><code>time.time()
# 输出：1552884340.400742
</code></pre>
<p>以时间元组形式 struct_time，返回本地时间</p>
<div>python<i></i><i></i></div>
<pre><code>time.localtime()
# 输出：time.struct_time(tm_year=2019, tm_mon=3, tm_mday=18, tm_hour=12, tm_min=47, tm_sec=18, tm_wday=0, tm_yday=77, tm_isdst=0)
</code></pre>
<p>以字符串形式，返回格式化的时间</p>
<div>python<i></i><i></i></div>
<pre><code>time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
# 输出：'2019-03-18 12:48:50'
</code></pre>
<p>格式化指定时间戳，输出字符串</p>
<div>python<i></i><i></i></div>
<pre><code>time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(1554197885.739947))
# 输出：'2019-04-02 17:38:05'
</code></pre>
<h3 id="toc-heading-4">2. 类型转换</h3>
<p>时间元组 → 字符串</p>
<div>python<i></i><i></i></div>
<pre><code>time.asctime(time.localtime())
# 输出：'Mon Mar 18 13:02:31 2019'
</code></pre>
<p>时间戳 → 字符串</p>
<div>python<i></i><i></i></div>
<pre><code>time.ctime(1552884340.400742)
# 输出：'Mon Mar 18 12:45:40 2019'

time.ctime(time.time())
# 输出：'Mon Mar 18 13:03:32 2019'
</code></pre>
<p>时间元组 → 时间戳</p>
<div>python<i></i><i></i></div>
<pre><code>time.mktime(time.localtime())
# 输出：1552885472.0
</code></pre>
<p>字符串 → 时间元组</p>
<div>python<i></i><i></i></div>
<pre><code>time_str=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
time.strptime(time_str, "%Y-%m-%d %H:%M:%S")
# 输出：time.struct_time(tm_year=2019, tm_mon=3, tm_mday=18, tm_hour=13, tm_min=5, tm_sec=48, tm_wday=0, tm_yday=77, tm_isdst=-1)
</code></pre>
<h2 id="toc-heading-5">三、datetime模块</h2>
<div>python<i></i><i></i></div>
<pre><code># 导入包
import datetime
</code></pre>
<h3 id="toc-heading-6">1. datetime时间的计算</h3>
<p>datetime获取的是datetime对象<br />
获取当前日期时间</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.now()
# 输出：datetime.datetime(2019, 3, 18, 15, 50, 31, 201287)
</code></pre>
<p>获取当天日期 date</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.date.today()
# 或 
datetime.datetime.now().date()
# 输出：datetime.date(2019, 3, 18)
</code></pre>
<p>获取当前的时间 time</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.now().time()
# 输出：datetime.time(15, 58, 25, 658748)
</code></pre>
<p>获取时间差<br />
可以计算相差多少 天（days）， 秒（seconds）， 微秒（microseconds）</p>
<div>python<i></i><i></i></div>
<pre><code>start_time = datetime.datetime.now()
end_time = datetime.datetime.now()
(end_time - start_time).seconds
# 执行完第3行输出：6
</code></pre>
<p>获取当前时间向后8个小时的时间<br />
可以计算：天（days），小时（hours），分钟（minutes），秒（seconds），微秒（microseconds）</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.now() + datetime.timedelta(hours=8)
# 输出：datetime.datetime(2019, 3, 19, 0, 19, 10, 233485)
</code></pre>
<p>获取当前是星期几<br />
返回的1~7代表周一到周日，如果用的是weekday则返回的0~6代表周一到周日</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.date.today().isoweekday()
# 或 
datetime.datetime.now().isoweekday()
# 输出：1
</code></pre>
<p>获取上周日和上周一的时间</p>
<div>python<i></i><i></i></div>
<pre><code>today = datetime.date.today()
today_weekday = today.isoweekday()
last_sunday = today - datetime.timedelta(days=today_weekday)
last_monday = last_sunday - datetime.timedelta(days=6)
# 执行完第1行得到：today: datetime.date(2019, 3, 18)
# 执行完第3行得到：last_sunday: datetime.date(2019, 3, 17)
# 执行完第4行得到：last_monday: datetime.date(2019, 3, 11)
</code></pre>
<p>获取上个月第一天和最后一天的日期</p>
<div>python<i></i><i></i></div>
<pre><code>today = datetime.date.today()
last_month_end = datetime.date(today.year, today.month, 1) - datetime.timedelta(days=1)
last_month_begin = datetime.date(last_month_end.year, last_month_end.month, 1)
# 执行完第1行得到：today: datetime.date(2019, 3, 18)
# 执行完第2行得到：last_month_end: datetime.date(2019, 2, 28)
# 执行完第3行得到：last_month_begin: datetime.date(2019, 2, 1)
</code></pre>
<p>计算指定日期当月最后一天的日期和本月天数</p>
<div>python<i></i><i></i></div>
<pre><code>import datetime

def specified_date_info(date_object):
    if date_object.month == 12:
        next_month_first_date = datetime.date(date_object.year+1,1,1)
    else:
        next_month_first_date = datetime.date(date_object.year, date_object.month+1, 1)
    return next_month_first_date - datetime.timedelta(1)

if __name__ == "__main__":
    date = datetime.date(2018, 12, 25)
    specified_month_last_date = specified_date_info(date)
    specified_month_days = specified_date_info(date).day
    print(specified_month_last_date)
    print(specified_month_days)
# 输出：2018-12-31
# 输出：31
</code></pre>
<h3 id="toc-heading-7">2. datetime时间类型的转换</h3>
<p>时间戳 → datetime对象</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.fromtimestamp(1552884340.400742)
# 输出：datetime.datetime(2019, 3, 18, 12, 45, 40, 400742)

datetime.datetime.fromtimestamp(time.time())
# 输出：datetime.datetime(2019, 3, 18, 17, 10, 21, 564136)
</code></pre>
<p>datetime对象 → 时间戳</p>
<div>python<i></i><i></i></div>
<pre><code>time.mktime(datetime.datetime.now().timetuple())
# 输出：1552900590.0
</code></pre>
<p>字符串 → datetime对象</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.strptime("2019-02-14 13:14:00", "%Y-%m-%d %H:%M:%S")
# 输出：datetime.datetime(2019, 2, 14, 13, 14)
</code></pre>
<p>datetime对象 → 字符串</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 输出：'2019-03-18 17:26:44'
</code></pre>
<p>时间元祖 → datetime对象</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.fromtimestamp(time.mktime(time.localtime()))
# 输出：datetime.datetime(2019, 3, 18, 17, 22, 13)
</code></pre>
<p>datetime对象 → 时间元祖</p>
<div>python<i></i><i></i></div>
<pre><code>datetime.datetime.now().timetuple()
# 输出：time.struct_time(tm_year=2019, tm_mon=3, tm_mday=18, tm_hour=17, tm_min=22, tm_sec=53, tm_wday=0, tm_yday=77, tm_isdst=-1)
</code></pre>
<h2 id="toc-heading-8">四、datetime，data，time对象转换</h2>
<div>python<i></i><i></i></div>
<pre><code>import time
from datetime import datetime
from datetime import date
from datetime import timedelta

datetime对象 → date对象
datetime.now().date() 
# 输出：datetime.date(2019, 3, 17)

datetime对象 → time对象
datetime.now().time()
# 输出：datetime.time(17, 33, 3, 833546)

date对象 + time对象 → datetime对象
t1 = datetime.now().date() 
t2 = datetime.now().time()
datetime.combine(t1, t2)
# 输出：datetime.datetime(2019, 3, 18, 17, 34, 7, 363993)

时间戳 → date对象
date.fromtimestamp(time.time())
# 输出：datetime.date(2019, 3, 17)
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/pythonjichushijianheriqimokuai.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
