<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>沐雨橙风</title>
  
  <subtitle>水滴石穿</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://sirxy.github.io/"/>
  <updated>2019-04-24T04:05:40.595Z</updated>
  <id>http://sirxy.github.io/</id>
  
  <author>
    <name>Sirxy</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Python抓取B站视频信息,写入csv文件</title>
    <link href="http://sirxy.github.io/2019/04/24/Python%E6%8A%93%E5%8F%96B%E7%AB%99%E8%A7%86%E9%A2%91%E4%BF%A1%E6%81%AF-%E5%86%99%E5%85%A5csv%E6%96%87%E4%BB%B6/"/>
    <id>http://sirxy.github.io/2019/04/24/Python抓取B站视频信息-写入csv文件/</id>
    <published>2019-04-24T02:51:15.000Z</published>
    <updated>2019-04-24T04:05:40.595Z</updated>
    
    <content type="html"><![CDATA[<p>今儿闲来无事，就想着捣鼓捣鼓，想着输出一篇逛B站想爬下来这些小视频，抓视频相关信息的爬虫。<br>准备好小板凳，这就开始咯哦。<a id="more"></a><br>首先，本文打算抓取B站小视频这一块的相关信息（用户id、用户名、是否vip用户、视频id、视频描述、上传时间、浏览量、视频url），于是，将事先准备好的小视频的url奉上：<a href="http://vc.bilibili.com/p/eden/rank#/?tab=%E5%85%A8%E9%83%A8。" target="_blank" rel="noopener">http://vc.bilibili.com/p/eden/rank#/?tab=%E5%85%A8%E9%83%A8。</a><br>有了小视频url，来开始今天的旅程吧。<br>浏览器访问上面这个url,打开Google Chrome自带的开发者工具，切换到network选项卡，按F5刷新网页，你会看到有很多的请求资源。<br><img src="/2019/04/24/Python抓取B站视频信息-写入csv文件/bilibili01.jpg" alt="bilibili01"><br>那么我们该怎么找到包含有小视频信息的请求呢，不要着急，跟我往下看。<br>滚动鼠标滚轮，继续，可以看到又加载出来很多请求资源，发现很多请求是动态加载的，于是想到会不会是ajax加载出来de呢，带着这种想法，切换到network选项卡下的XHR选项，可以看到很多XHR请求，一个一个点击查找，发现数据貌似在类似<a href="http://api.vc.bilibili.com/board/v1/ranking/top?page_size=10&amp;next_offset=&amp;tag=%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&amp;platform=pc请求中，" target="_blank" rel="noopener">http://api.vc.bilibili.com/board/v1/ranking/top?page_size=10&amp;next_offset=&amp;tag=%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&amp;platform=pc请求中，</a><br><img src="/2019/04/24/Python抓取B站视频信息-写入csv文件/bilibili02.jpg" alt="bilibili02"><br>到这里为止，我们找到了目标url。<br>开始码代码之前，首先确定整个的采集流程逻辑：<br>1、发起请求，接收响应；<br>2、解析响应，拿到想拿的数据；<br>3、持久化（本地化或入库），本文直接本地持久化写入csv文件。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line">import requests</span><br><span class="line">import jsonpath</span><br><span class="line">import csv</span><br><span class="line"># 1、发起请求，获取相应内容模块</span><br><span class="line">def get_response(url):</span><br><span class="line">headers = &#123;</span><br><span class="line">&apos;User-Agent&apos;: &apos;Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.3&apos;</span><br><span class="line">&#125;</span><br><span class="line">try:</span><br><span class="line">response = requests.get(url, headers=headers)</span><br><span class="line">if response.status_code == 200:</span><br><span class="line">response.encoding = &apos;utf-8&apos;</span><br><span class="line">return response</span><br><span class="line">return None</span><br><span class="line">except Exception as e:</span><br><span class="line">print(e)</span><br><span class="line">return None</span><br><span class="line"></span><br><span class="line"># 2、解析相应，提取相关数据模块</span><br><span class="line">def parse_response(response):</span><br><span class="line">response_json = response.json()</span><br><span class="line">uid = jsonpath.jsonpath(response_json, &apos;$.data.items[*].user.uid&apos;) # 用户id列表</span><br><span class="line">name = jsonpath.jsonpath(response_json, &apos;$.data.items[*].user.name&apos;) # 用户名列表</span><br><span class="line">is_vip = jsonpath.jsonpath(response_json, &apos;$.data.items[*].user.is_vip&apos;) # 是否vip用户列表</span><br><span class="line">item_id = jsonpath.jsonpath(response_json, &apos;$.data.items[*].item.id&apos;) # 视频id列表</span><br><span class="line">description = jsonpath.jsonpath(response_json, &apos;$.data.items[*].item.description&apos;) # 视频描述列表</span><br><span class="line">upload_time = jsonpath.jsonpath(response_json, &apos;$.data.items[*].item.upload_time&apos;) # 上传时间列表</span><br><span class="line">watched_num = jsonpath.jsonpath(response_json, &apos;$.data.items[*].item.watched_num&apos;) # 浏览量列表</span><br><span class="line">video_playurl = jsonpath.jsonpath(response_json, &apos;$.data.items[*].item.video_playurl&apos;) # 视频url列表</span><br><span class="line"></span><br><span class="line">return zip(uid, name, is_vip, item_id, upload_time, watched_num, video_playurl)</span><br><span class="line"></span><br><span class="line"># 业务逻辑</span><br><span class="line">def main():</span><br><span class="line"># 一个ajax的url</span><br><span class="line">url = &apos;http://api.vc.bilibili.com/board/v1/ranking/top?page_size=10&amp;next_offset=&amp;tag=%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&amp;platform=pc&apos;</span><br><span class="line">response = get_response(url) # 调用get_response</span><br><span class="line">data_list = parse_response(response)</span><br><span class="line"># print(type(data_list), data_list) # &lt;class &apos;zip&apos;&gt; &lt;zip object at 0x031C0260&gt;</span><br><span class="line"># for i in data_list:</span><br><span class="line"># print(i) # 元组</span><br><span class="line"></span><br><span class="line"># 3、准备本地持久化到csv文件。当然也可以入库，读者可以自行编写。</span><br><span class="line"># 当然这里也可以封装成一个函数模块，供调用，直接提供文件名即可，读者自行优化。</span><br><span class="line"># 打开文件，追加a</span><br><span class="line">out = open(&apos;bilibili111.csv&apos;, &apos;a&apos;, newline=&apos;&apos;)</span><br><span class="line">for u, n, i, item, uptime, wat, play in data_list: </span><br><span class="line"># print(str(u) +&apos;,&apos; + n +&apos;,&apos; + str(i) +&apos;,&apos; + str(item) +&apos;,&apos; + uptime +&apos;,&apos; + str(wat) +&apos;,&apos; + play)</span><br><span class="line"># with open(&apos;bilibili.csv&apos;, &apos;a&apos;, newline=&apos;&apos;) as fp:</span><br><span class="line"># fp.write(str(u) +&apos;,&apos; + n +&apos;,&apos; + str(i) +&apos;,&apos; + str(item) +&apos;,&apos; + uptime +&apos;,&apos; + str(wat) +&apos;,&apos; + play)</span><br><span class="line"># fp.write(&apos;\n&apos;)</span><br><span class="line"></span><br><span class="line"># 重组数据为列表</span><br><span class="line">data_list = []</span><br><span class="line">data_list.append(u)</span><br><span class="line">data_list.append(n)</span><br><span class="line">data_list.append(i)</span><br><span class="line">data_list.append(item)</span><br><span class="line">data_list.append(uptime)</span><br><span class="line">data_list.append(wat)</span><br><span class="line">data_list.append(play)</span><br><span class="line">print(data_list)</span><br><span class="line"></span><br><span class="line"># 设定写入模式</span><br><span class="line">csv_write = csv.writer(out, dialect=&apos;excel&apos;)</span><br><span class="line"># 写入具体内容</span><br><span class="line">csv_write.writerow(data_list)</span><br><span class="line">out.close()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">if __name__ == &apos;__main__&apos;:</span><br><span class="line">main()</span><br></pre></td></tr></table></figure><p>运行直接运行上述代码，看到已经有10条数据存入csv文件中了。<br>剩下的只要写一个循环就可以拿到所有的数据了，读者也可以下载视频根据视频的url，读者自行完成即可。</p><h3 id="拓展知识点：csv文件的读取："><a href="#拓展知识点：csv文件的读取：" class="headerlink" title="拓展知识点：csv文件的读取："></a>拓展知识点：csv文件的读取：</h3><p>定义一个csv文件的变量csv_file,然后通过open对此文件进行打开，打开模式采用‘r’<br>csv_file只是一个对象的模型，对这个模型进行遍历打印：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">try:</span><br><span class="line">csv_file = csv.reader(open(&apos;bilibili111.csv&apos;, &apos;r&apos;))</span><br><span class="line">print(csv_file) # &lt;_csv.reader object at 0x02F015F0&gt;</span><br><span class="line">for content_list in csv_file:</span><br><span class="line">if content_list:</span><br><span class="line">print(content_list)</span><br><span class="line">else:</span><br><span class="line">break</span><br><span class="line">except FileNotFoundError as e:</span><br><span class="line">print(e, &apos;dfd&apos;)</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;今儿闲来无事，就想着捣鼓捣鼓，想着输出一篇逛B站想爬下来这些小视频，抓视频相关信息的爬虫。&lt;br&gt;准备好小板凳，这就开始咯哦。&lt;/p&gt;
    
    </summary>
    
      <category term="爬虫" scheme="http://sirxy.github.io/categories/%E7%88%AC%E8%99%AB/"/>
    
    
      <category term="Python爬虫" scheme="http://sirxy.github.io/tags/Python%E7%88%AC%E8%99%AB/"/>
    
  </entry>
  
  <entry>
    <title>Virtualenv虚拟环境</title>
    <link href="http://sirxy.github.io/2019/04/11/Virtualenv/"/>
    <id>http://sirxy.github.io/2019/04/11/Virtualenv/</id>
    <published>2019-04-11T09:02:24.000Z</published>
    <updated>2019-04-11T09:20:50.913Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Virtualenv"><a href="#Virtualenv" class="headerlink" title="Virtualenv"></a>Virtualenv</h3><p>VirtualEnv用于在一台机器上创建多个独立的Python虚拟运行环境，多个Python环境相互独立，互不影响，它能够：在没有权限的情况下安装新套件；不同应用可以使用不同的套件版本；套件升级不影响其他应用。<a id="more"></a></p><ul><li><p>ubuntu16.04安装:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ [sudo] pip3 install virtualenv</span><br></pre></td></tr></table></figure></li><li><p>创建虚拟环境</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$  virtualenv venv</span><br></pre></td></tr></table></figure></li><li><p>激活虚拟环境</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">ubuntu:</span><br><span class="line"></span><br><span class="line">    $ source venv/bin/activate</span><br><span class="line"></span><br><span class="line">windows:</span><br><span class="line">    cd ./f1/Scripts/</span><br><span class="line">    activate.bat</span><br><span class="line">    (f1) F:\tulingxueyuan\f1\Scripts&gt;</span><br><span class="line">```    </span><br><span class="line">当虚拟环境被激活了，Python解释器的位置会被添加到PATH中，但是这个改动并不是永久的；它只影响当前命令会话。提醒一下，你激活了虚拟环境，该激活命令会将环境的名称包含在命令提示符里面：</span><br></pre></td></tr></table></figure></li></ul><p>(venv) $<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- 停止虚拟环境</span><br><span class="line">当你在虚拟环境中完成工作并想回到全局Python解释器，在命令提示符中输入deactivate就可以了。</span><br></pre></td></tr></table></figure></p><p>$ deactivate<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">### 使用pip安装python包</span><br><span class="line">大多数的Python包是通过pip程序安装的，在创建虚拟环境的时候virtualenv会自动添加进去。当一个虚拟环境被激活后，pip程序的位置会被添加到PATH中。</span><br><span class="line"></span><br><span class="line">注：如果你使用pyvenv创建虚拟环境在Python 3.3中，则必须手动安装pip。安装指令在pip网站上可以找到。在Python 3.4下，pyvenv会自动安装pip。</span><br><span class="line"></span><br><span class="line">比如，安装Flask到虚拟环境中，使用下面的命令：</span><br></pre></td></tr></table></figure></p><p>(venv)$ pip install flask<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">通过这个命令，Flask和它的依赖集都会安装到虚拟环境中。你可以验证Flask是否正确安装通过启动Python解释器并试着导入它：</span><br></pre></td></tr></table></figure></p><p>(venv)$ python</p><blockquote><blockquote><blockquote><p>import flask<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">如果需要安装的包比较多的时候，这样做会比较繁琐，我们还有一键安装的方法。首先新建一个文本文件，如：requirements.txt，然后将你需要安装的包名保存到该文件中(根据自己的需要)，如下：</span><br></pre></td></tr></table></figure></p></blockquote></blockquote></blockquote><p>Babel==1.3<br>Flask==0.10.1<br>Flask-Login==0.2.7<br>Flask-SQLAlchemy==1.0<br>Flask-WTF==0.9.3<br>Jinja2==2.7.1<br>SQLAlchemy==0.8.2<br>WTForms==1.0.5<br>Werkzeug==0.9.4<br>psycopg2==2.5.1<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">最后你只需要输入以下命令，所有需要的包就可以全部安装好了：</span><br></pre></td></tr></table></figure></p><p>(venv)$ pip install -r requirements.txt<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">如果没有出现错误，祝贺你：安装成功了。</span><br><span class="line"></span><br><span class="line">若要查看当前环境安装了哪些包，可以使用下面的命令：</span><br></pre></td></tr></table></figure></p><p>(venv)$ pip freeze<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">还可以直接导出到文件中</span><br></pre></td></tr></table></figure></p><p>(venv)$ pip freeze &gt; requirements.txt<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">### 移除环境</span><br><span class="line">删除虚拟环境只需通过停用虚拟环境并删除环境文件夹及其所有内容即可完成：</span><br></pre></td></tr></table></figure></p><p>(ENV)$ deactivate<br>$ rm -r /path/to/ENV<br><code>`</code></p><p><img src="https://virtualenv.pypa.io/en/latest/" alt="Virtualenv —— virtualenv 16.4.4.dev0 documentation"></p><p>持续中。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;Virtualenv&quot;&gt;&lt;a href=&quot;#Virtualenv&quot; class=&quot;headerlink&quot; title=&quot;Virtualenv&quot;&gt;&lt;/a&gt;Virtualenv&lt;/h3&gt;&lt;p&gt;VirtualEnv用于在一台机器上创建多个独立的Python虚拟运行环境，多个Python环境相互独立，互不影响，它能够：在没有权限的情况下安装新套件；不同应用可以使用不同的套件版本；套件升级不影响其他应用。&lt;/p&gt;
    
    </summary>
    
      <category term="Python" scheme="http://sirxy.github.io/categories/Python/"/>
    
    
      <category term="Python基础" scheme="http://sirxy.github.io/tags/Python%E5%9F%BA%E7%A1%80/"/>
    
  </entry>
  
  <entry>
    <title>教你三分钟学会Ajax</title>
    <link href="http://sirxy.github.io/2019/04/11/ajax/"/>
    <id>http://sirxy.github.io/2019/04/11/ajax/</id>
    <published>2019-04-11T07:52:48.000Z</published>
    <updated>2019-04-11T09:13:55.986Z</updated>
    
    <content type="html"><![CDATA[<h3 id="ajax是什么"><a href="#ajax是什么" class="headerlink" title="ajax是什么?"></a>ajax是什么?</h3><p>AJAX 指异步 JavaScript 及 XML（Asynchronous JavaScript And XML）。AJAX 是与服务器交换数据并更新部分网页的艺术，在不重新加载整个页面的情况下。AJAX 是一种在 2005 年由 Google 推广开来的编程模式。<a id="more"></a>AJAX 不是一种新的编程语言，而是一种使用现有标准的新方法。通过 AJAX，你可以创建更好、更快以及更友好的 WEB 应用程序。AJAX 基于 JavaScript 和 HTTP 请求（HTTP requests）。通过 HTTP 请求加载远程数据。</p><p>jQuery 底层对 AJAX 实现进行了封装.使得我们在进行ajax操作时,不必像原生js中那么复杂<br>$.get, $.post, $.ajax() 返回其创建的 XMLHttpRequest 对象。多数情况下我们不需要去操作返回的对象</p><h3 id="如何使用ajax技术"><a href="#如何使用ajax技术" class="headerlink" title="如何使用ajax技术?"></a>如何使用ajax技术?</h3><p>首先你得有web服务器,能够通过浏览器去执行你的html和你的python，注意一点:我们平常写的html,直接在浏览器打开时 使用的是file协议，而ajax是基于HTTP请求的,所以要求你的html能够使用http的协议打开<br>如果你能做到用http协议去打开你的html并且能够正常显示的话,就代表你的web服务器搭建成功。</p><ul><li><p>$.get() 方法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">//发送ajax请求 1.url  2.可选 发送get请求时携带的参数  ,3,可选 回调函数,请求完之后做什么事  4,可选,返回的数据类型 json</span><br><span class="line">$.get(url,&#123;请求的参数&#125;,function(data)&#123;&#125;,&apos;json&apos;)</span><br></pre></td></tr></table></figure></li><li><p>$.post()</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$.post(url,&#123;请求的参数&#125;,function(data)&#123;&#125;,&apos;json&apos;)</span><br></pre></td></tr></table></figure></li><li><p>$.ajax()</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">$.ajax(&#123;</span><br><span class="line">    url:&apos;/cgi-bin/5.py&apos;,//当前请求的url地址</span><br><span class="line">    type:&apos;get&apos;,//当前请求的方式 get  post</span><br><span class="line">    data:&#123;id:100,username:&apos;zhangsan&apos;&#125;,//请求时发送的参数</span><br><span class="line">    dataType:&apos;json&apos;,//返回的数据类型</span><br><span class="line">    success:function(data)&#123;</span><br><span class="line">        //ajax请求成功后执行的代码</span><br><span class="line">        console.log(data);</span><br><span class="line">    &#125;,</span><br><span class="line">    error:function()&#123;</span><br><span class="line">        //ajax执行失败后执行的代码</span><br><span class="line">        alert(&apos;ajax执行错误&apos;);</span><br><span class="line">    &#125;,</span><br><span class="line">    timeout:2000,//设置当前请求的超时时间  毫秒,必须时异步请求才会生效</span><br><span class="line">    async:true// 是否异步  true为异步  false 同步</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li><li><p>ajax异步 同步</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">//设置ajax的全局配置  async:false 设置当前请求为同步</span><br><span class="line">$.ajaxSetup(&#123;</span><br><span class="line">    async:false</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li></ul><p>关于ajax中 异步 和 同步：<br>ajax默认就是异步请求,async (默认: true) 默认设置下，所有请求均为异步请求。<br>如果需要发送同步请求，请将此选项设置为 false。<br>同步请求,就发ajax请求发出去后必须等待ajax的结果返回后才能继续往下执行。<br>一般情况下都使用异步操作就可以,除非有特殊情况,必须等ajax的结果回来后才能做处理的,就用同步。</p><h3 id="扩展：了解json格式数据"><a href="#扩展：了解json格式数据" class="headerlink" title="扩展：了解json格式数据"></a>扩展：了解json格式数据</h3><p>json是 JavaScript Object Notation 的首字母缩写，单词的意思是javascript对象表示法，这里说的json指的是类似于javascript对象的一种数据格式，目前这种数据格式比较流行，逐渐替换掉了传统的xml数据格式。</p><p>javascript对象字面量：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var tom = &#123;</span><br><span class="line">    name:&apos;tom&apos;,</span><br><span class="line">    age:18</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>json格式的数据：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    &quot;name&quot;:&apos;tom&apos;,</span><br><span class="line">    &quot;age&quot;:18</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>与json对象不同的是，json数据格式的属性名称需要用双引号引起来，用单引号或者不用引号会导致读取数据错误。</p><p>json的另外一个数据格式是数组，和javascript中的数组字面量相同。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[&apos;tom&apos;,18,&apos;programmer&apos;]</span><br></pre></td></tr></table></figure></p><p>持续中。。。。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;ajax是什么&quot;&gt;&lt;a href=&quot;#ajax是什么&quot; class=&quot;headerlink&quot; title=&quot;ajax是什么?&quot;&gt;&lt;/a&gt;ajax是什么?&lt;/h3&gt;&lt;p&gt;AJAX 指异步 JavaScript 及 XML（Asynchronous JavaScript And XML）。AJAX 是与服务器交换数据并更新部分网页的艺术，在不重新加载整个页面的情况下。AJAX 是一种在 2005 年由 Google 推广开来的编程模式。&lt;/p&gt;
    
    </summary>
    
      <category term="web前端" scheme="http://sirxy.github.io/categories/web%E5%89%8D%E7%AB%AF/"/>
    
    
      <category term="web前端" scheme="http://sirxy.github.io/tags/web%E5%89%8D%E7%AB%AF/"/>
    
  </entry>
  
  <entry>
    <title>MongoDB简介与安装</title>
    <link href="http://sirxy.github.io/2019/04/11/MongoDB%E7%AE%80%E4%BB%8B%E4%B8%8E%E5%AE%89%E8%A3%85/"/>
    <id>http://sirxy.github.io/2019/04/11/MongoDB简介与安装/</id>
    <published>2019-04-11T05:16:17.000Z</published>
    <updated>2019-04-11T05:38:55.093Z</updated>
    
    <content type="html"><![CDATA[<h3 id="什么是MongoDB"><a href="#什么是MongoDB" class="headerlink" title="什么是MongoDB ?"></a>什么是MongoDB ?</h3><p>MongoDB 是一个基于分布式文件存储的开源数据库系统。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。<a id="more"></a><br><img src="/2019/04/11/MongoDB简介与安装/mongodb.jpg" alt="logo"><br>MongoDB 是一个介于关系数据库和非关系数据库之间的产品，是非关系数据库当中功能最丰富，最像关系数据库的。</p><p>在高负载的情况下，添加更多的节点，可以保证服务器性能。</p><p>MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。</p><p>MongoDB 将数据存储为一个文档，数据结构由键值(key=&gt;value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档，数组及文档数组。<br><img src="/2019/04/11/MongoDB简介与安装/crud-annotated-document.jpg" alt="dataframe"></p><ul><li>主要特点<br>1.MongoDB的提供了一个面向文档存储，操作起来比较简单和容易。<br>2.你可以在MongoDB记录中设置任何属性的索引 (如：FirstName=”Sameer”,Address=”8 Gandhi Road”)来实现更快的排序。<br>3.你可以通过本地或者网络创建数据镜像，这使得MongoDB有更强的扩展性。<br>4.如果负载的增加（需要更多的存储空间和更强的处理能力） ，它可以分布在计算机网络中的其他节点上这就是所谓的分片。<br>5.Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记，可轻易查询文档中内嵌的对象及数组。<br>6.MongoDb 使用update()命令可以实现替换完成的文档（数据）或者一些指定的数据字段 。<br>7.Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。<br>8.Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录，将key与value传给Reduce函数进行处理。<br>9.Map函数和Reduce函数是使用Javascript编写的，并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。<br>10.GridFS是MongoDB中的一个内置功能，可以用于存放大量小文件。<br>11.MongoDB允许在服务端执行脚本，可以用Javascript编写某个函数，直接在服务端执行，也可以把函数的定义存储在服务端，下次直接调用即可。<br>12.MongoDB支持各种编程语言:RUBY，PYTHON，JAVA，C++，PHP，C#等多种语言。<br>MongoDB安装简单。</li></ul><h3 id="ubuntu16-04通过apt-get方式安装MongoDB"><a href="#ubuntu16-04通过apt-get方式安装MongoDB" class="headerlink" title="ubuntu16.04通过apt-get方式安装MongoDB"></a>ubuntu16.04通过apt-get方式安装MongoDB</h3><p>虽然Ubuntu本身也提供MongoDB安装包，但往往官网的安装包版本更新。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">~$ apt-cache show mongodb-clients</span><br><span class="line">Package: mongodb-clients</span><br><span class="line">Priority: optional</span><br><span class="line">Section: universe/database</span><br><span class="line">Installed-Size: 160066</span><br><span class="line">Maintainer: Ubuntu Developers &lt;ubuntu-devel-discuss@lists.ubuntu.com&gt;</span><br><span class="line">Original-Maintainer: Laszlo Boszormenyi (GCS) &lt;gcs@debian.org&gt;</span><br><span class="line">Architecture: amd64</span><br><span class="line">Source: mongodb</span><br><span class="line">Version: 1:2.6.10-0ubuntu1   # 版本号</span><br></pre></td></tr></table></figure></p><ul><li>安装:</li></ul><p>1.导入包管理系统使用的公钥<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6</span><br></pre></td></tr></table></figure></p><p>2.为MongoDB创建一个列表文件</p><p>根据版本创建/etc/apt/sources.list.d/mongodb-org-3.4.list 列表文件<br>Ubuntu 16.04<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse&quot; | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list</span><br></pre></td></tr></table></figure></p><p>3.更新本地包数据库<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br></pre></td></tr></table></figure></p><p>4.安装最新版本的MongoDB<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install -y mongodb-org</span><br></pre></td></tr></table></figure></p><p>5.查看配置文件</p><p>配置文件mongod.conf所在路径:/etc/mongod.conf<br>内容:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"># mongod.conf</span><br><span class="line"></span><br><span class="line"># for documentation of all options, see:</span><br><span class="line">#   http://docs.mongodb.org/manual/reference/configuration-options/</span><br><span class="line"></span><br><span class="line"># Where and how to store data.</span><br><span class="line">storage:</span><br><span class="line">  dbPath: /var/lib/mongodb   #数据库存储路径</span><br><span class="line">  journal:</span><br><span class="line">    enabled: true</span><br><span class="line">#  engine:</span><br><span class="line">#  mmapv1:</span><br><span class="line">#  wiredTiger:</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># where to write logging data.</span><br><span class="line">systemLog:</span><br><span class="line">  destination: file</span><br><span class="line">  logAppend: true     #以追加的方式写入日志</span><br><span class="line">  path: /var/log/mongodb/mongod.log   #日志文件路径</span><br><span class="line"></span><br><span class="line"># network interfaces</span><br><span class="line">net:</span><br><span class="line">  port: 27017</span><br><span class="line">  bindIp: 127.0.0.1   #绑定监听的ip 127.0.0.1只能监听本地的连接，可以改为0.0.0.0</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#processManagement:</span><br><span class="line"></span><br><span class="line">#security:</span><br><span class="line"></span><br><span class="line">#operationProfiling:</span><br><span class="line"></span><br><span class="line">#replication:</span><br><span class="line"></span><br><span class="line">#sharding:</span><br><span class="line"></span><br><span class="line">## Enterprise-Only Options:</span><br><span class="line"></span><br><span class="line">#auditLog:</span><br><span class="line"></span><br><span class="line">#snmp:</span><br></pre></td></tr></table></figure></p><p>6.启动和关闭MongoDB<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">sudo service mongod start  # 启动</span><br><span class="line">sudo service mongod stop   # 关闭</span><br><span class="line"></span><br><span class="line">hupeng@hupeng-vm:~$ ps aux | grep mongod   # 查看守护进程mongod的运行状态</span><br><span class="line">mongodb   18454  9.5  1.5 292152 61952 ?        Ssl  12:27   0:00 /usr/bin/mongod --quiet --config /etc/mongod.conf</span><br><span class="line">hupeng    18475  0.0  0.0  15964   936 pts/4    R+   12:27   0:00 grep --color=auto mongod</span><br></pre></td></tr></table></figure></p><ul><li>卸载<br>1.关闭守护进程mongod<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo service mongod stop</span><br></pre></td></tr></table></figure></li></ul><p>2.卸载安装的软件包<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get purge mongodb-org*</span><br></pre></td></tr></table></figure></p><p>3.移除数据库和日志文件（数据库和日志文件的路径取决于/etc/mongod.conf文件中的配置)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sudo rm -r /var/log/</span><br><span class="line">mongodb</span><br><span class="line">sudo rm </span><br><span class="line">-r /var/lib/mongodb</span><br></pre></td></tr></table></figure></p><p>参考文档: <a href="https://docs.mongodb.com/master/tutorial/install-mongodb-on-ubuntu/" target="_blank" rel="noopener">Install MongoDB Community Edition on Ubuntu —— MongoDB Manual</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;什么是MongoDB&quot;&gt;&lt;a href=&quot;#什么是MongoDB&quot; class=&quot;headerlink&quot; title=&quot;什么是MongoDB ?&quot;&gt;&lt;/a&gt;什么是MongoDB ?&lt;/h3&gt;&lt;p&gt;MongoDB 是一个基于分布式文件存储的开源数据库系统。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。&lt;/p&gt;
    
    </summary>
    
      <category term="数据库" scheme="http://sirxy.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
      <category term="数据库" scheme="http://sirxy.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>Python操作redis</title>
    <link href="http://sirxy.github.io/2019/04/11/Python%E6%93%8D%E4%BD%9Credis/"/>
    <id>http://sirxy.github.io/2019/04/11/Python操作redis/</id>
    <published>2019-04-11T05:07:35.000Z</published>
    <updated>2019-04-11T05:11:00.375Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Python-访问-Redis"><a href="#Python-访问-Redis" class="headerlink" title="Python 访问 Redis"></a>Python 访问 Redis</h3><p>对于使用 Python 访问 Redis，我们需要先安装 <code>redis-py</code> 软件包，该包实现了 Python 的 Redis 驱动。通过以下命令建立工作环境，安装软件包：<a id="more"></a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo  pip3 install redis</span><br></pre></td></tr></table></figure></p><h3 id="Python-操作-Redis"><a href="#Python-操作-Redis" class="headerlink" title="Python 操作 Redis"></a>Python 操作 Redis</h3><p>Python 中访问 Redis 可以通过redis-py软件包进行。类似于 PyMongo, 也是需要先创建一个 Redis 客户端，如下代码基本操作:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import redis</span><br><span class="line">r = redis.Redis(host=&apos;127.0.0.1&apos;, port=6379,decode_responses=True)</span><br><span class="line">r.set(&apos;name&apos;, &apos;OK&apos;)</span><br><span class="line">print(r.get(&apos;name&apos;))</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;Python-访问-Redis&quot;&gt;&lt;a href=&quot;#Python-访问-Redis&quot; class=&quot;headerlink&quot; title=&quot;Python 访问 Redis&quot;&gt;&lt;/a&gt;Python 访问 Redis&lt;/h3&gt;&lt;p&gt;对于使用 Python 访问 Redis，我们需要先安装 &lt;code&gt;redis-py&lt;/code&gt; 软件包，该包实现了 Python 的 Redis 驱动。通过以下命令建立工作环境，安装软件包：&lt;/p&gt;
    
    </summary>
    
      <category term="数据库" scheme="http://sirxy.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
      <category term="数据库" scheme="http://sirxy.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>Redis高级实用特性</title>
    <link href="http://sirxy.github.io/2019/04/11/Redis%E9%AB%98%E7%BA%A7%E5%AE%9E%E7%94%A8%E7%89%B9%E6%80%A7/"/>
    <id>http://sirxy.github.io/2019/04/11/Redis高级实用特性/</id>
    <published>2019-04-11T04:50:13.000Z</published>
    <updated>2019-04-11T06:17:59.257Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Redis-安全"><a href="#Redis-安全" class="headerlink" title="Redis 安全"></a>Redis 安全</h3><p>我们可以通过 redis 的配置文件设置密码参数，这样客户端连接到 redis 服务就需要密码验证，这样可以让你的 redis 服务更安全。<br><a id="more"></a><br>查看是否设置了密码验证：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; CONFIG get requirepass</span><br><span class="line">1) &quot;requirepass&quot;</span><br><span class="line">2) &quot;&quot;</span><br></pre></td></tr></table></figure></p><p>默认情况下 requirepass 参数是空的，这就意味着你无需通过密码验证就可以连接到 redis 服务。</p><p>临时修改密码(redis服务重启后不再生效)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; CONFIG set requirepass &quot;runoob&quot;</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; CONFIG get requirepass</span><br><span class="line">1) &quot;requirepass&quot;</span><br><span class="line">2) &quot;runoob&quot;</span><br></pre></td></tr></table></figure></p><p>配置文件为Redis添加密码<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">修改配置文件</span><br><span class="line">sudo vim /etc/redis/redis.conf</span><br><span class="line"></span><br><span class="line">设置：requirepass redis的密码</span><br><span class="line"></span><br><span class="line"># requirepass foobared</span><br><span class="line"></span><br><span class="line">requirepass abc123</span><br><span class="line"></span><br><span class="line">重启服务</span><br><span class="line">sudo service redis restart</span><br><span class="line"></span><br><span class="line">登录（两种）</span><br><span class="line">1.# ./redis-cli -a  密码 //连接时指定密码来进行授权</span><br><span class="line">2.redis-cli 进入后发现操作不了时</span><br><span class="line">  auth 密码</span><br><span class="line">  OK</span><br><span class="line">---------------------</span><br><span class="line">windows 下设置密码生效</span><br><span class="line">修改配置文件</span><br><span class="line">启动服务 加载配置文件redis-server redis.conf  \(加载一次即可\)</span><br><span class="line">启动客户端</span><br></pre></td></tr></table></figure></p><h3 id="Redis主从复制"><a href="#Redis主从复制" class="headerlink" title="Redis主从复制"></a>Redis主从复制</h3><p>操作步骤：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">1.先将linux虚拟机关闭，之后克隆一个。</span><br><span class="line"></span><br><span class="line">2.启动两个虚拟机：master（主）和slave（从）</span><br><span class="line"></span><br><span class="line">3. 在slave（从）中配置一下ip地址</span><br><span class="line"></span><br><span class="line">   \# ifconfig eth0 192.168.128.229</span><br><span class="line"></span><br><span class="line">   \# ping 一下看看通不通。</span><br><span class="line"></span><br><span class="line">4. 配置从机</span><br><span class="line"></span><br><span class="line">   进入：配置文件</span><br><span class="line"></span><br><span class="line">   slaveof  192.168.128.228 6379   //配置连接主机的Redis的ip和端口</span><br><span class="line"></span><br><span class="line">   masterauth 密码  //配置连接密码</span><br><span class="line"></span><br><span class="line">   最后启动slave（从）机的Redis服务。</span><br><span class="line"></span><br><span class="line">其他：可以通过info命令中的role属性查看自己角色是master、slave</span><br></pre></td></tr></table></figure></p><h3 id="Redis事务"><a href="#Redis事务" class="headerlink" title="Redis事务"></a>Redis事务</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&gt;multi   //开启一个事务</span><br><span class="line">&gt;set age 10 //暂存指令队列</span><br><span class="line">&gt;set age 20</span><br><span class="line">&gt;exec    //开始执行（提交事务）</span><br><span class="line">或&gt;discard //清空指令队列（事务回滚）</span><br></pre></td></tr></table></figure><h3 id="Redis乐观锁"><a href="#Redis乐观锁" class="headerlink" title="Redis乐观锁"></a>Redis乐观锁</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Redis Watch 命令用于监视一个(或多个) key ，如果在事务执行之前这个(或这些) key 被其他命令所改动，那么事务将被打断</span><br><span class="line">在事务前对被操作的属性做一个：</span><br><span class="line">&gt; watch age</span><br><span class="line">&gt;multi   //开启一个事务(在此期间有其他修改，则此处会失败)</span><br><span class="line">&gt;set age 10 //暂存指令队列</span><br><span class="line">&gt;set age 20</span><br><span class="line">&gt;exec    //开始执行（提交事务）</span><br><span class="line">或&gt;discard //清空指令队列（事务回滚）</span><br></pre></td></tr></table></figure><h3 id="Redis持久化机制-通过修改配置文件做设置"><a href="#Redis持久化机制-通过修改配置文件做设置" class="headerlink" title="Redis持久化机制(通过修改配置文件做设置)"></a>Redis持久化机制(通过修改配置文件做设置)</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">1.snapshotting(快照)默认方式</span><br><span class="line">   配置    save</span><br><span class="line">   save 900 1 #900秒内如果超过1个key被修改，则发起快照保存</span><br><span class="line">   save 300 10 #300秒内容如超过10个key被修改，则发起快照保存</span><br><span class="line">   save 60 10000</span><br><span class="line">2.Append-only file（aof方式）</span><br><span class="line">   配置 appendonly on 改为yes</span><br><span class="line">   会在bin目录下产生一个.aof的文件</span><br><span class="line">   关于aof的配置</span><br><span class="line">   appendonly yes //启用aof 持久化方式</span><br><span class="line"></span><br><span class="line">   # appendfsync always //收到写命令就立即写入磁盘，最慢，但是保证完全的持久化</span><br><span class="line">     appendfsync everysec //每秒钟写入磁盘一次，在性能和持久化方面做了很好的折中</span><br><span class="line">   # appendfsync no //完全依赖os，性能最好,持久化没保证</span><br></pre></td></tr></table></figure><h3 id="Redis发布订阅"><a href="#Redis发布订阅" class="headerlink" title="Redis发布订阅"></a>Redis发布订阅</h3><p>Redis 发布订阅(pub/sub)是一种消息通信模式：发送者(pub)发送消息，订阅者(sub)接收消息。<br>Redis 客户端可以订阅任意数量的频道。<br>下图展示了频道 channel1 ， 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系：<br><img src="/2019/04/11/Redis高级实用特性/pubsub1.jpg" alt="pubsub1"><br>当有新消息通过 PUBLISH 命令发送给频道 channel1 时， 这个消息就会被发送给订阅它的三个客户端：<br><img src="/2019/04/11/Redis高级实用特性/pubsub2.jpg" alt="pubsub2"></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">我们创建了订阅频道名为 redisChat:</span><br><span class="line">redis 127.0.0.1:6379&gt; SUBSCRIBE redisChat</span><br><span class="line"></span><br><span class="line">Reading messages... (press Ctrl-C to quit)</span><br><span class="line">1) &quot;subscribe&quot;</span><br><span class="line">2) &quot;redisChat&quot;</span><br><span class="line">3) (integer) 1</span><br><span class="line"></span><br><span class="line">现在，我们先重新开启个 redis 客户端，然后在同一个频道 redisChat 发布两次消息，订阅者就能接收到消息。</span><br><span class="line">redis 127.0.0.1:6379&gt; PUBLISH redisChat &quot;Redis is a great caching technique&quot;</span><br><span class="line">(integer) 1</span><br><span class="line"></span><br><span class="line">redis 127.0.0.1:6379&gt; PUBLISH redisChat &quot;Learn redis by runoob.com&quot;</span><br><span class="line">(integer) 1</span><br><span class="line"></span><br><span class="line"># 订阅者的客户端会显示如下消息</span><br><span class="line">1) &quot;message&quot;</span><br><span class="line">2) &quot;redisChat&quot;</span><br><span class="line">3) &quot;Redis is a great caching technique&quot;</span><br><span class="line">1) &quot;message&quot;</span><br><span class="line">2) &quot;redisChat&quot;</span><br><span class="line">3) &quot;Learn redis by runoob.com&quot;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">----------------------------</span><br><span class="line"></span><br><span class="line">序号    命令及描述</span><br><span class="line">1    PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道。</span><br><span class="line">2    PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态。</span><br><span class="line">3    PUBLISH channel message 将信息发送到指定的频道。</span><br><span class="line">4    PUNSUBSCRIBE [pattern [pattern ...]] 退订所有给定模式的频道。</span><br><span class="line">5    SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。</span><br><span class="line">6    UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道。</span><br></pre></td></tr></table></figure><h3 id="Redis配置虚拟内存"><a href="#Redis配置虚拟内存" class="headerlink" title="Redis配置虚拟内存"></a>Redis配置虚拟内存</h3><p>和大多NoSQL数据库一样，Redis同样遵循了Key/Value数据存储模型。在有些情况下，Redis会将Keys/Values保存在内存中以提高数据查询和数据修改的效率，然而这样的做法并非总是很好的选择。鉴于此，我们可以将之进一步优化，即尽量在内存中只保留Keys的数据，这样可以保证数据检索的效率，而Values数据在很少使用的时候则可以被换出到磁盘。</p><p>在实际的应用中，大约只有10%的Keys属于相对比较常用的键，这样Redis就可以通过虚存将其余不常用的Keys和Values换出到磁盘上，而一旦这些被换出的Keys或Values需要被读取时，Redis则将其再次读回到主内存中。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">在redis配置文件中设置</span><br><span class="line">vm-enabled yes            #开启vm功能</span><br><span class="line">vm-swap-file  /tmp/redis.swap    #交换出来的value保存的文件路径</span><br><span class="line">vm-max-memory 1000000    #redis使用的最大内存上限</span><br><span class="line">vm-page-size 32            #每个页面的大小32字节</span><br><span class="line">vm-pages 134217728        #最多使用多少页面</span><br><span class="line">vm-max-threads 4        #用于执行value对象换入患处的工作线程数量</span><br></pre></td></tr></table></figure></p><p>持续中。。。。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;Redis-安全&quot;&gt;&lt;a href=&quot;#Redis-安全&quot; class=&quot;headerlink&quot; title=&quot;Redis 安全&quot;&gt;&lt;/a&gt;Redis 安全&lt;/h3&gt;&lt;p&gt;我们可以通过 redis 的配置文件设置密码参数，这样客户端连接到 redis 服务就需要密码验证，这样可以让你的 redis 服务更安全。&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="数据库" scheme="http://sirxy.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
      <category term="数据库" scheme="http://sirxy.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>Redis数据库之数据类型</title>
    <link href="http://sirxy.github.io/2019/04/11/Redis%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B9%8B%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/"/>
    <id>http://sirxy.github.io/2019/04/11/Redis数据库之数据类型/</id>
    <published>2019-04-11T04:39:12.000Z</published>
    <updated>2019-04-11T05:11:25.586Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Redis的数据类型"><a href="#Redis的数据类型" class="headerlink" title="Redis的数据类型"></a>Redis的数据类型</h3><p>Redis通常被称为数据结构服务器，因为值（value）可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。<a id="more"></a><br>下面介绍redis数据类型：</p><ul><li><p>String（子串类型）</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">set 命令：设置一个键和值，键存在则只覆盖，返回ok</span><br><span class="line">&gt; set 键  值    例如： &gt;set name zhangsan</span><br><span class="line"></span><br><span class="line">get 命令：获取一个键的值，返回值</span><br><span class="line">&gt; get 键        例如：&gt;get name</span><br><span class="line"></span><br><span class="line">setnx命令：设置一个不存在的键和值（防止覆盖），</span><br><span class="line">&gt; setnx 键 值      若键已存在则返回0表示失败</span><br><span class="line"></span><br><span class="line">setex命令：设置一个指定有效期的键和值（单位秒）</span><br><span class="line">&gt; setex 键 [有效时间] 值  例如: &gt;setex color 10 red</span><br><span class="line"> 不写有效时间则表示永久有效，等价于set</span><br><span class="line"></span><br><span class="line">setrange命令：替换子字符串 (替换长度由子子串长度决定)</span><br><span class="line">&gt; setrange 键 位置 子字串</span><br><span class="line">&gt; setrange name 4 aa  将name键对应值的第4个位置开始替换</span><br><span class="line"></span><br><span class="line">mset命令：批量设置键和值,成功则返回ok</span><br><span class="line">&gt; mset 键1 值1 键2 值2 键3 值3 ....</span><br><span class="line"></span><br><span class="line">msetnx命令：批量设置不存在的键和值,成功则返回ok</span><br><span class="line">&gt; msetnx 键1 值1 键2 值2 键3 值3 ....</span><br><span class="line"></span><br><span class="line">getset命令：获取原值，并设置新值</span><br><span class="line"></span><br><span class="line">getrange命令：获取指定范围的值</span><br><span class="line">&gt;getrange 键 0 4     //获取指定0到4位置上的值</span><br><span class="line"></span><br><span class="line">mget命令： 批量获取值</span><br><span class="line">&gt;mget 键1 键2 键3....</span><br><span class="line"></span><br><span class="line">incr命令： 指定键的值做加加操作，返回加后的结果。</span><br><span class="line">&gt;  键        例如： &gt;incr kid</span><br><span class="line">incrby命令： 设置某个键加上指定值</span><br><span class="line">&gt; incrby 键 m    //其中m可以是正整数或负整数</span><br><span class="line"></span><br><span class="line">decr命令： 指定键的值做减减操作，返回减后的结果。</span><br><span class="line">&gt; decr 键        例如： &gt;decr kid</span><br><span class="line">decrby命令： 设置某个键减上指定值</span><br><span class="line">&gt; decrby 键 m    //其中m可以是正整数或负整数</span><br><span class="line"></span><br><span class="line">append命令：给指定key的字符串追加value，返回新字符串值的长度</span><br><span class="line">&gt;append 键 追加字串</span><br><span class="line"></span><br><span class="line">strlen求长度 &gt;strlen 键名   //返回对应的值。</span><br></pre></td></tr></table></figure></li><li><p>Hash类型<br>Redis hash 是一个string类型的field和value的映射表，hash特别适合用于存储对象。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">hset命令：设置一个哈希表的键和值</span><br><span class="line">&gt;hset hash名 键  值</span><br><span class="line">如：&gt;hset user:001 name zhangsan</span><br><span class="line">hget命令： 获取执行哈希名中的键对应值</span><br><span class="line"></span><br><span class="line">hsetnx命令：设置一个哈希表中不存在的键和值</span><br><span class="line">&gt;hsetnx hash名 键  值  //成功返回1，失败返回0</span><br><span class="line">如：&gt;hsetnx user:001 name zhangsan</span><br><span class="line"></span><br><span class="line">hmset命令:hmset user:001 username zhangsan age 20 sex 1 批量设置</span><br><span class="line">hmget user:001 username age sex:批量获取值</span><br><span class="line"></span><br><span class="line">&gt;hexists user:001 name //是否存在， 若存在返回1</span><br><span class="line"></span><br><span class="line">&gt;hlen user:001  //获取某哈希user001名中键的数量</span><br><span class="line"></span><br><span class="line">&gt;hdel user:001 name //删除哈希user:001 中name键</span><br><span class="line"></span><br><span class="line">&gt;hkeys user:002   //返回哈希名为user:002中的所有键。</span><br><span class="line">&gt;hvals user:002   //返回哈希名为user:002中的所有值。</span><br><span class="line">&gt;hgetall user:002 //返回哈希名为user:002中的所有键和值。</span><br></pre></td></tr></table></figure></li><li><p>List列表（双向链表结构）<br>Redis列表是简单的字符串列表，按照插入顺序排序。你可以添加一个元素到列表的头部（左边）或者尾部（右边）</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">list即可以作为“栈”也可以作为&quot;队列&quot;。</span><br><span class="line">操作：</span><br><span class="line">&gt;lpush list1 &quot;world&quot;  //在list1头部压入一个字串</span><br><span class="line">&gt;lpush list1 &quot;hello&quot;  // 在list1头部压入一个字串</span><br><span class="line">&gt;lrange list1 0 -1  //获取list1中内容</span><br><span class="line">    0:表示开头  -1表示结尾。</span><br><span class="line"></span><br><span class="line">&gt;rpush list2 &quot;world&quot;  //在list2尾部压入一个字串</span><br><span class="line">&gt;rpush list2 &quot;hello&quot;  // 在list2尾部压入一个字串</span><br><span class="line">&gt;lrange list2 0 -1  //获取list2中内容</span><br><span class="line">    0:表示开头  -1表示结尾。</span><br><span class="line"></span><br><span class="line">&gt;linsert list2 before hello there</span><br><span class="line">在key对应list的特定位置前或后添加字符串</span><br><span class="line"></span><br><span class="line">&gt;lset list2 1 &quot;four&quot;</span><br><span class="line">修改指定索引位置上的值</span><br><span class="line"></span><br><span class="line">&gt;lrem list2 2 &quot;hello&quot;  //删除前两个hello值</span><br><span class="line">&gt;lrem list2 -2 &quot;hello&quot; //删除后两个hello值</span><br><span class="line">&gt;lrem list2 0 &quot;hello&quot;  //删除所有hello值</span><br><span class="line"></span><br><span class="line">&gt;ltrim mylist8 1 3    //删除此范围外的值</span><br><span class="line"></span><br><span class="line">&gt;lpop list2   //从list2的头部删除元素，并返回删除元素</span><br><span class="line">&gt;rpop list2   //从list2的尾部删除元素，并返回删除元素</span><br><span class="line">&gt;rpoplpush list1 list2    //将list1的尾部一个元素移出到list2头部。并返回</span><br><span class="line"></span><br><span class="line">&gt;lindex list2 1 //返回list2中索引位置上的元素</span><br><span class="line">&gt;llen list2 //返回list2上长度</span><br></pre></td></tr></table></figure></li><li><p>Redis 集合(Set)<br>Redis的Set是string类型的无序集合。集合成员是唯一的，这就意味着集合中不能出现重复的数据。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&gt;sadd myset &quot;hello&quot; //向myset中添加一个元素</span><br><span class="line"> 成功返回1，失败(重复)返回0</span><br><span class="line"></span><br><span class="line">&gt;smembers myset //获取myset中的所有元素(结果是无序的)</span><br><span class="line"></span><br><span class="line">&gt;srem myset &quot;one&quot; //从myset中删除一个one</span><br><span class="line"> 成功返回1，失败(不存在)返回0</span><br><span class="line"></span><br><span class="line">&gt;spop myset //随机返回并删除myset中的一个元素</span><br><span class="line">&gt;srandmember myset //随机获取myset中的一个元素，但是不删除</span><br><span class="line"></span><br><span class="line">&gt; smove myset1 myset2 zhangsan:将myset1中zhangsan移动到myset2中</span><br><span class="line">&gt; scard myset1 返回myset1的个数</span><br><span class="line">&gt; sismember myset zhangsan:判断张三是否在myset中</span><br><span class="line"></span><br><span class="line">&gt;sdiff myset1 myset2 //返回两个集合的差集</span><br><span class="line">以myset1为标准，获取myset2中不存在的。</span><br><span class="line">&gt;sdiffstore dstset myset1 myset2 ...// 返回所有集合的差集，并保存到dstset中</span><br><span class="line"></span><br><span class="line">&gt;sinter myset1 myset2 myset3... // 返回N个集合中的交集</span><br><span class="line">&gt;sinterstore dstset myset1 myset2 ... // 返回N个集合的交集并存储到dstset中</span><br><span class="line"></span><br><span class="line">&gt; sunion myset1 myset2 ...//返回所有集合的并集</span><br><span class="line">&gt; sunionstore dstset myset1 myset2// 返回所有集合的并集，并存储到dstset中</span><br></pre></td></tr></table></figure></li><li><p>Redis 有序集合Sset (sorted set)<br>Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。<br>不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。<br>有序集合的成员是唯一的,但分数(score)却可以重复。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&gt; zadd zset 1 one 向zset中添加one，排序为1排序</span><br><span class="line">&gt; zrem zset one:删除zset中one</span><br><span class="line"></span><br><span class="line">&gt; zincrby zset 2 one:如果one存在，则顺序增加2，如果one不存在，那么就是2</span><br><span class="line"></span><br><span class="line">&gt; zrank zset one:返回one在zset中排名(从小到大的排序)</span><br><span class="line">&gt; zrevrank zset one:返回one在zset中排名(从大到小的排序)</span><br><span class="line"></span><br><span class="line">&gt; zrange zset 0 -1 withscores:根据score排序（根据score从小到大排序）</span><br><span class="line">&gt; zrevrange zset 0 -1 withscores:根据score排序（根据score从大到小排序）</span><br><span class="line"></span><br><span class="line">&gt; zrangebyscore zset 2 3 withscores:返回集合中score在给定区间的元素（包含2和5）</span><br><span class="line">&gt; zcount zset 2 3:返回集合中给定区间的数量</span><br><span class="line">&gt; zcard zset:返回集合中元素的个数</span><br><span class="line">&gt; zscore zset one:返回one元素的score</span><br><span class="line">&gt; zremrangebyrank zset 3 3:删除集合中排名在给定区间的元素</span><br><span class="line">&gt; zremrangebyscore zset 1 2:将zset中从小到大排序结果的score在1-2之间的删除</span><br></pre></td></tr></table></figure></li></ul><p>持续中。。。。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;Redis的数据类型&quot;&gt;&lt;a href=&quot;#Redis的数据类型&quot; class=&quot;headerlink&quot; title=&quot;Redis的数据类型&quot;&gt;&lt;/a&gt;Redis的数据类型&lt;/h3&gt;&lt;p&gt;Redis通常被称为数据结构服务器，因为值（value）可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。&lt;/p&gt;
    
    </summary>
    
      <category term="数据库" scheme="http://sirxy.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
      <category term="数据库" scheme="http://sirxy.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>Redis 数据库</title>
    <link href="http://sirxy.github.io/2019/04/11/Redis/"/>
    <id>http://sirxy.github.io/2019/04/11/Redis/</id>
    <published>2019-04-11T04:16:05.000Z</published>
    <updated>2019-04-11T04:37:38.524Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Redis简介与安装"><a href="#Redis简介与安装" class="headerlink" title="Redis简介与安装"></a>Redis简介与安装</h3><p>1、Redis简介：<br>Redis 一个内存数据库，通过 Key-Value 键值对的的方式存储数据。由于 Redis 的数据都存储在内存中，所以访问速度非常快，因此 Redis <a id="more"></a>大量用于缓存系统，存储热点数据，可以极大的提高网站的响应速度。</p><p>2、优点：<br>支持数据的持久化，通过配置可以将内存中的数据保存在磁盘中，Redis 重启以后再将数据加载到内存中；<br>支持列表，哈希，有序集合等数据结构，极大的扩展了 Redis 用途；<br>原子操作，Redis 的所有操作都是原子性的，这使得基于 Redis 实现分布式锁非常简单；<br>支持发布/订阅功能，数据过期功能；<br>环境准备：<a href="http://www.runoob.com/redis/redis-install.html" target="_blank" rel="noopener">http://www.runoob.com/redis/redis-install.html</a><br>3、Ubuntu下安装<br>在 Ubuntu 系统安装 Redi 可以使用以下命令:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$sudo apt-get update</span><br><span class="line">$sudo apt-get install redis-server</span><br></pre></td></tr></table></figure></p><p>启动 Redis<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ redis-server</span><br></pre></td></tr></table></figure></p><p>查看 redis 是否启动？<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ redis-cli</span><br></pre></td></tr></table></figure></p><p>以上命令将打开以下终端：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">redis 127.0.0.1:6379&gt;</span><br><span class="line">127.0.0.1 是本机 IP ，6379 是 redis 服务端口。现在我们输入 PING 命令。</span><br><span class="line"></span><br><span class="line">redis 127.0.0.1:6379&gt; ping</span><br><span class="line">PONG</span><br></pre></td></tr></table></figure></p><p>以上说明我们已经成功安装了redis。</p><h3 id="Redis基本操作与配置"><a href="#Redis基本操作与配置" class="headerlink" title="Redis基本操作与配置"></a>Redis基本操作与配置</h3><p>1、基本操作<br>Redis 是 Key-Value 内存数据库，操作是通过各种指令进行的，比如 <code>SET</code> 指令可以设置键值对，而 <code>GET</code> 指令则获取某一个键的值。不同的数据结构，Redis 有不同的指令，这样指令一共有几十个，下面主要介绍一些常用的指令。<br>Redis 对 Key 也就是键有各种各样的指令，主要有下面的指令（下面的指令中小写字符串都是参数，可以自定义）：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&gt;keys *  //返回键（key）</span><br><span class="line">&gt;keys list*   //返回名以list开头的所有键（key）</span><br><span class="line">&gt;exists list1  //判断键名为list1的是否存在   存在返回1， 不存在返回0</span><br><span class="line">&gt;del list1 //删除一个键（名为list1）</span><br><span class="line">&gt;expire list1 10 //设置键名为list1的过期时间为10秒后</span><br><span class="line">&gt;ttl list1 //查看键名为list1的过期时间，若为-1表示以过期 或 永不过期</span><br><span class="line">&gt;move age 1 //将键名age的转移到1数据库中。</span><br><span class="line">&gt;select 1 //表示进入到1数据库中，默认在0数据库</span><br><span class="line">&gt;persist age //移除age的过期时间</span><br><span class="line">&gt;flushdb:删除所有的数据 清除当前所在库的所有数据</span><br><span class="line">&gt;flushall 清空所有数据</span><br></pre></td></tr></table></figure></p><p>2、Redis 配置<br>Redis 的配置文件位于 Redis 安装目录下，文件名为 redis.conf。<br>你可以通过CONFIG命令查看或设置配置项。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">redis 127.0.0.1:6379&gt; CONFIG GET CONFIG_SETTING_NAME</span><br><span class="line"></span><br><span class="line">redis 127.0.0.1:6379&gt; CONFIG GET loglevel</span><br><span class="line"></span><br><span class="line">1) &quot;loglevel&quot;</span><br><span class="line">2) &quot;notice&quot;</span><br></pre></td></tr></table></figure></p><p>3、Redis 配置参数说明<br>redis.conf 配置项说明如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line">1. Redis默认不是以守护进程的方式运行，可以通过该配置项修改，使用yes启用守护进程</span><br><span class="line">    daemonize no</span><br><span class="line">2. 当Redis以守护进程方式运行时，Redis默认会把pid写入/var/run/redis.pid文件，可以通过pidfile指定</span><br><span class="line">    pidfile /var/run/redis.pid</span><br><span class="line">3. 指定Redis监听端口，默认端口为6379，作者在自己的一篇博文中解释了为什么选用6379作为默认端口，</span><br><span class="line">    因为6379在手机按键上MERZ对应的号码，而MERZ取自意大利歌女Alessia Merz的名字</span><br><span class="line">    port 6379</span><br><span class="line">4. 绑定的主机地址</span><br><span class="line">    bind 127.0.0.1</span><br><span class="line">5.当 客户端闲置多长时间后关闭连接，如果指定为0，表示关闭该功能</span><br><span class="line">    timeout 300</span><br><span class="line">6. 指定日志记录级别，Redis总共支持四个级别：debug、verbose、notice、warning，默认为verbose</span><br><span class="line">    loglevel verbose</span><br><span class="line">7. 日志记录方式，默认为标准输出，如果配置Redis为守护进程方式运行，而这里又配置为日志记录方式为标准输出，则日志将会发送给/dev/null</span><br><span class="line">    logfile stdout</span><br><span class="line">8. 设置数据库的数量，默认数据库为0，可以使用SELECT &lt;dbid&gt;命令在连接上指定数据库id</span><br><span class="line">    databases 16</span><br><span class="line">9. 指定在多长时间内，有多少次更新操作，就将数据同步到数据文件，可以多个条件配合</span><br><span class="line">    save &lt;seconds&gt; &lt;changes&gt;</span><br><span class="line">    Redis默认配置文件中提供了三个条件：</span><br><span class="line">    save 900 1</span><br><span class="line">    save 300 10</span><br><span class="line">    save 60 10000</span><br><span class="line">    分别表示900秒（15分钟）内有1个更改，300秒（5分钟）内有10个更改以及60秒内有10000个更改。</span><br><span class="line"></span><br><span class="line">10. 指定存储至本地数据库时是否压缩数据，默认为yes，Redis采用LZF压缩，如果为了节省CPU时间，可以关闭该选项，</span><br><span class="line">    但会导致数据库文件变的巨大</span><br><span class="line">    rdbcompression yes</span><br><span class="line">11. 指定本地数据库文件名，默认值为dump.rdb</span><br><span class="line">    dbfilename dump.rdb</span><br><span class="line">12. 指定本地数据库存放目录</span><br><span class="line">    dir ./</span><br><span class="line">13. 设置当本机为slav服务时，设置master服务的IP地址及端口，在Redis启动时，它会自动从master进行数据同步</span><br><span class="line">    slaveof &lt;masterip&gt; &lt;masterport&gt;</span><br><span class="line">14. 当master服务设置了密码保护时，slav服务连接master的密码</span><br><span class="line">    masterauth &lt;master-password&gt;</span><br><span class="line">15. 设置Redis连接密码，如果配置了连接密码，客户端在连接Redis时需要通过AUTH &lt;password&gt;命令提供密码，默认关闭</span><br><span class="line">    requirepass foobared</span><br><span class="line">16. 设置同一时间最大客户端连接数，默认无限制，Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数，</span><br><span class="line">    如果设置 maxclients 0，表示不作限制。当客户端连接数到达限制时，</span><br><span class="line">    Redis会关闭新的连接并向客户端返回max number of clients reached错误信息</span><br><span class="line">    maxclients 128</span><br><span class="line">17. 指定Redis最大内存限制，Redis在启动时会把数据加载到内存中，达到最大内存后，Redis会先尝试清除已到期或即将到期的Key，</span><br><span class="line">    当此方法处理 后，仍然到达最大内存设置，将无法再进行写入操作，但仍然可以进行读取操作。</span><br><span class="line">    Redis新的vm机制，会把Key存放内存，Value会存放在swap区</span><br><span class="line">    maxmemory &lt;bytes&gt;</span><br><span class="line">18. 指定是否在每次更新操作后进行日志记录，Redis在默认情况下是异步的把数据写入磁盘，如果不开启，</span><br><span class="line">    可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的，</span><br><span class="line">    所以有的数据会在一段时间内只存在于内存中。默认为no</span><br><span class="line">    appendonly no</span><br><span class="line">19. 指定更新日志文件名，默认为appendonly.aof</span><br><span class="line">     appendfilename appendonly.aof</span><br><span class="line">20. 指定更新日志条件，共有3个可选值： </span><br><span class="line">    no：表示等操作系统进行数据缓存同步到磁盘（快） </span><br><span class="line">    always：表示每次更新操作后手动调用fsync()将数据写到磁盘（慢，安全） </span><br><span class="line">    everysec：表示每秒同步一次（折衷，默认值）</span><br><span class="line">    appendfsync everysec</span><br><span class="line"></span><br><span class="line">21. 指定是否启用虚拟内存机制，默认值为no，简单的介绍一下，VM机制将数据分页存放，由Redis将访问量较少的页即冷数据swap到磁盘上，</span><br><span class="line">    访问多的页面由磁盘自动换出到内存中（在后面的文章我会仔细分析Redis的VM机制）</span><br><span class="line">     vm-enabled no</span><br><span class="line">22. 虚拟内存文件路径，默认值为/tmp/redis.swap，不可多个Redis实例共享</span><br><span class="line">     vm-swap-file /tmp/redis.swap</span><br><span class="line">23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),</span><br><span class="line">    也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0</span><br><span class="line">     vm-max-memory 0</span><br><span class="line">24. Redis swap文件分成了很多的page，一个对象可以保存在多个page上面，但一个page上不能被多个对象共享，</span><br><span class="line">    vm-page-size是要根据存储的 数据大小来设定的，作者建议如果存储很多小对象，page大小最好设置为32或者64bytes；</span><br><span class="line">    如果存储很大大对象，则可以使用更大的page，如果不 确定，就使用默认值</span><br><span class="line">     vm-page-size 32</span><br><span class="line">25. 设置swap文件中的page数量，由于页表（一种表示页面空闲或使用的bitmap）是在放在内存中的，，在磁盘上每8个pages将消耗1byte的内存。</span><br><span class="line">     vm-pages 134217728</span><br><span class="line">26. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的，可能会造成比较长时间的延迟。</span><br><span class="line">    默认值为4</span><br><span class="line">     vm-max-threads 4</span><br><span class="line">27. 设置在向客户端应答时，是否把较小的包合并为一个包发送，默认为开启</span><br><span class="line">    glueoutputbuf yes</span><br><span class="line">28. 指定在超过一定的数量或者最大的元素超过某一临界值时，采用一种特殊的哈希算法</span><br><span class="line">    hash-max-zipmap-entries 64</span><br><span class="line">    hash-max-zipmap-value 512</span><br><span class="line">29. 指定是否激活重置哈希，默认为开启（后面在介绍Redis的哈希算法时具体介绍）</span><br><span class="line">    activerehashing yes</span><br><span class="line">30. 指定包含其它的配置文件，可以在同一主机上多个Redis实例之间使用同一份配置文件，而同时各个实例又拥有自己的特定配置文件</span><br><span class="line">    include /path/to/local.conf</span><br></pre></td></tr></table></figure></p><p>持续中。。。。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;Redis简介与安装&quot;&gt;&lt;a href=&quot;#Redis简介与安装&quot; class=&quot;headerlink&quot; title=&quot;Redis简介与安装&quot;&gt;&lt;/a&gt;Redis简介与安装&lt;/h3&gt;&lt;p&gt;1、Redis简介：&lt;br&gt;Redis 一个内存数据库，通过 Key-Value 键值对的的方式存储数据。由于 Redis 的数据都存储在内存中，所以访问速度非常快，因此 Redis&lt;/p&gt;
    
    </summary>
    
      <category term="数据库" scheme="http://sirxy.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
      <category term="数据库" scheme="http://sirxy.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>单线程和多线程执行对比</title>
    <link href="http://sirxy.github.io/2019/04/10/Thread-comparison/"/>
    <id>http://sirxy.github.io/2019/04/10/Thread-comparison/</id>
    <published>2019-04-10T10:08:11.000Z</published>
    <updated>2019-04-10T10:37:32.987Z</updated>
    
    <content type="html"><![CDATA[<p>为了将单线程和多线程执行进行对比，下面的脚本比较了递归求斐波那契、阶乘以及累加函数的操作。该脚本按照单线程的方式运行这三个函数，接着使用多线程的方式执行同样的三个函数，以此来说明多线程环境的优点。<a id="more"></a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">from myThread import MyThread</span><br><span class="line">from time import ctime, sleep</span><br><span class="line"></span><br><span class="line">def fib(x):</span><br><span class="line">sleep(0.005)</span><br><span class="line">if x &lt; 2:</span><br><span class="line">return 1</span><br><span class="line">return (fib(x - 2) + fib(x - 1))</span><br><span class="line"></span><br><span class="line">def fac(x):</span><br><span class="line">sleep(0.1)</span><br><span class="line">if x &lt; 2:</span><br><span class="line">return 1</span><br><span class="line">return (x * fac(x - 1))</span><br><span class="line"></span><br><span class="line">def sum(x):</span><br><span class="line">sleep(0.1)</span><br><span class="line">if x &lt; 2:</span><br><span class="line">return 1</span><br><span class="line">return (x + sum(x - 1))</span><br><span class="line"></span><br><span class="line">funcs = [fib, fac, sum]</span><br><span class="line">n = 12</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line">nfuncs = range(len(funcs))</span><br><span class="line"></span><br><span class="line">print(&apos;***single thread&apos;)</span><br><span class="line">for i in nfuncs:</span><br><span class="line">print(&apos;starting&apos;, funcs[i].__name__, &apos;at:&apos;, ctime())</span><br><span class="line">print(funcs[i](n)) # 调用函数</span><br><span class="line">print(funcs[i].__name__, &apos;finished at:&apos;, ctime())</span><br><span class="line"></span><br><span class="line">print(&apos;***multiple threads&apos;)</span><br><span class="line">threads = []</span><br><span class="line">for i in nfuncs:</span><br><span class="line">t = MyThread(funcs[i], (n, ), funcs[i].__name__)</span><br><span class="line">threads.append(t)</span><br><span class="line"></span><br><span class="line">for i in nfuncs:</span><br><span class="line">threads[i].start()</span><br><span class="line"></span><br><span class="line">for i in nfuncs:</span><br><span class="line">threads[i].join()</span><br><span class="line">print(threads[i].getResult())</span><br><span class="line"></span><br><span class="line">print(&apos;all Done&apos;)</span><br><span class="line"></span><br><span class="line">if __name__ == &apos;__main__&apos;:</span><br><span class="line">main()</span><br></pre></td></tr></table></figure></p><p>运行上述代码，结果如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">***single thread</span><br><span class="line">starting fib at: Wed Apr 10 18:23:13 2019</span><br><span class="line">233</span><br><span class="line">fib finished at: Wed Apr 10 18:23:15 2019</span><br><span class="line">starting fac at: Wed Apr 10 18:23:15 2019</span><br><span class="line">479001600</span><br><span class="line">fac finished at: Wed Apr 10 18:23:16 2019</span><br><span class="line">starting sum at: Wed Apr 10 18:23:16 2019</span><br><span class="line">78</span><br><span class="line">sum finished at: Wed Apr 10 18:23:18 2019</span><br><span class="line">***multiple threads</span><br><span class="line">starting fib at: Wed Apr 10 18:23:18 2019</span><br><span class="line">starting fac at: Wed Apr 10 18:23:18 2019</span><br><span class="line">starting sum at: Wed Apr 10 18:23:18 2019</span><br><span class="line">fac finished at: Wed Apr 10 18:23:19 2019</span><br><span class="line">sum finished at: Wed Apr 10 18:23:19 2019</span><br><span class="line">fib finished at: Wed Apr 10 18:23:20 2019</span><br><span class="line">233</span><br><span class="line">479001600</span><br><span class="line">78</span><br><span class="line">all Done</span><br></pre></td></tr></table></figure></p><p>通过上面可以看出，以单线程模式运行只是简单地调用每个函数，并在函数执行结束后立即显示相应的结果。<br>而以多线程模式运行时，并不会立即显示结果。因为希望让MyThread类越通用越好（即有输出和没有输出的调用都能够执行），我们要一直等到所有线程都执行结束，然后调用getResult()方法来最终显示每个函数的返回值。<br>因为这些函数执行起来都非常快（斐波那契除外），所以你看到每个函数中都加入了sleep()用于减慢执行速度，以便让我们看到多线程是如何改善性能的。</p><p>待续中。。。。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;为了将单线程和多线程执行进行对比，下面的脚本比较了递归求斐波那契、阶乘以及累加函数的操作。该脚本按照单线程的方式运行这三个函数，接着使用多线程的方式执行同样的三个函数，以此来说明多线程环境的优点。&lt;/p&gt;
    
    </summary>
    
      <category term="多线程编程" scheme="http://sirxy.github.io/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="Python线程与进程" scheme="http://sirxy.github.io/tags/Python%E7%BA%BF%E7%A8%8B%E4%B8%8E%E8%BF%9B%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>多线程编程——threading模块</title>
    <link href="http://sirxy.github.io/2019/04/09/threading%E6%A8%A1%E5%9D%97/"/>
    <id>http://sirxy.github.io/2019/04/09/threading模块/</id>
    <published>2019-04-09T08:17:07.000Z</published>
    <updated>2019-04-10T10:36:39.840Z</updated>
    
    <content type="html"><![CDATA[<h3 id="threading模块的Thread类"><a href="#threading模块的Thread类" class="headerlink" title="threading模块的Thread类"></a>threading模块的Thread类</h3><p>threading模块的Thread类是主要的执行对象。它有thread模块中没有的许多函数。使用Thread类可以有很多方法来创建线程。这里介绍其中比较相似的三种方法。<a id="more"></a></p><ul><li>方法一：创建Thread的实例，传给它一个函数。如下啊：<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">import threading</span><br><span class="line">from time import sleep, ctime</span><br><span class="line"></span><br><span class="line">loops = [4, 2]</span><br><span class="line"></span><br><span class="line">def loop(nloop, nsec):</span><br><span class="line">print(&apos;start loop&apos;, nloop, &apos;at:&apos;, ctime())</span><br><span class="line">sleep(nsec)</span><br><span class="line">print(&apos;loop&apos;, nloop, &apos;done at:&apos;, ctime())</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line">print(&apos;starting at:&apos;, ctime())</span><br><span class="line">threads = []</span><br><span class="line">nloops = range(len(loops))</span><br><span class="line"></span><br><span class="line">for i in nloops:</span><br><span class="line">t = threading.Thread(target=loop, args=(i, loops[i]))</span><br><span class="line">threads.append(t)</span><br><span class="line"></span><br><span class="line">for i in nloops: # start threads</span><br><span class="line">threads[i].start()</span><br><span class="line"></span><br><span class="line">for i in nloops: # wait for all threads to finish</span><br><span class="line">threads[i].join()</span><br><span class="line"></span><br><span class="line">print(&apos;all done at:&apos;, ctime())</span><br><span class="line"></span><br><span class="line">if __name__ == &apos;__main__&apos;:</span><br><span class="line">main()</span><br></pre></td></tr></table></figure></li></ul><p>当运行完后，打印结果如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">starting at: Wed Apr 10 16:28:53 2019</span><br><span class="line">start loop 0 at: Wed Apr 10 16:28:53 2019</span><br><span class="line">start loop 1 at: Wed Apr 10 16:28:53 2019</span><br><span class="line">loop 1 done at: Wed Apr 10 16:28:55 2019</span><br><span class="line">loop 0 done at: Wed Apr 10 16:28:57 2019</span><br><span class="line">all done at: Wed Apr 10 16:28:57 2019</span><br><span class="line">[Finished in 4.2s]</span><br></pre></td></tr></table></figure></p><ul><li>方法二：创建Thread的实例，传给它一个可调用的类实例<br>在创建线程时，与传入函数相似的一个方法是传入一个可调用的类的实例，用于线程执行——这种方法更加接近面向对象的多线程编程。这种可调用的类包含一个执行环境，比起一个函数或者从一组函数中选择而言，有更好的灵活性。现在你有了一个类对象，而不仅仅是单个函数或者一个函数列表/元组。<br>在方法一的代码中添加一个新类ThreadFunc，并进行一些其他的轻微改动，得到下面的代码：<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">import threading</span><br><span class="line">from time import sleep, ctime</span><br><span class="line"></span><br><span class="line">loops = [4, 2]</span><br><span class="line"></span><br><span class="line">class ThreadFunc(object):</span><br><span class="line"></span><br><span class="line">def __init__(self, func, args, name=&apos;&apos;):</span><br><span class="line">self.name = name</span><br><span class="line">self.func = func</span><br><span class="line">self.args = args</span><br><span class="line"></span><br><span class="line">def __call__(self):</span><br><span class="line">self.func(*self.args)</span><br><span class="line"></span><br><span class="line">def loop(nloop, nsec):</span><br><span class="line">print(&apos;start loop&apos;, nloop, &apos;at:&apos;, ctime())</span><br><span class="line">sleep(nsec)</span><br><span class="line">print(&apos;loop&apos;, nloop, &apos;done at:&apos;, ctime())</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line">print(&apos;starting at:&apos;, ctime())</span><br><span class="line">threads = []</span><br><span class="line">nloops = range(len(loops))</span><br><span class="line"></span><br><span class="line">for i in nloops: # create all threads</span><br><span class="line">t = threading.Thread(target=ThreadFunc(loop, (i, loops[i]), loop.__name__))</span><br><span class="line">threads.append(t)</span><br><span class="line"></span><br><span class="line">for i in nloops: # start threads</span><br><span class="line">threads[i].start()</span><br><span class="line"></span><br><span class="line">for i in nloops: # wait for all threads to finish</span><br><span class="line">threads[i].join()</span><br><span class="line"></span><br><span class="line">print(&apos;all done at:&apos;, ctime())</span><br><span class="line"></span><br><span class="line">if __name__ == &apos;__main__&apos;:</span><br><span class="line">main()</span><br></pre></td></tr></table></figure></li></ul><p>当运行完后，得到了如下的输出：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">starting at: Wed Apr 10 16:51:55 2019</span><br><span class="line">start loop 0 at: Wed Apr 10 16:51:55 2019</span><br><span class="line">start loop 1 at: Wed Apr 10 16:51:55 2019</span><br><span class="line">loop 1 done at: Wed Apr 10 16:51:57 2019</span><br><span class="line">loop 0 done at: Wed Apr 10 16:51:59 2019</span><br><span class="line">all done at: Wed Apr 10 16:51:59 2019</span><br><span class="line">[Finished in 4.2s]</span><br></pre></td></tr></table></figure></p><ul><li>方法三：派生Thread的子类，并创建子类的实例<br>这种方法要介绍的这个例子要调用Thread()的子类（实际上就是继承Thread类鞭编写我们自己需要的线程类），和上一个创建可调用类的例子有些类似。当创建线程时使用子类要相对更容易阅读。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">import threading</span><br><span class="line">from time import sleep, ctime</span><br><span class="line"></span><br><span class="line">loops = [4, 2]</span><br><span class="line"></span><br><span class="line">class MyThread(threading.Thread): # 继承</span><br><span class="line"></span><br><span class="line">def __init__(self, func, args, name=&apos;&apos;):</span><br><span class="line">threading.Thread.__init__(self) # 必须调用基类的构造函数</span><br><span class="line">self.name = name</span><br><span class="line">self.func = func</span><br><span class="line">self.args = args</span><br><span class="line"></span><br><span class="line">def run(self):</span><br><span class="line">self.func(*self.args)</span><br><span class="line"></span><br><span class="line">def loop(nloop, nsec):</span><br><span class="line">print(&apos;start loop&apos;, nloop, &apos;at:&apos;, ctime())</span><br><span class="line">sleep(nsec)</span><br><span class="line">print(&apos;loop&apos;, nloop, &apos;done at:&apos;, ctime())</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line">print(&apos;starting at:&apos;, ctime())</span><br><span class="line">threads = []</span><br><span class="line">nloops = range(len(loops))</span><br><span class="line"></span><br><span class="line">for i in nloops: # create all threads</span><br><span class="line">t = MyThread(loop, (i, loops[i]), loop.__name__)</span><br><span class="line">threads.append(t)</span><br><span class="line"></span><br><span class="line">for i in nloops: # start threads</span><br><span class="line">threads[i].start()</span><br><span class="line"></span><br><span class="line">for i in nloops: # wait for all threads to finish</span><br><span class="line">threads[i].join()</span><br><span class="line"></span><br><span class="line">print(&apos;all Done at:&apos;, ctime())</span><br><span class="line"></span><br><span class="line">if __name__ == &apos;__main__&apos;:</span><br><span class="line">main()</span><br></pre></td></tr></table></figure><p>当运行完后，得到了如下的输出：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">starting at: Wed Apr 10 17:07:01 2019</span><br><span class="line">start loop 0 at: Wed Apr 10 17:07:01 2019</span><br><span class="line">start loop 1 at: Wed Apr 10 17:07:01 2019</span><br><span class="line">loop 1 done at: Wed Apr 10 17:07:03 2019</span><br><span class="line">loop 0 done at: Wed Apr 10 17:07:05 2019</span><br><span class="line">all Done at: Wed Apr 10 17:07:05 2019</span><br><span class="line">[Finished in 4.2s]</span><br></pre></td></tr></table></figure></p><p>本例中将对Thread子类化，而不是直接对齐实例化。这将使我们在定制线程对象时拥有更多的灵活性，也能够简化线程创建的调用过程。</p><p>现在对MyThread类进行修改，增加一些调试信息的输出，并将其存储为一个名为myThread的独立模块，以便于后面自己用到这个类。myThread.py：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">import threading</span><br><span class="line">from time import sleep, ctime</span><br><span class="line"></span><br><span class="line">class MyThread(threading.Thread):</span><br><span class="line"></span><br><span class="line">def __init__(self, func, args, name=&apos;&apos;):</span><br><span class="line">threading.Thread.__init__(self) # 必须调用基类的构造函数</span><br><span class="line">self.name = name</span><br><span class="line">self.func = func</span><br><span class="line">self.args = args</span><br><span class="line"></span><br><span class="line">def getResult(self):</span><br><span class="line">return self.res</span><br><span class="line"></span><br><span class="line">def run(self):</span><br><span class="line">print(&apos;starting&apos;, self.name, &apos;at:&apos;, ctime())</span><br><span class="line">self.res = self.func(*self.args)</span><br><span class="line">print(self.name, &apos;finished at:&apos;, ctime())</span><br></pre></td></tr></table></figure></p><h3 id="threading模块的其他函数"><a href="#threading模块的其他函数" class="headerlink" title="threading模块的其他函数"></a>threading模块的其他函数</h3><p>除了各种同步和线程对象外，threading模块还提供了一些函数：<br>active_count()：当前活动的Thread对象个数<br>current_thread：返回当前的Thread对象<br>enumerate()：返回当前活动的Thread对象列表<br>settrace(func)：为所有线程设置一个trace函数<br>setprofile(func)：为所有线程设置一个profile函数<br>stack_size(size=0)：返回新创建线程的栈大小；或为后续创建的线程设定栈的大小为size</p><p>待续中。。。。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;threading模块的Thread类&quot;&gt;&lt;a href=&quot;#threading模块的Thread类&quot; class=&quot;headerlink&quot; title=&quot;threading模块的Thread类&quot;&gt;&lt;/a&gt;threading模块的Thread类&lt;/h3&gt;&lt;p&gt;threading模块的Thread类是主要的执行对象。它有thread模块中没有的许多函数。使用Thread类可以有很多方法来创建线程。这里介绍其中比较相似的三种方法。&lt;/p&gt;
    
    </summary>
    
      <category term="多线程编程" scheme="http://sirxy.github.io/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="Python线程与进程" scheme="http://sirxy.github.io/tags/Python%E7%BA%BF%E7%A8%8B%E4%B8%8E%E8%BF%9B%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>Python面向对象——设计模式</title>
    <link href="http://sirxy.github.io/2019/04/08/Python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E2%80%94%E2%80%94%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    <id>http://sirxy.github.io/2019/04/08/Python面向对象——设计模式/</id>
    <published>2019-04-08T10:05:12.000Z</published>
    <updated>2019-04-08T10:39:56.529Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Python设计模式"><a href="#Python设计模式" class="headerlink" title="Python设计模式"></a>Python设计模式</h3><p>一个定义：为了解决面向对象系统中重要和重复的设计封装在一起的一种代码实现框架，可以使得代码更加易于扩展和调用。<a id="more"></a><br>四个基本要素：模式名称、问题、解决方案、效果。<br>六大原则：<br>1、开闭原则：一个软件实体,如类,模块和函数应该对扩展开发,对修改关闭.既软件实体应尽量在不修改原有代码的情况下进行扩展。<br>2、里氏替换原则：所有引用父类的方法必须能透明的使用其子类的对象。<br>3、依赖倒置原则：高层模块不应该依赖底层模块，二者都应该依赖其抽象，抽象不应该依赖于细节，细节应该依赖抽象，换而言之，要针对接口编程而不是针对实现编程。<br>4、接口隔离原则：使用多个专门的接口,而不是使用单一的总接口，即客户端不应该依赖那些并不需要的接口。<br>5、迪米特法则：一个软件实体应该尽可能的少与其他实体相互作用。<br>6、单一直责原则：不要存在多个导致类变更的原因，即一个类只负责一项职责。<br>比较流行的是：GOF23种设计模式。</p><h3 id="设计模式——工厂模式"><a href="#设计模式——工厂模式" class="headerlink" title="设计模式——工厂模式"></a>设计模式——工厂模式</h3><p>工厂模式实现了创建者和调用者的分离，使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">class CarFactory:</span><br><span class="line"></span><br><span class="line">def create_car(self, brand):</span><br><span class="line">if brand == &apos;奔驰&apos;:</span><br><span class="line">return Benz()</span><br><span class="line">elif brand == &apos;宝马&apos;:</span><br><span class="line">return BMW()</span><br><span class="line">elif brand == &apos;比亚迪&apos;:</span><br><span class="line">return BYD()</span><br><span class="line">else:</span><br><span class="line">return &apos;未知品牌，无法创建&apos;</span><br><span class="line"></span><br><span class="line">class Benz():</span><br><span class="line">pass</span><br><span class="line"></span><br><span class="line">class BMW():</span><br><span class="line">pass</span><br><span class="line"></span><br><span class="line">class BYD():</span><br><span class="line">pass</span><br><span class="line"></span><br><span class="line">factory = CarFactory()</span><br><span class="line">c1 = factory.create_car(&apos;奔驰&apos;)</span><br><span class="line">c2 = factory.create_car(&apos;宝马&apos;)</span><br><span class="line">c3 = factory.create_car(&apos;比亚迪&apos;)</span><br><span class="line">print(c1)</span><br><span class="line">print(c2)</span><br><span class="line">print(c3)</span><br></pre></td></tr></table></figure></p><p>打印结果如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;__main__.Benz object at 0x0261EBD0&gt;</span><br><span class="line">&lt;__main__.BMW object at 0x0261E9F0&gt;</span><br><span class="line">&lt;__main__.BYD object at 0x0261ECB0&gt;</span><br></pre></td></tr></table></figure></p><h3 id="设计模式——单例模式"><a href="#设计模式——单例模式" class="headerlink" title="设计模式——单例模式"></a>设计模式——单例模式</h3><p>单例模式（Singleton Pattern）的核心作用是确保一个类只有一个实例，并且提供一个访问该实例的全局访问点。<br>单例模式只生成一个实例对象，减少了对系统资源的开销。当一个对象的产生需要比较多的资源，<br>如读取配置文件、产生其他依赖对象时，可以产生一个“单例对象”，然后永久驻留在内存中，从而极大的降低开销。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">class MySingleton:</span><br><span class="line">__obj = None # 类属性</span><br><span class="line">__init_flag = True</span><br><span class="line"></span><br><span class="line">def __new__(cls, *args, **kwargs):</span><br><span class="line">if cls.__obj == None:</span><br><span class="line">cls.__obj = object.__new__(cls)</span><br><span class="line">return cls.__obj</span><br><span class="line"></span><br><span class="line">def __init__(self, name):</span><br><span class="line">if MySingleton.__init_flag:</span><br><span class="line"></span><br><span class="line">print(&quot;init.......&quot;)</span><br><span class="line">self.name = name</span><br><span class="line">MySingleton.__init_flag = False</span><br><span class="line"></span><br><span class="line">a = MySingleton(&apos;aa&apos;)</span><br><span class="line">b = MySingleton(&apos;bb&apos;)</span><br><span class="line">print(a)</span><br><span class="line">print(b)</span><br></pre></td></tr></table></figure></p><p>打印结果如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">init.......</span><br><span class="line">&lt;__main__.MySingleton object at 0x0305E250&gt;</span><br><span class="line">&lt;__main__.MySingleton object at 0x0305E250&gt;</span><br></pre></td></tr></table></figure></p><h3 id="工厂模式和单例模式的整合应用"><a href="#工厂模式和单例模式的整合应用" class="headerlink" title="工厂模式和单例模式的整合应用"></a>工厂模式和单例模式的整合应用</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">class CarFactory:</span><br><span class="line"></span><br><span class="line">__obj = None # 类属性</span><br><span class="line">__init_flag = True</span><br><span class="line"></span><br><span class="line">def create_car(self, brand):</span><br><span class="line">if brand == &apos;奔驰&apos;:</span><br><span class="line">return Benz()</span><br><span class="line">elif brand == &apos;宝马&apos;:</span><br><span class="line">return BMW()</span><br><span class="line">elif brand == &apos;比亚迪&apos;:</span><br><span class="line">return BYD()</span><br><span class="line">else:</span><br><span class="line">return &apos;未知品牌，无法创建&apos;</span><br><span class="line"></span><br><span class="line">def __new__(cls, *args, **kwargs):</span><br><span class="line">if cls.__obj == None:</span><br><span class="line">cls.__obj = object.__new__(cls)</span><br><span class="line">return cls.__obj</span><br><span class="line"></span><br><span class="line">def __init__(self):</span><br><span class="line">if CarFactory.__init_flag:</span><br><span class="line">print(&quot;init CarFactory.......&quot;)</span><br><span class="line">CarFactory.__init_flag = False</span><br><span class="line"></span><br><span class="line">class Benz():</span><br><span class="line">pass</span><br><span class="line">class BMW():</span><br><span class="line">pass</span><br><span class="line">class BYD():</span><br><span class="line">pass</span><br><span class="line"></span><br><span class="line">factory = CarFactory()</span><br><span class="line">c1 = factory.create_car(&apos;奔驰&apos;)</span><br><span class="line">c2 = factory.create_car(&apos;宝马&apos;)</span><br><span class="line">c3 = factory.create_car(&apos;比亚迪&apos;)</span><br><span class="line">print(c1, c2, c3)</span><br><span class="line"></span><br><span class="line">factory2 = CarFactory()</span><br><span class="line">print(factory)</span><br><span class="line">print(factory2)</span><br></pre></td></tr></table></figure><p>打印结果如下啊：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">init CarFactory.......</span><br><span class="line">&lt;__main__.Benz object at 0x02E2ECF0&gt; &lt;__main__.BMW object at 0x02E2EC30&gt; &lt;__main__.BYD object at 0x02E2ED10&gt;</span><br><span class="line">&lt;__main__.CarFactory object at 0x02CBA450&gt;</span><br><span class="line">&lt;__main__.CarFactory object at 0x02CBA450&gt;</span><br></pre></td></tr></table></figure></p><blockquote><p>参考有：<a href="https://www.cnblogs.com/luhuajun/p/7442815.html" target="_blank" rel="noopener">Python设计模式</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;Python设计模式&quot;&gt;&lt;a href=&quot;#Python设计模式&quot; class=&quot;headerlink&quot; title=&quot;Python设计模式&quot;&gt;&lt;/a&gt;Python设计模式&lt;/h3&gt;&lt;p&gt;一个定义：为了解决面向对象系统中重要和重复的设计封装在一起的一种代码实现框架，可以使得代码更加易于扩展和调用。&lt;/p&gt;
    
    </summary>
    
      <category term="Python面向对象" scheme="http://sirxy.github.io/categories/Python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/"/>
    
    
      <category term="Python面向对象" scheme="http://sirxy.github.io/tags/Python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/"/>
    
  </entry>
  
  <entry>
    <title>Python网络爬虫之——认识urllib库</title>
    <link href="http://sirxy.github.io/2019/04/07/Python%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB%E4%B9%8B%E2%80%94%E2%80%94%E8%AE%A4%E8%AF%86urllib%E5%BA%93/"/>
    <id>http://sirxy.github.io/2019/04/07/Python网络爬虫之——认识urllib库/</id>
    <published>2019-04-07T04:22:58.000Z</published>
    <updated>2019-04-07T06:34:12.657Z</updated>
    
    <content type="html"><![CDATA[<p>不说废话，耿直，直接上案例。<br><a id="more"></a></p><h3 id="案例1：百度首页爬取"><a href="#案例1：百度首页爬取" class="headerlink" title="案例1：百度首页爬取"></a>案例1：百度首页爬取</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">#  导包</span><br><span class="line">from urllib import request</span><br><span class="line"># 确定爬取资源</span><br><span class="line">base_url = &apos;http://www.baidu.com&apos;</span><br><span class="line"># 构建请求 发送请求</span><br><span class="line">response = request.urlopen(base_url)</span><br><span class="line"># 接受响应信息</span><br><span class="line">html = response.read().decode(&apos;utf-8&apos;)</span><br><span class="line">print(html)   # 返回的是html源代码  </span><br><span class="line"># 信息存储</span><br><span class="line">with open(&apos;./baidu.html&apos;,&apos;w&apos;,encodeing=&apos;utf-8&apos;) as f:</span><br><span class="line">    f.wirte(html) </span><br><span class="line">```   </span><br><span class="line"></span><br><span class="line">### 案例2：get请求中url带中文字符</span><br><span class="line"></span><br><span class="line">实现百度搜索。url地址会将url中的中文字符进行编码，所以当我们使用urllib发送此类url请求前要讲中文字符进行编码。</span><br></pre></td></tr></table></figure><p>from urllib import request, parse #  1.导包<br>base_url = ‘<a href="http://www.baidu.com/s?&#39;" target="_blank" rel="noopener">http://www.baidu.com/s?&#39;</a> # 2.确定爬取资源<br>inp = input(‘输入搜索内容:’)<br>msg = { # 3.构造请求参数<br>    ‘wd’: inp<br>}<br>encodemsg = parse.urlencode(msg)<br>newurl = base_url+encodemsg # 将编码后的参数进行拼接<br>response = request.urlopen(newurl) #4. 构建请求 发送请求<br>html = response.read().decode(‘utf-8’) # 5.接受响应信息<br>print(html)   # 返回的是html源代码<br>with open(‘./baidu.html’, ‘w’, encodeing=’utf-8’) as f: # 信息存储<br>    f.wirte(html)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">### 案例3：带user-agent反爬的网站</span><br><span class="line"></span><br><span class="line">带有user-agent反爬的网站在发送请求之前必须要构建自己的请求头。</span><br></pre></td></tr></table></figure></p><p>from urllib import request # 1.导包<br>base_url = ‘<a href="http://www.xicidaili.com&#39;" target="_blank" rel="noopener">http://www.xicidaili.com&#39;</a> # 2.确定爬取资源<br>headers = { # 3.构造请求头与请求<br>    ‘User-Agent’: ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36’<br>}<br>req = request.Request(url=base_url, headers=headers)<br>html = request.urlopen(req) # 4.发送请求<br>with open(‘./xici.html’,’w’,encodeing=’utf-8’) as f: # 5.接受并存储信息<br>    f.write(html)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">### 案例4：以上都是get请求 接下来做百度翻译(post请求)</span><br><span class="line"></span><br><span class="line">先通过抓包工具F12 newwork分析，找到翻译时发送的请求，因为是异步请求又是post请求，所以还要找到传递的参数。直接上代码：</span><br></pre></td></tr></table></figure></p><p>from urllib import request,parse<br>import ssl,json<br>ssl._create_default_https_context = ssl._create_unverified_context</p><h1 id="确定爬取地址"><a href="#确定爬取地址" class="headerlink" title="确定爬取地址"></a>确定爬取地址</h1><p>base_url = ‘<a href="https://fanyi.baidu.com/sug&#39;" target="_blank" rel="noopener">https://fanyi.baidu.com/sug&#39;</a><br>def fanyi(msg):<br>    dataform = { # 构造数据<br>        ‘kw’: msg<br>    }<br>    newdataform = parse.urlencode(dataform)<br>    response =  request.urlopen(url=base_url, data=bytes(newdataform, encoding=’utf-8’)) # 发送请求<br>    res = response.read().decode(‘utf-8’) # 接受返回的数据<br>    newres = json.loads(res)</p><pre><code># print(json.loads(res), type(json.loads(res)))str = &apos;&apos;for item in newres[&apos;data&apos;]:    str += item[&apos;v&apos;] + &apos;\n&apos;print(str)</code></pre><h1 id="print-json-dumps-newres-indent-4-ensure-ascii-False-将字典类型转换成字符串"><a href="#print-json-dumps-newres-indent-4-ensure-ascii-False-将字典类型转换成字符串" class="headerlink" title="print(json.dumps(newres, indent=4, ensure_ascii=False)) # 将字典类型转换成字符串"></a>print(json.dumps(newres, indent=4, ensure_ascii=False)) # 将字典类型转换成字符串</h1><p>if <strong>name</strong> == “<strong>main</strong>“:<br>    while True:<br>        msg = input(‘请输入要翻译的单词：’)<br>        if msg == ‘q’:  # 按q退出<br>            break<br>        fanyi(msg)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">注意：如果发送请求时出现如下错误：</span><br></pre></td></tr></table></figure></p><p>urllib.error.URLError: <urlopen error="" [ssl:="" certificate_verify_failed]="" certificate="" verify="" failed="" (_ssl.c:777)=""><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这是因为ssl 验证的错误，可以将下面代码粘贴，解决不进行验证：</span><br></pre></td></tr></table></figure></urlopen></p><p>ssl._create_default_https_context = ssl._create_unverified_context<br><code>`</code></p><p>练习：爬取百度贴吧，根据用户输入的贴吧名称，页码范围来爬取指定贴吧指定页数范围。<br>爬取豆瓣电影的数据，这个是豆瓣电影的api:<a href="https://movie.douban.com/typerank?type_name=%E5%89%A7%E6%83%85&amp;type=11&amp;interval_id=100:90&amp;action=" target="_blank" rel="noopener">https://movie.douban.com/typerank?type_name=%E5%89%A7%E6%83%85&amp;type=11&amp;interval_id=100:90&amp;action=</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;不说废话，耿直，直接上案例。&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="爬虫" scheme="http://sirxy.github.io/categories/%E7%88%AC%E8%99%AB/"/>
    
    
      <category term="Python爬虫" scheme="http://sirxy.github.io/tags/Python%E7%88%AC%E8%99%AB/"/>
    
  </entry>
  
  <entry>
    <title>网络通信之——socket套接字</title>
    <link href="http://sirxy.github.io/2019/04/07/%E7%BD%91%E7%BB%9C%E9%80%9A%E4%BF%A1%E4%B9%8B%E2%80%94%E2%80%94socket%E5%A5%97%E6%8E%A5%E5%AD%97/"/>
    <id>http://sirxy.github.io/2019/04/07/网络通信之——socket套接字/</id>
    <published>2019-04-07T04:00:22.000Z</published>
    <updated>2019-04-07T04:40:42.833Z</updated>
    
    <content type="html"><![CDATA[<h3 id="什么是Socket"><a href="#什么是Socket" class="headerlink" title="什么是Socket"></a>什么是Socket</h3><p>socket(简称 套接字)是一个网络通信的端点，它能实现不同主机间的进程通信，我们网络上各种各样大多数都是基于Socket来完成的通讯。<br><a id="more"></a></p><h3 id="网络中进程之间如何通讯呢？"><a href="#网络中进程之间如何通讯呢？" class="headerlink" title="网络中进程之间如何通讯呢？"></a>网络中进程之间如何通讯呢？</h3><p>首要解决的问题是如何确定你要和对方电脑上哪个进程进行通讯，这主要是<br>利用协议，IP地址，端口标识网络的进程，然后通过这些标识进行通讯。</p><h4 id="socket——UDP网络通讯"><a href="#socket——UDP网络通讯" class="headerlink" title="socket——UDP网络通讯"></a>socket——UDP网络通讯</h4><p>使用socket创建UDP通讯的过程很简单，如下图：<br><img src="/2019/04/07/网络通信之——socket套接字/socket-udp.png" alt="socket——UDP网络通讯示意图"><br>根据上图我们可以总结创建服务端和客户端的步骤，使用代码分别实现服务端和客户端：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">服务端：</span><br><span class="line">1.创建套接字对象</span><br><span class="line">2.绑定ip地址和端口号</span><br><span class="line">3.接受消息</span><br><span class="line">4.返回消息</span><br><span class="line">5.关闭套接字</span><br><span class="line"></span><br><span class="line">import socket</span><br><span class="line"># 创建套接字</span><br><span class="line">udp_s = socket.socked(socket.AF_INET,socket.SOCK_DGRAM)</span><br><span class="line"># 绑定ip地址</span><br><span class="line">udp_s.bind((&apos;&apos;,8080))</span><br><span class="line"># 接受消息</span><br><span class="line">data,addr = udp_s.recvfrom(1024)</span><br><span class="line">print(data)</span><br><span class="line"></span><br><span class="line"># 关闭套接字</span><br><span class="line">udp_s.close()</span><br></pre></td></tr></table></figure></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">客户端：</span><br><span class="line">1.创建套接字对象</span><br><span class="line">2.发送消息</span><br><span class="line">3.关闭套接字对象</span><br><span class="line"></span><br><span class="line">import socekd</span><br><span class="line"># 创建套接字对象</span><br><span class="line">udp_c = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)</span><br><span class="line"># 发送消息</span><br><span class="line">udp_c.sendto(&apos;hello&apos;.encode(&apos;utf-8&apos;),(&apos;192.168.1.15&apos;,8080))</span><br><span class="line"># 关闭套接字</span><br><span class="line">udp_c.close()</span><br></pre></td></tr></table></figure><h4 id="Socket–TCP网络通讯"><a href="#Socket–TCP网络通讯" class="headerlink" title="Socket–TCP网络通讯"></a>Socket–TCP网络通讯</h4><p>TCP通讯过程如下图：<br><img src="/2019/04/07/网络通信之——socket套接字/socket-tcp.png" alt="socket——TCP网络通信示意图"><br>从图上可以看出，创建服务端通信需要经过：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">1.创建套接字对象</span><br><span class="line">2.绑定ip地址和端口号</span><br><span class="line">3.监听</span><br><span class="line">4.接受消息</span><br><span class="line">5.返回消息</span><br><span class="line">6.关闭套接字</span><br><span class="line"></span><br><span class="line">import socket</span><br><span class="line">tcp_s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)</span><br><span class="line">tcp_s.bind((&apos;&apos;,8080))</span><br><span class="line">tcp_s.listen()</span><br><span class="line">s,addr = tcp_s.accept()</span><br><span class="line">data = s.recv(1024)</span><br><span class="line">print(data.decode(&apos;utf-8&apos;))</span><br><span class="line">s.send(&apos;hello&apos;.encode(&apos;utf-8))</span><br><span class="line">s.close()</span><br><span class="line">tcp_s.close()</span><br><span class="line">``` </span><br><span class="line">创建客户端通信需要经过：</span><br><span class="line">```    </span><br><span class="line">1.创建套接字对象</span><br><span class="line">2.创建连接</span><br><span class="line">3.发送消息</span><br><span class="line">4.关闭套接字对象</span><br><span class="line"></span><br><span class="line">import socket</span><br><span class="line">tcp_c = socket.socket(socket.AF_INET,socket.SOCK_STRAM)</span><br><span class="line">tcp_c.connect((&apos;192.168.1.15&apos;,8080))</span><br><span class="line">tcp_c.send(&apos;hello&apos;.encode(&apos;utf-8&apos;))</span><br><span class="line">tcp_c.close()</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;什么是Socket&quot;&gt;&lt;a href=&quot;#什么是Socket&quot; class=&quot;headerlink&quot; title=&quot;什么是Socket&quot;&gt;&lt;/a&gt;什么是Socket&lt;/h3&gt;&lt;p&gt;socket(简称 套接字)是一个网络通信的端点，它能实现不同主机间的进程通信，我们网络上各种各样大多数都是基于Socket来完成的通讯。&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="网络通信" scheme="http://sirxy.github.io/categories/%E7%BD%91%E7%BB%9C%E9%80%9A%E4%BF%A1/"/>
    
    
      <category term="网络通信学习" scheme="http://sirxy.github.io/tags/%E7%BD%91%E7%BB%9C%E9%80%9A%E4%BF%A1%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>网络协议之——UDP和TCP</title>
    <link href="http://sirxy.github.io/2019/04/07/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E4%B9%8B%E2%80%94%E2%80%94UDP%E5%92%8CTCP/"/>
    <id>http://sirxy.github.io/2019/04/07/网络协议之——UDP和TCP/</id>
    <published>2019-04-07T03:49:03.000Z</published>
    <updated>2019-04-07T04:03:31.334Z</updated>
    
    <content type="html"><![CDATA[<h3 id="UDP协议和TCP协议"><a href="#UDP协议和TCP协议" class="headerlink" title="UDP协议和TCP协议"></a>UDP协议和TCP协议</h3><h4 id="UDP协议"><a href="#UDP协议" class="headerlink" title="UDP协议"></a>UDP协议</h4><p>UDP：用户数据报协议，不可靠性，只是把应用程序传给IP层数据报送出去，但是不能保证他们是否能到达目的地<a id="more"></a>，传输数据报前不用再客户端和服务器之间建立连接，并且没有超时重发机制，所以传输速度快。<br>特点：安全性差，传输速度快，无序，大小有限制64kb。</p><h3 id="TCP协议"><a href="#TCP协议" class="headerlink" title="TCP协议"></a>TCP协议</h3><p>我们知道，在通讯之前，一定要先建立相关链接，才能发送数据。</p><p>下面是tcp建立连接 三次握手的概述：<br><img src="/2019/04/07/网络协议之——UDP和TCP/threehand.png" alt="tcp三次握手，建立连接"><br>其中：ACK：确认标志，SYN：同步标志<br>第一次握手：主机A发送位码为syn＝1,随机产生seq number=1234567的数据包到服务器，主机B由SYN=1知道，A要求建立联机；<br>第二次握手：主机B收到请求后要确认联机信息，向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包<br>第三次握手：主机A收到后检查ack number是否正确，即第一次发送的seq number+1,以及位码ack是否为1，若正确，主机A会再发送ack number=(主机B的seq+1),ack=1，主机B收到后确认seq值与ack=1则连接建立成功。<br>完成三次握手，主机A与主机B开始传送数据。<br>特点：安全性高，稳定性好，有序；速度相对较慢。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;UDP协议和TCP协议&quot;&gt;&lt;a href=&quot;#UDP协议和TCP协议&quot; class=&quot;headerlink&quot; title=&quot;UDP协议和TCP协议&quot;&gt;&lt;/a&gt;UDP协议和TCP协议&lt;/h3&gt;&lt;h4 id=&quot;UDP协议&quot;&gt;&lt;a href=&quot;#UDP协议&quot; class=&quot;headerlink&quot; title=&quot;UDP协议&quot;&gt;&lt;/a&gt;UDP协议&lt;/h4&gt;&lt;p&gt;UDP：用户数据报协议，不可靠性，只是把应用程序传给IP层数据报送出去，但是不能保证他们是否能到达目的地&lt;/p&gt;
    
    </summary>
    
      <category term="网络协议" scheme="http://sirxy.github.io/categories/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/"/>
    
    
      <category term="网络协议学习" scheme="http://sirxy.github.io/tags/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>git常用命令</title>
    <link href="http://sirxy.github.io/2019/04/06/git01/"/>
    <id>http://sirxy.github.io/2019/04/06/git01/</id>
    <published>2019-04-06T04:35:25.000Z</published>
    <updated>2019-04-06T12:24:12.570Z</updated>
    
    <content type="html"><![CDATA[<h3 id="一张git版本控制常用命令图送给你"><a href="#一张git版本控制常用命令图送给你" class="headerlink" title="一张git版本控制常用命令图送给你"></a>一张git版本控制常用命令图送给你</h3><p>Git 是一个开源的分布式版本控制系统，用于敏捷高效地处理任何或小或大的项目。<br>Git 是 Linus Torvalds 为了<a id="more"></a>帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。<br>Git 与常用的版本控制工具 CVS, Subversion 等不同，它采用了分布式版本库的方式，不必服务器端软件支持。<br>下面是一张关于git版本控制的常用命令表：<br><img src="/2019/04/06/git01/b00-git-cheat-sheet-zh-cn.jpg" alt="版本控制git常用命令"></p><blockquote><p>参考自：<a href="http://www.runoob.com/git/git-tutorial.html" target="_blank" rel="noopener">Git教程|菜鸟教程</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;一张git版本控制常用命令图送给你&quot;&gt;&lt;a href=&quot;#一张git版本控制常用命令图送给你&quot; class=&quot;headerlink&quot; title=&quot;一张git版本控制常用命令图送给你&quot;&gt;&lt;/a&gt;一张git版本控制常用命令图送给你&lt;/h3&gt;&lt;p&gt;Git 是一个开源的分布式版本控制系统，用于敏捷高效地处理任何或小或大的项目。&lt;br&gt;Git 是 Linus Torvalds 为了&lt;/p&gt;
    
    </summary>
    
      <category term="版本控制" scheme="http://sirxy.github.io/categories/%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6/"/>
    
    
      <category term="git版本控制" scheme="http://sirxy.github.io/tags/git%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6/"/>
    
  </entry>
  
  <entry>
    <title>Python面向对象——super()</title>
    <link href="http://sirxy.github.io/2019/04/05/Python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E2%80%94%E2%80%94super/"/>
    <id>http://sirxy.github.io/2019/04/05/Python面向对象——super/</id>
    <published>2019-04-05T02:25:02.000Z</published>
    <updated>2019-04-05T05:59:01.051Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Python-OOP中关于super-的描述"><a href="#Python-OOP中关于super-的描述" class="headerlink" title="Python OOP中关于super()的描述"></a>Python OOP中关于super()的描述</h3><p>在Python OOP实际应用中，有一个函数super()，通过这个函数可以允许继承父类的子类访问该父类中的方法。super()会在该子类当中单独返回一个父类的临时对象，然后允许你在该子类中调用该父类所拥有的方法。<a id="more"></a>通常使用super()这个函数调用父类当中所构建的方法，这可以使你无需在子类中重写这些方法，并允许你使用最少的代码更改来替换父类。在对Python super()有了一个大致的认识后，下面说一说Python中关于各种继承（单继承、多继承）对super()的简单应用等。</p><h3 id="Python单继承之super"><a href="#Python单继承之super" class="headerlink" title="Python单继承之super()"></a>Python单继承之super()</h3><p>首先来定义两个类：Rectangle、Square，通过这两个类来说明继承关系。定义类如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">class Rectangle():</span><br><span class="line">&apos;&apos;&apos;矩形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, width, height):</span><br><span class="line">self.width = width</span><br><span class="line">self.length = length</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.width</span><br><span class="line"></span><br><span class="line">def perimeter(self):</span><br><span class="line">&apos;&apos;&apos;计算周长&apos;&apos;&apos;</span><br><span class="line">return (self.width + self.length) &lt;&lt; 1</span><br><span class="line"></span><br><span class="line">class Square():</span><br><span class="line">&apos;&apos;&apos;正方形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length):</span><br><span class="line">self.length = length</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.length</span><br><span class="line"></span><br><span class="line">def perimeter(self):</span><br><span class="line">&apos;&apos;&apos;计算周长&apos;&apos;&apos;</span><br><span class="line">return self.length &lt;&lt; 2</span><br><span class="line"></span><br><span class="line">square = Square(4) # 实例化正方形类</span><br><span class="line">print(square.area())</span><br><span class="line">rectangle = Rectangle(2, 4) # 实例化矩形类</span><br><span class="line">print(rectangle.area())</span><br></pre></td></tr></table></figure></p><p>通过此示例发现，这两个类是两个相互有关联的形状类：正方形是一种特殊的矩形， 但以上的代码似乎并没有展示出这种关系，因此这两个类具有重复的代码。找出了相关性，我们就可以通过这种相关性类实现继承的关系，通过继承减少代码的量的编写：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">class Rectangle():</span><br><span class="line">&apos;&apos;&apos;矩形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, width, length):</span><br><span class="line">self.width = width</span><br><span class="line">self.length = length</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.width</span><br><span class="line"></span><br><span class="line">def perimeter(self):</span><br><span class="line">&apos;&apos;&apos;计算周长&apos;&apos;&apos;</span><br><span class="line">return (self.width + self.length) &lt;&lt; 1</span><br><span class="line"></span><br><span class="line">class Square(Rectangle):</span><br><span class="line">&apos;&apos;&apos;正方形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length):</span><br><span class="line">super().__init__(length, length)</span><br><span class="line"></span><br><span class="line">square = Square(4) # 实例化正方形类</span><br><span class="line">print(square.area())</span><br><span class="line">rectangle = Rectangle(2, 4) # 实例化矩形类</span><br><span class="line">print(rectangle.area())</span><br></pre></td></tr></table></figure></p><p>在这里，我们使用了super()来调用Rectangle类的<strong>init </strong>()，允许我们在Square类中使用它而不重复代码。 如下所示，核心功能在进行更改后仍然存在。<br>因为Square和Rectangle .<strong> init </strong>()方法非常相似，所以你可以使用super()从Square的方法中调用超类的.<strong> init </strong>()方法（Rectangle .<strong> init </strong>()）。 这里设置了.length和.width属性，即使您只需要为Square构造函数提供单个长度参数。<br>当你运行它时，即使你的Square类没有显式地实现它，对.area()的调用将使用超类中的.area()方法并打印16. Square类从Rectangle继承.area() 方法。</p><h3 id="super-在单继承中能为你做什么呢？"><a href="#super-在单继承中能为你做什么呢？" class="headerlink" title="super()在单继承中能为你做什么呢？"></a>super()在单继承中能为你做什么呢？</h3><p>与其他面向对象语言一样，它允许您在子类中调用父类的方法。这种情况的主要用例是扩展继承方法的功能。<br>在下面的示例中，您将创建一个继承自Square的类Cube，并扩展.area()的功能（通过Square继承自Rectangle类）以计算Cube实例的表面积和体积：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">class Rectangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;矩形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, width, length):</span><br><span class="line">self.width = width</span><br><span class="line">self.length = length</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.width</span><br><span class="line"></span><br><span class="line">def perimeter(self):</span><br><span class="line">&apos;&apos;&apos;计算周长&apos;&apos;&apos;</span><br><span class="line">return (self.width + self.length) &lt;&lt; 1</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class Square(Rectangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;正方形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length):</span><br><span class="line">super().__init__(length, length)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class Cube(Square):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;立方体类&apos;&apos;&apos;</span><br><span class="line">def surface_area(self):</span><br><span class="line">&apos;&apos;&apos;计算表面积&apos;&apos;&apos;</span><br><span class="line">face_area = super().area()</span><br><span class="line">return face_area * 6</span><br><span class="line"></span><br><span class="line">def volume(self):</span><br><span class="line">face_area = super().area()</span><br><span class="line">return face_area * self.length</span><br></pre></td></tr></table></figure></p><p>这时，让我们看一下边长为3的立方体的表面积和体积：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cube = Cube(3)</span><br><span class="line">print(cube.surface_area()) # 54</span><br><span class="line">print(cube.volume()) # 27</span><br></pre></td></tr></table></figure></p><p>从上面可以看出，我们为Cube立方体类实现了两个方法：.surface_area()和.volume()。这两个计算都依赖于计算单个面的面积，因此您不必重新实现面积计算，而是使用super()来扩展面积计算。<br>另外请注意，Cube类定义没有.<strong> init </strong>()。因为Cube继承自Square，而.<strong> init </strong>()并没有为Cube做任何不同的事情，所以你可以跳过定义它，并且将自动调用超类（Square）的.<strong> init </strong>()。<br>super()将委托对象返回给父类，因此您可以直接调用它所需的方法：super().area()。这不仅使我们不必重写面积计算方法，而且还允许我们在一个位置更改内部.area()逻辑。当你有一些继承自一个父类的子类时，这尤其有用。<br>介绍了上面这些示例，下面我们探索一下super()它的机制。</p><h3 id="super-机制"><a href="#super-机制" class="headerlink" title="super()机制"></a>super()机制</h3><p>我们发现，上面一系列的示例是在没有任何参数的情况下调用super()的，然而super()也可以使用两个参数：第一个是子类，第二个参数是作为该子类实例的对象。<br>首先，让我们看两个示例，通过使用已有的类来展示操作第一个变量可以做什么：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">class Rectangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;矩形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, width, length):</span><br><span class="line">self.width = width</span><br><span class="line">self.length = length</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.width</span><br><span class="line"></span><br><span class="line">def perimeter(self):</span><br><span class="line">&apos;&apos;&apos;计算周长&apos;&apos;&apos;</span><br><span class="line">return (self.width + self.length) &lt;&lt; 1</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class Square(Rectangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;正方形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length):</span><br><span class="line">super(Square, self).__init__(length, length)</span><br></pre></td></tr></table></figure></p><p>在Python 3当中，super(Square，self)调用等同于无参数的super()调用。 第一个参数指的是子类Square，而第二个参数指的是Square对象，在这种情况下，它是self。 我们也可以使用其他类调用super()：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">class Cube(Square):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;立方体类&apos;&apos;&apos;</span><br><span class="line">def surface_area(self):</span><br><span class="line">&apos;&apos;&apos;计算表面积&apos;&apos;&apos;</span><br><span class="line">face_area = super(Square, self).area()</span><br><span class="line">return face_area * 6</span><br><span class="line"></span><br><span class="line">def volume(self):</span><br><span class="line">face_area = super(Square, self).area()</span><br><span class="line">return face_area * self.length</span><br></pre></td></tr></table></figure></p><p>在此示例中，您将Square设置为super()的子类参数，而不是Cube。 这导致super()开始在实例层次结构中的Square上方的一个级别搜索匹配方法（在本例中为.area()方法），在本例中为Rectangle类。在此特定示例中，行为不会更改。 但想象一下Square还实现了一个你想要确保Cube不使用的.area()方法。 以这种方式调用super()可以让你这样做。<br>第二个参数怎么样？请记住，这是一个对象，它是用作第一个参数的类的实例。例如，isinstance(Cube，Square)必须返回True。<br>通过包含实例化对象，super()返回一个绑定方法：绑定到对象的方法，用来为方法提供对象的上下文，例如任何实例属性。如果未包含此参数，则返回的方法只是一个函数，与对象的上下文无关。（注意：super()不返回方法。它返回一个代理对象。它将调用正确的类方法，而不需要另外创建一个对象。）</p><h3 id="Python多继承之super"><a href="#Python多继承之super" class="headerlink" title="Python多继承之super()"></a>Python多继承之super()</h3><p>了解了单继承的super()和它的一些示例，下面，我们将开始了解多继承的一些概述和一些示例，这些示例将演示多继承如何工作以及super()如何启用该功能。</p><ul><li>多继承概述<br>Python支持多继承，其中子类可以从多个不必继承的超类（也称为兄弟类）继承。<br>为了更好地说明多继承的实际应用，下面将展示如何通过三角形和正方形构建一个右金字塔（带有方形底座的金字塔）：<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">class Rectangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;矩形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, width, length):</span><br><span class="line">self.width = width</span><br><span class="line">self.length = length</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.width</span><br><span class="line"></span><br><span class="line">def perimeter(self):</span><br><span class="line">&apos;&apos;&apos;计算周长&apos;&apos;&apos;</span><br><span class="line">return (self.width + self.length) &lt;&lt; 1</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class Square(Rectangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;正方形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length):</span><br><span class="line">super().__init__(length, length)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class Triangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;三角形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, base, height):</span><br><span class="line">self.base = base</span><br><span class="line">self.height = height</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">return self.base * self.height * 0.5</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class RightPyramid(Triangle, Square):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;右金字塔类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, base, slant_height):</span><br><span class="line">self.base = base</span><br><span class="line"># 倾斜高度：从物体底部中心（如金字塔）到其面部到该物体顶部的高度</span><br><span class="line">self.slant_height = slant_height </span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">base_area = super().area()</span><br><span class="line">perimeter = super().perimeter()</span><br><span class="line">return perimeter * self.slant_height * 0.5 + base_area</span><br></pre></td></tr></table></figure></li></ul><p>此示例原来的基础上又声明了一个Triangle类和一个继承Square和Triangle的RightPyramid类。<br>您将看到另一个使用super()的.area()方法，就像在单继承中一样，目的是用到在Rectangle类中一直定义的.perimeter()和.area()方法。<br>但问题是两个超类（Triangle和Square）都定义了一个.area()。花一点时间思考在RightPyramid上调用.area()时会发生什么，然后尝试调用它，如下所示：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">pyramid = RightPyramid(2, 4)</span><br><span class="line">print(pyramid.area())</span><br><span class="line"># Traceback (most recent call last):</span><br><span class="line">#   File &quot;C:\Users\lenovo\Desktop\dianping.py&quot;, line 103, in &lt;module&gt;</span><br><span class="line">#     print(pyramid.area())</span><br><span class="line">#   File &quot;C:\Users\lenovo\Desktop\dianping.py&quot;, line 99, in area</span><br><span class="line">#     base_area = super().area()</span><br><span class="line">#   File &quot;C:\Users\lenovo\Desktop\dianping.py&quot;, line 88, in area</span><br><span class="line">#     return self.base * self.height * 0.5</span><br><span class="line"># AttributeError: &apos;RightPyramid&apos; object has no attribute &apos;height&apos;</span><br></pre></td></tr></table></figure></p><p>您是否猜测Python会尝试调用Triangle.area()？ 这是因为所谓的方法解析顺序在起作用。<br>注意：我们怎么注意到Triangle.area()被调用了，而不是像我们希望的那样，Square.area()？ 如果查看回溯的最后一行（在AttributeError之前），您将看到对特定代码行的引用：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">return self.base * self.height * 0.5</span><br></pre></td></tr></table></figure></p><p>您可以将几何类中的这个方法认为是三角形面积公式。 或者，你可能已经找到Triangle和Rectangle类定义，并在Triangle.area()中看到了相同的代码。</p><ul><li>方法解析顺序mro<br>方法解析顺序告诉Python如何搜索继承来的方法，当你使用super()时，这回排上很大的用场，因为mro会告诉Python将使用super()以及以什么样的顺序来进行调用的方法。<br>每个类都会有一个.<strong>mro</strong>的魔术属性，它允许我们检查顺序：<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">print(RightPyramid.__mro__) </span><br><span class="line"># 打印结果：</span><br><span class="line">(&lt;class &apos;__main__.RightPyramid&apos;&gt;, &lt;class &apos;__main__.Triangle&apos;&gt;, &lt;class &apos;__main__.Square&apos;&gt;, &lt;class &apos;__main__.Rectangle&apos;&gt;, &lt;class &apos;object&apos;&gt;)</span><br></pre></td></tr></table></figure></li></ul><p>这告诉我们首先在Rightpyramid中搜索方法，然后在Triangle中搜索，然后在Square中搜索，然后在Rectangle中搜索，然后，如果没有找到，则在对象中搜索。</p><p>这里的问题是解释器在Square和Rectangle之前在Triangle中搜索.area()，并且在Triangle中找到.area()时，Python会调用它而不是你想要的那个。 因为Triangle.area()期望有.height和.base属性，所以Python会抛出AttributeError。</p><p>幸运的是，您可以控制MRO的构建方式。 只需更改RightPyramid类的签名，即可按所需顺序进行搜索，方法将正确解析：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">class RightPyramid(Square, Triangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;右金字塔类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, base, slant_height):</span><br><span class="line">self.base = base</span><br><span class="line">self.slant_height = slant_height</span><br><span class="line">super().__init__(self.base)</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">base_area = super().area()</span><br><span class="line">perimeter = super().perimeter()</span><br><span class="line">return perimeter * self.slant_height * 0.5 + base_area</span><br></pre></td></tr></table></figure></p><p>请注意，RightPyramid使用Square类中的.<strong> init </strong>()进行部分初始化。 这允许.area()在对象上使用.length，如设计的那样。</p><p>现在，您可以构建金字塔类，检查MRO并计算表面积：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">pyramid = RightPyramid(2, 4)</span><br><span class="line">print(pyramid.area()) # 20.0</span><br><span class="line">print(RightPyramid.__mro__) # (&lt;class &apos;__main__.RightPyramid&apos;&gt;, &lt;class &apos;__main__.Square&apos;&gt;, &lt;class &apos;__main__.Rectangle&apos;&gt;, &lt;class &apos;__main__.Triangle&apos;&gt;, &lt;class &apos;object&apos;&gt;)</span><br></pre></td></tr></table></figure></p><p>您可以看到MRO现在是您所期望的，并且您也可以检查金字塔的表面积，这要归功于.area()和.perimeter()。</p><p>不过，这里仍然存在问题。为了简单起见，我在这个例子中故意设置了一些错误：第一个，可以说最重要的是，我有两个具有相同方法名称和签名的独立类。</p><p>这会导致方法解析问题，因为将调用MRO列表中遇到的.area()的第一个实例。</p><p>当您使用具有多重继承的super()时，必须设计您的类以进行协作。其中一点是确保您的方法是唯一的，以便通过签名确保方法是唯一的 - 无论是使用方法名称还是方法参数，在MRO中正确解析它们。</p><p>在这种情况下，为了避免对代码进行彻底检查，可以将Triangle类的.area()方法重命名为.tri_area()。这样，area方法可以继续使用类属性而不是使用外部参数：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">class Triangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;三角形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, base, height):</span><br><span class="line">self.base = base</span><br><span class="line">self.height = height</span><br><span class="line">super().__init__()</span><br><span class="line"></span><br><span class="line">def tri_area(self):</span><br><span class="line">return self.base * self.height * 0.5</span><br></pre></td></tr></table></figure></p><p>让我们继续在RightPyramid类中使用它：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">class RightPyramid(Square, Triangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;右金字塔类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, base, slant_height):</span><br><span class="line">self.base = base</span><br><span class="line">self.slant_height = slant_height</span><br><span class="line">super().__init__(self.base)</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">base_area = super().area()</span><br><span class="line">perimeter = super().perimeter()</span><br><span class="line">return perimeter * self.slant_height * 0.5 + base_area</span><br><span class="line">def area_2(self):</span><br><span class="line">base_area = super().area()</span><br><span class="line">triangle_area = super().tri_area()</span><br><span class="line">return triangle_area * 4 + base_area</span><br></pre></td></tr></table></figure></p><p>这里的下一个问题是代码没有像Square对象那样的委托的Triangle对象，所以调用.area_2()会给我们一个AttributeError，因为.base和.height没有任何值。</p><p>你需要做两件事来解决这个问题：</p><p>1.使用super()调用的所有方法都需要调用其超类的该方法版本。 这意味着您需要将super().<strong> init </strong>()添加到Triangle和Rectangle的.<strong> init </strong>()方法中。</p><p>2.重新设计所有.<strong> init </strong>()调用以获取关键字字典。 请参阅下面的完整代码。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line">class Rectangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;矩形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, width, length, **kwargs):</span><br><span class="line">self.width = width</span><br><span class="line">self.length = length</span><br><span class="line">super().__init__(**kwargs)</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.width</span><br><span class="line"></span><br><span class="line">def perimeter(self):</span><br><span class="line">&apos;&apos;&apos;计算周长&apos;&apos;&apos;</span><br><span class="line">return (self.width + self.length) &lt;&lt; 1</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class Square(Rectangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;正方形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length, **kwargs):</span><br><span class="line">super().__init__(length=length, width=length, **kwargs)</span><br><span class="line"></span><br><span class="line">class Cube(Square):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;立方体类&apos;&apos;&apos;</span><br><span class="line">def surface_area(self):</span><br><span class="line">face_area = super().area()</span><br><span class="line">return face_area * 6</span><br><span class="line"></span><br><span class="line">def volume(self):</span><br><span class="line">face_area = super().area()</span><br><span class="line">return face_area * self.length</span><br><span class="line"></span><br><span class="line">class Triangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;三角形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, base, height, **kwargs):</span><br><span class="line">self.base = base</span><br><span class="line">self.height = height</span><br><span class="line">super().__init__(**kwargs)</span><br><span class="line"></span><br><span class="line">def tri_area(self):</span><br><span class="line">return self.base * self.height * 0.5</span><br><span class="line"></span><br><span class="line">class RightPyramid(Square, Triangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;右金字塔类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, base, slant_height, **kwargs):</span><br><span class="line">self.base = base</span><br><span class="line">self.slant_height = slant_height</span><br><span class="line">kwargs[&quot;height&quot;] = slant_height</span><br><span class="line">kwargs[&quot;length&quot;] = base</span><br><span class="line">super().__init__(base=base, **kwargs)</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">base_area = super().area()</span><br><span class="line">perimeter = super().perimeter()</span><br><span class="line">return perimeter * self.slant_height * 0.5 + base_area</span><br><span class="line"></span><br><span class="line">def area_2(self):</span><br><span class="line">base_area = super().area()</span><br><span class="line">triangle_area = super().tri_area()</span><br><span class="line">return triangle_area * 4 + base_area</span><br></pre></td></tr></table></figure></p><p>此代码中存在许多重要差异：</p><p>1.kwargs在某些地方被修改（例如RightPyramid .<strong> init </strong>()): 这将允许这些对象的用户仅使用对该特定对象有意义的参数来实例化它们。</p><p>2.在<strong>kwargs之前设置命名参数：你可以在RightPyramid .<strong> init </strong>()中看到这个。 这具有从</strong>kwargs字典中去除特定键的简洁效果，因此当它在MRO中最终进行到object时，**kwargs为空。<br>现在，当您使用这些更新的类时，您有：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">pyramid = RightPyramid(base=2, slant_height=4)</span><br><span class="line">print(pyramid.area()) # 20</span><br><span class="line">print(pyramid.area_2()) # 20.0</span><br></pre></td></tr></table></figure></p><p>起作用了！ 您已经使用super()成功追溯复杂的类层次结构，同时使用继承和组合来创建具有最少重新实现的新类。</p><h3 id="多重继承替代方案"><a href="#多重继承替代方案" class="headerlink" title="多重继承替代方案"></a>多重继承替代方案</h3><p>如您所见，多重继承可能很有用，但也会导致非常复杂的情况和难以阅读的代码。 拥有整齐地从多个其他对象继承所有东西的对象也很少见。</p><p>如果您发现自己开始使用多重继承和复杂的类层次结构，那么值得问问自己是否可以通过使用组合而不是继承来实现更清晰，更易于理解的代码。</p><p>通过组合，您可以从一个称为mixin的专用简单类中为您的类添加非常特定的功能。</p><p>由于本文主要关注继承，因此我不会详细介绍组合以及如何在Python中使用它，但这里有一个使用VolumeMixin为我们的3D对象提供特定功能的简短示例 - 在这种情况下，是一个体积计算：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">class Rectangle():</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;矩形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, width, length):</span><br><span class="line">self.width = width</span><br><span class="line">self.length = length</span><br><span class="line"></span><br><span class="line">def area(self):</span><br><span class="line">&apos;&apos;&apos;计算面积&apos;&apos;&apos;</span><br><span class="line">return self.length * self.width</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class Square(Rectangle):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;正方形类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length):</span><br><span class="line">super().__init__(length, length)</span><br><span class="line"></span><br><span class="line">class VolumeMixin():</span><br><span class="line">def volume(self):</span><br><span class="line">return self.area() * self.height</span><br><span class="line"></span><br><span class="line">class Cube(VolumeMixin, Square):</span><br><span class="line"></span><br><span class="line">&apos;&apos;&apos;立方体类&apos;&apos;&apos;</span><br><span class="line">def __init__(self, length):</span><br><span class="line">super().__init__(length)</span><br><span class="line">self.height = length</span><br><span class="line"></span><br><span class="line">def surface_area(self):</span><br><span class="line">face_area = super().area()</span><br><span class="line">return face_area * 6</span><br><span class="line"></span><br><span class="line">def face_area(self):</span><br><span class="line">return super().area()</span><br></pre></td></tr></table></figure></p><p>在这个例子中，代码被重新设计为包含一个名为VolumeMixin的mixin。 然后，Cube使用mixin并使Cube能够计算其体积，如下所示：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cube = Cube(2)</span><br><span class="line">print(cube.surface_area()) # 24</span><br><span class="line">print(cube.volume()) # 8</span><br></pre></td></tr></table></figure></p><p>这个mixin可以在任何需要计算体积的类中以相同的方式使用，并且公式area*height返回正确的结果。</p><p>有关Python中面向对象编程和使用super()的更多信息，请查看以下资源：</p><ul><li>官方的super()文档</li><li>由Raymond Hettinger写的Python的super()真的超赞</li><li>Python中面向对象的编程3</li></ul><blockquote><p>参考自：<a href="https://mp.weixin.qq.com/s?__biz=MjM5NzU0MzU0Nw==&amp;mid=2651382106&amp;idx=1&amp;sn=0ac795103888e188f965ccc4f70f2875&amp;chksm=bd242a4e8a53a3582d999408bc939e9904960b5c7607c7a2b41bdfc72ca086721f9b76efae57&amp;scene=0&amp;xtrack=1#rd" target="_blank" rel="noopener">使用Python Super()为类提供继承支持</a> 译者：javylee<br><a href="https://realpython.com/python-super/" target="_blank" rel="noopener">英文原文</a></p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;Python-OOP中关于super-的描述&quot;&gt;&lt;a href=&quot;#Python-OOP中关于super-的描述&quot; class=&quot;headerlink&quot; title=&quot;Python OOP中关于super()的描述&quot;&gt;&lt;/a&gt;Python OOP中关于super()的描述&lt;/h3&gt;&lt;p&gt;在Python OOP实际应用中，有一个函数super()，通过这个函数可以允许继承父类的子类访问该父类中的方法。super()会在该子类当中单独返回一个父类的临时对象，然后允许你在该子类中调用该父类所拥有的方法。&lt;/p&gt;
    
    </summary>
    
      <category term="Python面向对象" scheme="http://sirxy.github.io/categories/Python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/"/>
    
    
      <category term="Python面向对象" scheme="http://sirxy.github.io/tags/Python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/"/>
    
  </entry>
  
  <entry>
    <title>Python模块——hashlib</title>
    <link href="http://sirxy.github.io/2019/04/04/Python%E6%A8%A1%E5%9D%97%E2%80%94%E2%80%94hashlib/"/>
    <id>http://sirxy.github.io/2019/04/04/Python模块——hashlib/</id>
    <published>2019-04-04T05:37:00.000Z</published>
    <updated>2019-04-04T13:37:12.039Z</updated>
    
    <content type="html"><![CDATA[<p>Python的hashlib提供了常见的摘要算法，如MD5，SHA1，SHA224，SHA256，SHA384，SHA512等等,用于加密数据。<br>什么是摘要算法呢？摘要算法又称哈希算法、散列算法。它通过一个函数，把任意长度的数据转换为一个长度固定的数据串（通常用16进制的字符串表示）。<br><a id="more"></a><br>摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest，目的是为了发现原始数据是否被人篡改过。<br>摘要算法之所以能指出数据是否被篡改过，就是因为摘要函数是一个单向函数，计算f(data)很容易，但通过digest反推data却非常困难。而且，对原始数据做一个bit的修改，都会导致计算出的摘要完全不同。<br>我们以常见的摘要算法MD5为例，计算出一个字符串的MD5值：</p><h3 id="MD5"><a href="#MD5" class="headerlink" title="MD5"></a>MD5</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import hashlib</span><br><span class="line">md5 = hashlib.md5(b&apos;how to use md5 in python hashlib?&apos;)</span><br><span class="line">password_md5 = md5.hexdigest()</span><br><span class="line">print(password_md5) # d26a53750bc40b38b65a520292f69306</span><br></pre></td></tr></table></figure><p>如果数据量很大，可以分块多次调用update()，最后计算的结果是一样的：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import hashlib</span><br><span class="line">md5 = hashlib.md5()</span><br><span class="line">md5.update(b&apos;how to use md5 in &apos;)</span><br><span class="line">md5.update(b&apos;python hashlib?&apos;)</span><br><span class="line">print(md5.hexdigest()) # d26a53750bc40b38b65a520292f69306</span><br></pre></td></tr></table></figure></p><p>MD5是最常见的摘要算法，速度很快，生成结果是固定的128 bit字节，通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1，调用SHA1和调用MD5完全类似：</p><h3 id="SHA1"><a href="#SHA1" class="headerlink" title="SHA1"></a>SHA1</h3><p>SHA1的结果是160 bit字节，通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512，不过越安全的算法越慢，而且摘要长度更长。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import hashlib</span><br><span class="line">sha1 = hashlib.sha1()</span><br><span class="line">sha1.update(b&apos;how to use sha1 in &apos;)</span><br><span class="line">sha1.update(b&apos;python hashlib?&apos;)</span><br><span class="line">print(sha1.hexdigest()) # 2c76b57293ce30acef38d98f6046927161b46a44</span><br></pre></td></tr></table></figure></p><h3 id="摘要算法应用"><a href="#摘要算法应用" class="headerlink" title="摘要算法应用"></a>摘要算法应用</h3><p>任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢？方法是存到数据库表中：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">name    | password</span><br><span class="line">--------+----------</span><br><span class="line">michael | 123456</span><br><span class="line">bob     | abc999</span><br><span class="line">alice   | alice2008</span><br></pre></td></tr></table></figure></p><p>如果以明文保存用户口令，如果数据库泄露，所有用户的口令就落入黑客的手里。此外，网站运维人员是可以访问数据库的，也就是能获取到所有用户的口令。正确的保存口令的方式是不存储用户的明文口令，而是存储用户口令的摘要，比如MD5：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">username | password</span><br><span class="line">---------+---------------------------------</span><br><span class="line">michael  | e10adc3949ba59abbe56e057f20f883e</span><br><span class="line">bob      | 878ef96e86145580c38c87f0410ad153</span><br><span class="line">alice    | 99b1c2188db85afee403b1536010c2c9</span><br></pre></td></tr></table></figure></p><p>考虑这么个情况，很多用户喜欢用123456，888888，password这些简单的口令，于是，黑客可以事先计算出这些常用口令的MD5值，得到一个反推表：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&apos;e10adc3949ba59abbe56e057f20f883e&apos;: &apos;123456&apos;</span><br><span class="line">&apos;21218cca77804d2ba1922c33e0151105&apos;: &apos;888888&apos;</span><br><span class="line">&apos;5f4dcc3b5aa765d61d8327deb882cf99&apos;: &apos;password&apos;</span><br></pre></td></tr></table></figure></p><p>这样，无需破解，只需要对比数据库的MD5，黑客就获得了使用常用口令的用户账号。<br>对于用户来讲，当然不要使用过于简单的口令。但是，我们能否在程序设计上对简单口令加强保护呢？<br>由于常用口令的MD5值很容易被计算出来，所以，要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5，这一方法通过对原始口令加一个复杂字符串来实现，俗称“加盐”：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hashlib.md5(&quot;salt&quot;.encode(&quot;utf8&quot;))</span><br></pre></td></tr></table></figure></p><p>经过Salt处理的MD5口令，只要Salt不被黑客知道，即使用户输入简单口令，也很难通过MD5反推明文口令。<br>但是如果有两个用户都使用了相同的简单口令比如123456，在数据库中，将存储两条相同的MD5值，这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢？<br>如果假定用户无法修改登录名，就可以通过把登录名作为Salt的一部分来计算MD5，从而实现相同口令的用户也存储不同的MD5。<br>摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法，不能用于加密（因为无法通过摘要反推明文），只能用于防篡改，但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Python的hashlib提供了常见的摘要算法，如MD5，SHA1，SHA224，SHA256，SHA384，SHA512等等,用于加密数据。&lt;br&gt;什么是摘要算法呢？摘要算法又称哈希算法、散列算法。它通过一个函数，把任意长度的数据转换为一个长度固定的数据串（通常用16进制的字符串表示）。&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="Python" scheme="http://sirxy.github.io/categories/Python/"/>
    
      <category term="内置模块" scheme="http://sirxy.github.io/categories/Python/%E5%86%85%E7%BD%AE%E6%A8%A1%E5%9D%97/"/>
    
    
      <category term="Python模块" scheme="http://sirxy.github.io/tags/Python%E6%A8%A1%E5%9D%97/"/>
    
  </entry>
  
  <entry>
    <title>Python模块——sys</title>
    <link href="http://sirxy.github.io/2019/04/04/Python%E6%A8%A1%E5%9D%97%E2%80%94%E2%80%94sys/"/>
    <id>http://sirxy.github.io/2019/04/04/Python模块——sys/</id>
    <published>2019-04-04T05:31:07.000Z</published>
    <updated>2019-04-05T04:55:11.221Z</updated>
    
    <content type="html"><![CDATA[<h3 id="sys模块"><a href="#sys模块" class="headerlink" title="sys模块"></a>sys模块</h3><p>sys模块是与python解释器交互的一个接口。下面是常用的的一些接口解释：<br><a id="more"></a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">sys.argv           命令行参数List，第一个元素是程序本身路径</span><br><span class="line">sys.exit(n)        退出程序，正常退出时exit(0),错误退出sys.exit(1)</span><br><span class="line">sys.version        获取Python解释程序的版本信息</span><br><span class="line">sys.path           返回模块的搜索路径，初始化时使用PYTHONPATH环境变量的值</span><br><span class="line">sys.platform       返回操作系统平台名称</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;sys模块&quot;&gt;&lt;a href=&quot;#sys模块&quot; class=&quot;headerlink&quot; title=&quot;sys模块&quot;&gt;&lt;/a&gt;sys模块&lt;/h3&gt;&lt;p&gt;sys模块是与python解释器交互的一个接口。下面是常用的的一些接口解释：&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="Python" scheme="http://sirxy.github.io/categories/Python/"/>
    
      <category term="内置模块" scheme="http://sirxy.github.io/categories/Python/%E5%86%85%E7%BD%AE%E6%A8%A1%E5%9D%97/"/>
    
    
      <category term="Python模块" scheme="http://sirxy.github.io/tags/Python%E6%A8%A1%E5%9D%97/"/>
    
  </entry>
  
  <entry>
    <title>网站流量术语</title>
    <link href="http://sirxy.github.io/2019/04/04/HTTP%E5%AD%A6%E4%B9%A003/"/>
    <id>http://sirxy.github.io/2019/04/04/HTTP学习03/</id>
    <published>2019-04-04T01:46:13.000Z</published>
    <updated>2019-04-04T13:35:09.331Z</updated>
    
    <content type="html"><![CDATA[<p>网站统计一般以数值较大的IP,PV统计，比较好看。</p><h3 id="IP"><a href="#IP" class="headerlink" title="IP"></a>IP</h3><p>IP即Internet Protocol，这里是指独立ip数，不同的ip地址的计算机访问网站时被计算的总次数。<br>独立ip数是网站流量的一个重要指标。<br>一般相同ip地址的客户端访问网站页面一天内只会被计算一次。<a id="more"></a><br>这里的ip指的是是固定的公网ip。</p><h3 id="PV"><a href="#PV" class="headerlink" title="PV"></a>PV</h3><p>pv（Page View）即是页面浏览量，不管客户端是不是相同，也不管ip是否相同，用户只要访问网站页面就会被计算PV，一次计算一个PV。<br>pv的度量方法就是客户端从浏览器发出一个web请求（request），服务器接收请求返回一个页面给客户端，这样就产生一个pv。<br>页面刷新一下，就是一个PV。</p><h3 id="UV"><a href="#UV" class="headerlink" title="UV"></a>UV</h3><p>UV即unique visitor，同一个客户端（pc或移动端）访问网站被计算为一个访客。<br>一天内相同的客户端访问同一个网站只计一次uv，uv是以cookie等技术为统计依据，实际统计存在误差。<br>一台计算机可能有多人使用，因此uv也不是最准确的。</p><h3 id="并发数"><a href="#并发数" class="headerlink" title="并发数"></a>并发数</h3><p>并发数指系统同时能处理的请求数量，也反应了系统的负载能力。</p><h3 id="响应时间"><a href="#响应时间" class="headerlink" title="响应时间"></a>响应时间</h3><p>响应时间是指执行一个请求从开始到最后收到响应数据所花费的总体时间。</p><h3 id="QPS"><a href="#QPS" class="headerlink" title="QPS"></a>QPS</h3><p>Query Per Second：每秒查询数<br>服务器在一秒内处理了多少个请求，显然数字越大代表服务器的负载越高，处理能力越强。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Http相关术语pv、ip、uv 假设公司有一座大厦，大厦有100人，每个人有一台电脑和一部手机，上网都是通过nat转换出口，每个人点击网站2次（发2次请求）, 请问对应的pv,uv,ip分别是多少？</span><br><span class="line"></span><br><span class="line">PV：页面浏览量, 400 100人 2个设备 访问2次 =400数</span><br><span class="line">uv：独立的客户, 200 100人2个设备=200数</span><br><span class="line">ip：独立IP, 1个 同一个NAT出口，独立IP为1</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;网站统计一般以数值较大的IP,PV统计，比较好看。&lt;/p&gt;
&lt;h3 id=&quot;IP&quot;&gt;&lt;a href=&quot;#IP&quot; class=&quot;headerlink&quot; title=&quot;IP&quot;&gt;&lt;/a&gt;IP&lt;/h3&gt;&lt;p&gt;IP即Internet Protocol，这里是指独立ip数，不同的ip地址的计算机访问网站时被计算的总次数。&lt;br&gt;独立ip数是网站流量的一个重要指标。&lt;br&gt;一般相同ip地址的客户端访问网站页面一天内只会被计算一次。&lt;/p&gt;
    
    </summary>
    
      <category term="HTTP" scheme="http://sirxy.github.io/categories/HTTP/"/>
    
    
      <category term="HTTP学习" scheme="http://sirxy.github.io/tags/HTTP%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>HTTP报文、URI</title>
    <link href="http://sirxy.github.io/2019/04/03/HTTP%E5%AD%A6%E4%B9%A002/"/>
    <id>http://sirxy.github.io/2019/04/03/HTTP学习02/</id>
    <published>2019-04-03T13:50:12.000Z</published>
    <updated>2019-04-04T13:35:17.928Z</updated>
    
    <content type="html"><![CDATA[<p>什么是http报文？它是HTTP应用程序之间发送的数据块。这些数据块以一些文本形式的元信息开头，这些信息描述了报文的内容及含义，后面跟着可选的数据部分。这些报文都是在客户端、服务器和代理之间流动。<a id="more"></a></p><h3 id="HTTP请求报文"><a href="#HTTP请求报文" class="headerlink" title="HTTP请求报文"></a>HTTP请求报文</h3><p>由请求行，请求头部，空行，请求报文主体几个部分组成，即：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">起始行： &lt;method&gt; &lt;request-URL&gt; &lt;version&gt;</span><br><span class="line"></span><br><span class="line">头部：   &lt;headers&gt;</span><br><span class="line"></span><br><span class="line">主体：   &lt;entity-body&gt;</span><br></pre></td></tr></table></figure></p><h3 id="HTTP响应报文"><a href="#HTTP响应报文" class="headerlink" title="HTTP响应报文"></a>HTTP响应报文</h3><p>HTTP 响应与 HTTP 请求相似，HTTP响应也由3个部分构成，分别是：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">状态行</span><br><span class="line">响应头(Response Header)</span><br><span class="line">响应正文</span><br></pre></td></tr></table></figure></p><h3 id="URI"><a href="#URI" class="headerlink" title="URI"></a>URI</h3><p>uri中文叫“统一资源标识符”，是一个用于标识某一互联网资源名称的字符串，在世界范围内标识定位某一个唯一信息资源。<br>还有一个概念叫做URL，那什么是URL？URL简称统一资源定位符。那URL的组成部分是由协议, 域名:端口, 路径和文件名。<br>url主要用在各种www客户端和服务器程序上，url可以用一种统一的格式来描述各种信息资源，包括文件，服务器地址和目录等。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;什么是http报文？它是HTTP应用程序之间发送的数据块。这些数据块以一些文本形式的元信息开头，这些信息描述了报文的内容及含义，后面跟着可选的数据部分。这些报文都是在客户端、服务器和代理之间流动。&lt;/p&gt;
    
    </summary>
    
      <category term="HTTP" scheme="http://sirxy.github.io/categories/HTTP/"/>
    
    
      <category term="HTTP学习" scheme="http://sirxy.github.io/tags/HTTP%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
</feed>
