Resilio Sync(原 btsync)使用体验

最近在安装 Resilio Sync 的时候发现,竟然被屏蔽了,官网被屏蔽了竟然连 key 都下载不了,可以使用之前写过的 proxychains 代理 来使用代理下载这个 key。

更新

惊闻 btsync 已经改名字,现在叫 Resilio Sync ,官网地址也改为: https://www.resilio.com/

可以从 这里 获取不同平台客户端。

Linux 安装 Package 可以参考 https://help.getsync.com/hc/en-us/articles/206178924 这里

创建文件 /etc/apt/sources.list.d/resilio-sync.list, 添加如下内容:

deb http://linux-packages.resilio.com/resilio-sync/deb resilio-sync non-free

添加公钥:

wget -qO - https://linux-packages.resilio.com/resilio-sync/key.asc | sudo apt-key add -

安装:

sudo apt-get update
sudo apt-get install resilio-sync

配置文件存储地址 https://help.getsync.com/hc/en-us/articles/206664690

Linux 下配置文件地址:/var/lib/resilio-sync

啊,安装好了之后,添加这个 key,当个示例啦 BB63I5PBPBFDELAPXI6NTF47IPNZQAAJZ ,一周一本好书。

如果想要手动开启或者关闭 Resilio Sync 可以使用如下命令:

sudo service resilio-sync stop
sudo service resilio-sync start

原文

全称 BitTorrent Sync , 我习惯了叫他 btsync 了。想要了解他的前世今生直接去看维基百科 就好了。一句话概括,他就是一个同步工具,类 Dropbox,但是利用 P2P 等等 bt 种子的技术。当然私人使用当成网盘工具也好,当成分享工具也好,看个人使用了。不过黑客提醒,虽然是去中心化的,但是安全性依然存在问题,最好不要传输私人信息。

官网地址: https://www.getsync.com/

全平台

现在使用任何一个工具或者服务,我首要考虑的问题离不开跨平台了,最好是 Windows , Linux, Mac 下全部都有,不然在平台间来回切换不同的服务和工具时间成本,学习成本太高了。也正是因为这个原因我放弃了 Google Drive 而转用 Dropbox,作为主力同步工具。当然 btsync 在全平台都有客户端,甚至连一些 NAS,路由器设备都有。

安装

安装非常简单,去官网下载,下一步下一步,OK。当然 Linux 下,如果不想使用 下一步下一步安装法,也可以使用命令从 PPA 里拖。

PPA

sudo add-apt-repository ppa:tuxpoldo/btsync
sudo apt-get update

For normal desktop use, you only need to install btsync-user:

sudo apt-get install btsync-user

Alternatively, if you’re setting up your BTSync server, install btsync:

sudo apt-get install btsync

btsync client

在官网根据自己的机器选择合适的 client 下载并解压。并运行:

./btsync

即可。

默认的 Web GUI 地址是 : http://127.0.0.1:8888

更加详细的安装指南可以参考这篇

VPS 上架设

类似 Linux 下安装,官网下载并解压 btsync 文件。

tar -zxvf BitTorrent-Sync_x64.tar.gz

然后执行:

./btsync --dump-sample-config > btsync.conf

创建配置文件,然后修改 btsync.conf 配置文件中的:

"listen" : "0.0.0.0:8888"

还有 loginpassword , 端口默认是 8888,可修改成其他没有冲突的。loginpassword 是登陆用户名和密码。其他配置看注释修改即可。参考官网 config 文章.

然后保存配置文件,启动:

./btsync --config btsync.conf

在浏览器中就能够在 http://ip:port/ 访问 Web GUI。

然后在本地获取同步 key ,和 VPS 上同步即可。

技巧

移动同步后的文件夹

如果你已经同步了一个文件夹,比如在 ~/books,现在想要将该同步的目录移动到 ~/btsync/books 目录下。 就像 Dropbox 同步已经存在的文件夹 一样,如果单纯的再重新下载一边太麻烦了。所以幸好 btsync 和 dropbox 都有这样的性质,同步的内容都有文件记录,将文件重新加入索引,等索引完之后就可以继续和其他的文件同步了。

  1. 拷贝该文件夹的”共享秘钥”
  2. 从 btsync 中移除该文件夹
  3. 在本地硬盘移动文件夹到新的位置
  4. 重新在 btsync 用之前的”共享秘钥“,添加该文件夹

VPS 上启用 https

默认 btsync 的 web gui 是没有启用加密的,如果想要使用 https://ip:port/gui 来访问,则需要使用 config 配置,并在 config 配置中设置 force_https, ssl_certificate,ssl_private_key ,然后重启 btsync 。

如果觉得这样让 btsync 直接获取证书不安全,这里 还有另外一种配置,利用 nginx 的代理。

分享密钥的网站

推荐几个常用 KEY

  • 神 key BCWHZRSLANR64CGPTXRE54ENNSIUE5SMO
  • 最新电影 BA6RXJ7YOAOOFV42V6HD56XH4QVIBL2P6
  • 经济学人 BYRRPM52YK6Z6TETDQITFXBV647XLCNIO
  • Kindle 中文伴侣精品 BOC3NIGPF2DOKETOF2FAHXJXE2HF24QWC
  • 每周更新图书 BB63I5PBPBFDELAPXI6NTF47IPNZQAAJZ

Andy 电子书

Andy 整理的电子书,大概 100G 左右 B2YZTLQJYCRWAM4LJLWBZWH7EEYU25J3T

57G     ./Andy 收集
3.4M    ./_gsdata_
23G     ./kindlefere
5.2G    ./kindleren 精品资源(一)
3.2G    ./kindleren 精品资源(二)
11G     ./mebook
21G     ./suguniang01
5.5G    ./suguniang02
6.2G    ./ 其他 sync 资源
848M    ./ 子乌书简
13G     ./ 整理 3200
144G    .

reference


2016-04-18 btsync , 产品体验

小行星视图App review

最近迷上了360度全景,搞了得图800,和理光 theta m15的全景相机玩。然后就对周边的全景处理App都体验了一下。最早接触到 Sphere Photo 也要归功于 Google 的原生 Camera, 然而因为不知道的原因,在 Android kitkat 之后的版本中这个小行星视图就消失不见了。而我还是依然很怀念这样的视图。下面就是一些 Play Store 中存在的制作小行星视图的App。

Android Apps

Tiny Planet FX Pro

完整却不够完美 市场上唯一一款收费的小行星app,但是给我的感觉却是做的不够精致和完美,今天竟然处理出不完整的人脸。处理图像甚至比不上另一款免费的app。

Little Planet

除了开始的广告一切还好 开始的广告可能是让很多人打低分的原因,但是这款app,确实达到了我的需求,并且实现的很好。开发者可以尝试提供pro版本来去除广告或者内购去广告。

Tiny Planet - Globe Photo

广告多功能简单 太多影响操作的广告,横幅广告侵占了操作预览区域。功能比不上其他app。

Spherify

功能简单广告影响使用 功能几乎没有,处理时间太长。广告占据太多篇幅。

最后推荐 Little Planet , 虽然在App开始出现了全屏广告,但是效果及功能和收费的 Tiny Planet FX Pro 相差不大。

temple

android

cosoc

How to make sphere photo using photoshop

大多数时候我没有时间用 Google Camera 照完整个全景,这个时候如果可以后期合成当然是最好的,于是就有了这样一篇文章 ,只要有一张全景照片,利用 Photoshop 同样可以实现 Sphere Photo。 同样也可以参考这篇文章

最后推荐一个社区 https://plus.google.com/u/0/communities/115970110085205516914 ,社群的简介里面有很多教程,并且分享的 Post,质量都很高。


2016-04-16 Android , SpherePhoto , Android app

Python 标准库网关接口 wsgiref

The Web Server Gateway Interface(WSGI) 是网络服务器软件和网络应用程序之前的标准接口。通过共同的网关标准接口可以让同一个应用支持不同的服务器。只有网络服务器或者编程框架的作者需要熟悉 WSGI 设计,如果使用现存的框架则不太需要关心更底层的网关接口。

wsgiref 是 Python 的 WSGI 标准实现,可以用来帮助实现网络服务器和应用框架。他提供了一系列工具用来操作 WSGI 环境变量和响应头,也提供了基础的类来实现 WSGI 服务器,提供了简单的 HTTP 服务来给 WSGI 应用提供服务器,提供了一个符合 WSGI 标准(PEP 3333) 的验证工具来验证 WSGI 服务器和应用。

文档

几个部分

wsgiref.util

wsgiref.util 这个模块提供了一系列工具用来操作 WSGI environments。

wsgiref.headers

该模块提供了一个简单的类 Headers 用来操纵 WSGI 相应头。

wsgiref.simple_server

该模块基于 http.server 实现了一个简单的 HTTP 服务器,这个服务器能够给 WSGI 应用提供服务。每一个服务器实例在特定的 host 和 port 上提供一个 WSGI 应用服务。如果要在听一个 host 和 port 上给不同应用程序提供服务,那么你需要创建一个 WSGI 应用,并且传入 PATH_INFO 来选择哪一个应用程序来来被每一次请求调用。

wsgiref.validate

验证模块。

wsgiref.handlers

该模块提供了实现 WSGI 服务器和网关的基础类。这些基础类能够处理和 WSGI 应用的大部分通信。

Example

简单的例子

from wsgiref.simple_server import make_server

# Every WSGI application must have an application object - a callable
# object that accepts two arguments. For that purpose, we're going to
# use a function (note that you're not limited to a function, you can
# use a class for example). The first argument passed to the function
# is a dictionary containing CGI-style environment variables and the
# second variable is the callable object (see PEP 333).
def hello_world_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    headers = [('Content-type', 'text/plain; charset=utf-8')]  # HTTP Headers
    start_response(status, headers)

    # The returned object is going to be printed
    return [b"Hello World"]

httpd = make_server('', 8000, hello_world_app)
print("Serving on port 8000...")

# Serve until process is killed
httpd.serve_forever()

reference


2016-04-06 wsgi , python , wsgiref

MyBatis 自动生成的 Java client 方法区别

MyBatis 自动生成的 Java client generator 会产生如下的方法;

  • countByExample
  • deleteByPrimaryKey
  • deleteByExample
  • insert
  • insertSelective
  • selectByPrimaryKey
  • selectByExample
  • selectByExampleWithBLOBs
  • updateByPrimaryKey (with an override to specify whether or not to update BLOB columns)
  • updateByPrimaryKeySelective (will only update non-null fields in the parameter class)
  • updateByExample (with an override to specify whether or not to update BLOB columns)
  • updateByExampleSelective (will only update non-null fields in the parameter class)

前面一些方法看名字都能知道其用法,但是有些还是有些模棱两可。比如 withBLOBs 和 没有 BLOB 方法的区别。

selectByExample 和 selectByExampleWithBLOBs 区别

如需检索的字段中包含大字段类型时,必须用 selectByExampleWithBLOBs,不检索大字段时,用 selectByExample 就足够了。update 同样如此。

MyBatis Generator

MyBatis GeneratorXML 配置文件在大多数情况下由 XML 配置提供。文件会配置 MyBatis Generator :

  • 如何连接数据库
  • 生成什么 Object,以及如何生成
  • 哪一些数据表需要被生成 Object

下面是基础的模板

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
  <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />

  <context id="DB2Tables" targetRuntime="MyBatis3">
    <jdbcConnection driverClass="COM.ibm.db2.jdbc.app.DB2Driver"
        connectionURL="jdbc:db2:TEST"
        userId="db2admin"
        password="db2admin">
    </jdbcConnection>

    <javaTypeResolver >
      <property name="forceBigDecimals" value="false" />
    </javaTypeResolver>

    <javaModelGenerator targetPackage="test.model" targetProject="\MBGTestProject\src">
      <property name="enableSubPackages" value="true" />
      <property name="trimStrings" value="true" />
    </javaModelGenerator>

    <sqlMapGenerator targetPackage="test.xml"  targetProject="\MBGTestProject\src">
      <property name="enableSubPackages" value="true" />
    </sqlMapGenerator>

    <javaClientGenerator type="XMLMAPPER" targetPackage="test.dao"  targetProject="\MBGTestProject\src">
      <property name="enableSubPackages" value="true" />
    </javaClientGenerator>

    <table schema="DB2ADMIN" tableName="ALLTYPES" domainObjectName="Customer" >
      <property name="useActualColumnNames" value="true"/>
      <generatedKey column="ID" sqlStatement="DB2" identity="true" />
      <columnOverride column="DATE_FIELD" property="startDate" />
      <ignoreColumn column="FRED" />
      <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
    </table>

  </context>
</generatorConfiguration>

context 元素

<context> 元素用来定义生成 Object 的环境,子元素用来定义数据库连接方式,生成对象的类型,和需要生成的 table. 多个 <context> 标签可以配置在 <generatorConfiguration> 下,允许配置多个数据库连接。

jdbcConnection

顾名思义,连接数据库配置

plugin 元素

<plugin> 下定义一些插件,这些插件用来扩展或者修改 MyBatis Generator 生成的代码。plugin 是 context 的子元素。

generatorConfiguration

generatorConfiguration 配置,文档地址这里,每个子元素文档都存在。

javaTypeResolver

这个标签用来配置 MySQL 数据类型到 Java 类型转换过程的精度,比如使用 forceBigDecimals 那么就是默认尝试使用 java.math.BigDecial 来处理 Decimal 和 Numberic 字段。

reference

  • [[MyBatis]]

2016-04-05 java , mybatis , mysql

Python 容易混淆的知识点

星号解压列表元组

简单的解压列表和元组就省略,如果在解压时想要忽略一个元素,之前我们知道可以使用 _ 来忽略

first, _ = ("Ein", "Verne")

这是第二个元素不关心,也就不取了,但是如果要忽略一批元素呢

>>> record = ('ACME', 50, 3.14, (06,04,1989))
>>> name, *_, (*_, year) = record

这时就可以批量忽略中间的 50, 3.14 还有括号中的月份日期了。

Python 中的 slice

之前在看 slice 相关的内容的时候只简单的看了类似 list[:5] 这样的切片操作,几天突然朋友问道下面三元的切片操作,竟然一时没有反应过来,去看了一下文档,原来 slice 可以支持三个参数 obj[start:stop:step],那么综合之前学习的内容就很好解释了。

先来复习一下,假设 l = list(range(10)),那么

l[1:3]              # 结果 [1,2]  左边包括,右边不包括
l[:5]               # [0,1,2,3,4]  不包括 index 为 5 的值
l[5:]               # [5,6,7,8,9]
l[-5:]              # 取后 5 个 [5,6,7,8,9]
l[:-4]              # 除了后四位,输出 [0,1,2,3,4,5]

所以只有 l[start:end] 两个参数的很好理解,只需要直到切片操作是负数表示的序列中的 index 就行。

如果加上 step,那就是 l[start:end:step],而对于正数 step 也很好理解:

l[1:5:2]            # 从第 1 位到第 5 位,不包括 5 位,每次前进 2 个,结果 [1,3]
l[:5:1]             # 从第 0 个取到第 5 个,不包括第 5 位,每次前进 1,输出 [0,1,2,3,4]
l[5::1]             # 从 index 5 取值到最后,每次进一位,输出 [5,6,7,8,9]

再来看下 step 为负数的情况

l[::-1]             # 逆序输出所有的元素
l[-1:-5:-1]         # 第 -1 位到第 -5 位,不包括第 -5 位,每次往前一位,所以为 [9,8,7,6]
l[-1::-1]           # 从最后一位开始,每次往前一位,直到最前面 输出 [9,8,7,6,5,4,3,2,1,0]
l[5::-1]            # 可以怎么理解,从序号 5 开始,每次往前一位,直到最后,所以输出 [5,4,3,2,1,0]

如果 start 没有被省略,那么找到 start,然后往前查找直到 stop 就行,而如果 start 被省略,则需要从最末尾往前:

l[:5:-1]            # 因为省略了开头,所以需要看 step 正负,这里为 -1,所以从最后一位往前直到 index 为 5,所以输出 [9,8,7,6]

这样就比较清除的解决这些问题了,如果 step 换成 2 ,也是一样的模式。

打开文件的模式

python 文件处理时会遇到 open("filename", "mode") 这个函数后面的参数模式:

  • r 只读模式打开文件,文件指针在文件开头
  • rb 以二进制读,文件指针在文件开头
  • r+ 读写模式 (cannot truncate a file),文件指针在文件开头
  • rb+ 以二进制文件读或者写,文件指针在文件开头
  • w 以写模式打开文件,只写入,任何同名文件会被覆盖,如果文件不存在会创建新文件写入
  • w+ 读写模式 (can truncate a file)
  • wb 以二进制模式写,同名文件覆盖,不存在创建新文件
  • wb+ 以二进制模式读写,同名文件覆盖,不存在创建
  • a 附加模式,在文件末增加,文件指针在文件末尾,如果文件不存在会创建新的文件写
  • ab 以二进制形式附加,文件指针在末尾
  • a+ 附加,和读 打开文件,指针在文件末尾
  • ab+ 以二进制打开文件读或者附加,如果文件存在,文件指针指向文件末尾
  • x python 3 中新模式,如果文件存在会创建失败

所以可以总结一些规律

  • b 模式是以二进制形式打开
  • + 如果放在 r 后,是读写,放在 w 后也是 读写,所以有 + 模式表示读和写

String Bytes and Unicode in Python

例子

# Python 2

>>> print type("Hello World!")
<type 'str'>
# this is a byte string

>>>print type(u"Hello World!")
<type 'unicode'>
# this is a Unicode string

Python 3

# Python 3

>>> print(type("Hello World!"))
<class 'str'>
# this is a Unicode string

>>> print(type(b"Hello World!"))
<class 'bytes'>
# this is a byte string

总而言之,Python 2 中字面 str 以 bytes 存储,前缀 u’hello’ 表示 unicode 对象,以 unicode 存储。

而 Python 3,字面 str 以 Unicode 存储,前缀 b’hello’ 表示获取 bytes 对象,或者 str.encode() 来获取 bytes 对象。

Python 3.x 中有三种 string 对象类型,一种是文本类型,另外两种是二进制数据

  • str 表示 Unicode 文本 (both 8bit and wider)
  • bytes 表示二进制内容
  • bytearray,一种可变的 bytes 类型

encoding vs decoding

类型转换

  • encoding 是将 string 根据 encoding name 转变为 raw bytes
  • decoding 是将 raw string 根据 encoding name 转变为 string

将 string 转换为 raw bytes

  • str.encode() 或者 str(B, encoding)

将 raw bytes 转变为 str

  • bytes(S, encoding) 或者 bytes.decode()

Unicode 编码

在处理 Unicode 编码文本,Python 支持

  • “\xNN” hex byte value escapes
  • “\uNNNN” and “\UNNNNNNNN” Unicode escapes,在 unicode escapes 中,前一种使用 4 个十六进制数字编码 2-byte(16-bit) 字符串,后一种使用 8 个十六进制数字编码 4-byte(32-bit) 文本

ASCII 编码

在处理 ASCII 编码时

>>> ord('X')
88
>>> chr(88)
'X'

>>> S = 'XYZ'
>>> S.encode('ascii')               # Values 0..127 in 1 byte (7 bits) each
>>> S.encode('latin-1')             # Values 0..255 in 1 byte (8 bits) each
S.encode('utf-8')                   # Values 0..127 in 1 byte, 128..2047 in 2, others 3 or 4

非 ASCII 编码

在处理非 ASCII 编码时,可能会用到之前提到的 Unicode 编码

>>> chr(0xc4)                       # 0xC4, 0xE8: characters outside ASCII's range
>>> S = '\xc4\xe8'                  # Single byte 8-bit hex escapes
>>> S = '\u00c4\u00e8'              # 16-bit Unicode escapes
>>> len(S)                          # 2 characters long (not number of bytes!)

编解码非 ASCII 编码

如果我们使用 encode 来将一个非 ASCII 字符串使用 ASCII 编码转变为 raw bytes ,会抛出错误。

>>> S = '\u00c4\u00e8'
>>> S.encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1:
ordinal not in range(128)

>>> S.encode('latin-1')             # One byte per character
b'\xc4\xe8'

>>> S.encode('utf-8')               # Two bytes per character
b'\xc3\x84\xc3\xa8'

>>> len(S.encode('latin-1')))
2
>>> len(S.encode('utf-8'))
4

多重继承

在 Python 中如果一个类继承自多个类,这种行为被称为多重继承 multiple inheritance,虽然多重继承非常有用,但是需要注意一些问题,否则会出现不可预见的问题。

在使用多重继承时,如果一个方法从多个超类中继承,先继承的类中的方法会重写后继承类中的方法。(超类顺序为定义 class 时的顺序)。

property

@property 是一个将类方法伪装成为一个属性。

from math import pi

class Circle():
    def __init__(self,r):
        self.r = r

    @property
    def area(self):
        return pi*self.r**2

c = Circle(2)
print(c.area)

在这里 area() 虽然被定义为一个方法,但是类的实例可以使用点来访问 area ,假装是类的一个属性。

静态方法和类成员方法

Python 2.4 中,引入了装饰器(decorators) 的语法,能够对任何可调用的对象进行包装,既能够用于方法也能够用于函数。使用 @ 操作符,在方法或函数上将装饰器列出,指定一个或者多个装饰器。多个装饰器在应用时的顺序与指定顺序相反。

class Date(object):

    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = year

    @classmethod
    def from_string(cls, date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        date1 = cls(day, month, year)
        return date1

    @staticmethod
    def is_date_valid(date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        return day <= 31 and month <= 12 and year <= 3999

date2 = Date.from_string('11-09-2012')
is_date = Date.is_date_valid('11-09-2012')

classmethod 必须有一个指向 class object 的 reference 作为第一参数,而 staticmethod 则不需要。classmethod 通常被用来作为构造函数重载。

Class Method

C++ 有重载的功能,但是 Python 缺乏重载的机制,所以就有了 classmethod,可以想象成另外一个构造函数

@classmethod
def from_string(cls, date_as_string):
    day, month, year = map(int, date_as_string.split('-'))
    date1 = cls(day, month, year)
    return date1

date2 = Date.from_string('11-09-2012')

cls 是一个持有 class self 的对象,但是不是 class 的一个实例。如果继承了 Date 类,所有的子类都会拥有 from_string 方法。

Static method

对于这个例子,is_date_valid 方法不需要关心类内部的其他变量和方法,但是这个 valid 方法和 Date 相关,可以定义为静态方法。和其他语言中的静态方法可以一起理解。

getattr setattr

拦截 intercept 对象的所有特性访问是可能的,然后有一些魔法方法。比如 __getattr___setattr__

  • __getattribute__(self.name) 当特性 name 被访问时自动被调用,只能在新式类中使用
  • __getattr__(self.name) 当特性 name 被访问且对象没有相应的特性时被自动调用
  • __setattr__(self.name.value) 当试图给特性 name 赋值时被自动调用
  • __delattr__(self.name) 当试图删除特性 name 时被自动调用

这里是一些区别

  • __getattribute__ 无条件被调用,任何对象的属性访问时都会隐式调用,比如 t.__dict__ 其实是执行了 t.__getattribute__("__dict__") ,所以如果我们在重载__getattribute__中又调用__dict__的话,会无限递归,用 object 来避免,即 object.getattribute(self, name)
  • __getattr__ 只有 __getattribute__ 找不到的时候才会调用 __getattr__

举例

class Attr(object):

    def __init__(self, name):
        self.name = name

    def __getattribute__(self, item):
        print("__getattribute__ " + item)
        return object.__getattribute__(self, item)

    def __getattr__(self, item):
        print("__getattr__ " + item)

    def __setattr__(self, key, value):
        print("__setattr__ key %s, value %s" % (key, value))
        object.__setattr__(self, key, value)


if __name__ == '__main__':
    attr = Attr('wendy')
    print("main " + attr.name)
    attr.name = 'nancy'

在这个例子中,输出结果

__setattr__ key name, value wendy
__getattribute__ name
main wendy
__setattr__ key name, value nancy

迭代器

在 Python 中,很多对象都是可以通过 for 语句来直接遍历的,例如 list、string、dict 等等,这些对象都可以被称为可迭代对象。迭代器对象要求支持迭代器协议的对象,在 Python 中,支持迭代器协议就是实现对象的__iter__()next() 方法。其中__iter__() 方法返回迭代器对象本身;next() 方法返回容器的下一个元素,在结尾时引发 StopIteration 异常。

class PowTwo:
    """Class to implement an iterator
    of powers of two"""

    def __init__(self, max=0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 ** self.n
            self.n += 1
            return result
        else:
            raise StopIteration


p = PowTwo(5)
for i in p:
    print(i)

生成器

生成器通过生成器函数产生,生成器函数可以通过常规的 def 语句来定义,但是不用 return 返回,而是用 yield 一次返回一个结果,在每个结果之间挂起和继续它们的状态,来自动实现迭代协议。

在理解生成器之前,首先要先理解上面提到的迭代器,使用迭代器能够非常轻松的遍历列表等等中的内容,虽然迭代器很好用,但是迭代器会将内容全都放到内存中,所以一旦遇到特别庞大的列表,可能就会遇到问题。

所以有了生成器,生成器是一种特殊的迭代器,只能够遍历一次。

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)

这里 mygenerator 需要使用 ()

然后 yield 关键字,就像 return ,但是表示方法会返回一个生成器。

>>> def createGenerator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

返回 yield 的方法在方法被调用的时候并不会执行,只有在使用 for 来遍历该生成器时,才会执行。执行的顺序是,方法每 yield 一次就返回一次,等待 for 中执行完毕,继续执行生成器方法中的下一次 yield,然后返回 for 中,然后反复执行直到生成器没有 yield 任何内容。

模块

告诉编译器去哪里找,一种方法就是编辑 sys.path 另外一种方法就是使用 PYTHONPATH 环境变量

Python 3.6.1 (default, Apr 23 2017, 12:32:16)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.path)
['', '/home/einverne/.pyenv/versions/3.6.1/lib/python36.zip', '/home/einverne/.pyenv/versions/3.6.1/lib/python3.6', '/home/einverne/.pyenv/versions/3.6.1/lib/python3.6/lib-dynload', '/home/einverne/.pyenv/versions/3.6.1/lib/python3.6/site-packages']

对于不同的操作系统 PYTHONPATH 配置可能有些差异,在类 Unix 系统下

export PYTHONPATH=$PYTHONPATH:~/pypath:~/py1

为组织模块,可以分组为包 package, 为了让 Python 将其作为包对待,必须包含一个 __init__.py 的文件。

假如构造了如下的目录结构

├── douban
│   ├── album.py
│   ├── celebrity.py
│   ├── __init__.py

定义了 douban 目录,那么该文件夹下的 __init__.py 就是 douban 包(模块)的代码,其他两个 album.pycelebrity.py 分别是 album 和 celebrity 模块。

如果单纯的引入

import douban

那么 __init__ 模块的内容是可用的,但是其他两个模块是不可用的。

import douban.album

那么这个时候 album 模块也是可用的。但这时候只能通过全名 douban.album. 来使用。

from douban import celebrity

这时候 celebrity 模块可用,可以通过短名来使用,比如 celebrity.xxx

模块中定义 __all__ = [] 向外导出可用方法。在别人应用该模块时,打印 __all__ 内容就能够清晰看到模块对外提供的方法。

标准库

sys 模块能够轻松访问 Python 解释器联系的变量和函数

函数或变量 描述
argv 命令行参数,包括脚本名字
exit([arg]) 退出,可选参数给定返回值或错误
modules 映射模块名字到载入模块的字典
path 查找模块所在目录的目录名列表
platform 平台
stdin 标准输入流
stdout 标准输出流
stderr 标准错误流

os 模块提供了访问操作系统服务的功能。

os.path子模块包含了检查构造删除目录和文件的函数。

time 模块能够实现,获取当前时间,操作时间和日期,从字符串读取时间以及格式化时间为字符串等等功能。

函数 描述
asctime([tuple]) 将时间元组转换为字符串
localtime([secs]) 将秒转换为日期元组,本地时间
mktime(tuple) 将时间元组转换为本地时间
sleep(secs) 休眠
strptime(string[, format]) 将字符串解析为时间元组
time() 当前时间,秒

random 模块包括返回随机数的函数,可以用于模拟或者任何产生随机数的程序。

f-Strings

f-Strings 在 Python 3.6 以后引入的新特性,新语法,用来输出格式化的文本 (PEP 498)

>>> name = "Eric"
>>> age = 74
>>> f"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'

Python 以前的格式化输出,总或多或少有些毛病

>>> "Hello, %s. You are %s." % (name, age)
>>> "Hello, {}. You are {}.".format(name, age)

关于输出字符串各种方式的优缺点、性能比较可以参考这篇

reference


2016-04-04 python , class , inheritance

Java 查漏补缺之 Thread 类中 interrupt() interrupted() isInterrupted() 区别

Thread 类中有三个方法长得非常像,也特别容易混淆,但是使用起来却非常不同:

public void interrupt() // 无返回值
public boolean isInterrupted() // 有返回值
public static boolean interrupted() // 静态,有返回值

解释

  • interrupt(): 中断本线程

      myThread.interrupt();// 中断的是调用 interrupt() 方法的线程
    

    阻塞于 wait/join/sleep 的线程,中断状态会被清除掉,同时收到异常 InterruptedException;而其他情况中断状态都被设置,并不一定收到异常。interrupt() 方法其实是通知线程该中断了。线程具体中断还是继续执行,应该由被执行线程自己处理。

    具体来说,当一个线程调用 interrupt() 方法时:

      - 线程处于阻塞状态(sleep,wait,join 等),线程立即退出被阻塞状态,抛出 InterruptedException 异常
      - 线程处于正常活动状态,会将线程中断标志设置为 true,被设置中断标志的线程将继续正常运行
    

    一个线程如果有被中断的需求,在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程

      Thread thread = new Thread(() -> {
          // 若未发生中断,就正常执行任务
          while (!Thread.interrupted()) {
              // 正常任务代码
          }
          // 中断处理代码
          doSomething();
      });
      thread.start();
    
      // 一段时间以后
      thread.interrupt();
    
  • isInterrupted(): 检测本线程是否已经中断

      myThread.isInterrupted();// 判断本线程 myThread 是否中断
    

    如果已经中断,则返回 true,否则 false。中断状态不受该方法的影响。 如果中断调用时线程已经不处于活动状态,则返回 false。

  • interrupted(): 检测当前线程是否已经中断

      Thread.interrupted();// 判断该语句所在线程是否中断
    

    如果已经中断,则返回 true,否则 false,并清除中断状态。换言之,如果该方法被连续调用两次,第二次必将返回 false,除非在第一次与第二次的瞬间线程再次被中断。如果中断调用时线程已经不处于活动状态,则返回 false。

横向对比

后两个方法的区别横向比较:

isInterrupted() interrupted()
实例方法 类方法
判断本线程 判断当前线程
仅读取中断状态 读取并清除中断状态

reference


2016-04-02 java , thread , interrupt

每天学习一个命令:fdisk 查看磁盘详情

fdisk 命令用于观察硬盘实体使用情况,可以用来列出机器中所有磁盘的个数,也能列出所有磁盘分区情况,也可对硬盘分区(适用于 2T 以下磁盘,高于 2T 磁盘使用 parted)。

常见用法

显示所有磁盘的分区详情

fdisk -l

常见的磁盘标示都是 sda, sdb 类似,而分区则是在磁盘标示后面添加数字,比如 sda1, sda2, … , sdb3 等等。

选择进行操作的磁盘

fdisk /dev/sdb

对 U 盘进行格式化,其他设备同理。

# 查看 U 盘挂载点(此例是 /tmp/mnt/sda1)
$ df -h
Filesystem                Size      Used Available Use% Mounted on
ubi:rootfs_ubifs         77.2M     64.0M     13.2M  83% /
mtd:bootfs                4.4M      3.3M      1.1M  75% /bootfs
mtd:data                  8.0M    556.0K      7.5M   7% /data
/dev/mtdblock8           48.0M      9.0M     39.0M  19% /jffs
/dev/sda1                 3.5G     51.1M      3.3G   2% /tmp/mnt/sda1

# 卸载 U 盘
$ umount /tmp/mnt/sda1

# 查看 U 盘设备路径(此例是 /dev/sda)
$ fdisk -l
Disk /dev/sda: 3869 MB, 3869544448 bytes
245 heads, 52 sectors/track, 593 cylinders
Units = cylinders of 12740 * 512 = 6522880 bytes
   Device Boot      Start         End      Blocks  Id System
/dev/sda1               1         593     3777384  83 Linux

# 删除分区、新建分区
$ fdisk /dev/sda
Command (m for help): d  # 删除分区
Selected partition 1
Command (m for help): n  # 新建分区
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1015, default 1): Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-1015, default 1015): Using default value 1015
Command (m for help): w  # 保存分区
The partition table has been altered.
Calling ioctl() to re-read partition table

# 格式化分区为 ext4
mkfs.ext4 /dev/sda1

# 挂载 U 盘
$ mkdir /tmp/mnt/sda1
$ mount -t ext3 /dev/sda1 /tmp/mnt/sda1

2016-04-02 fdisk , disk , linux , partition , command

MySQL 中的大小写敏感设置

默认情况下 MySQL 中存储内容不是大小写敏感的。MySQL 的大小写和建数据库时的排序规则有关。

  • utf8_bin 则是将字符串中的每一个字符用二进制存储,bin 是 binary case sensitive collation,区分大小写
  • utf8_general_ci 不区分大小写,ci 为 case insensitive
  • utf8_general_cs 区分大小写,cs 为 case sensitive 缩写

建表时字段区分大小写

在建表时可以通过 BINARY 来区别

比如

CREATE TABLE test
(
    name VARCHAR(20),
    UNIQUE(name)
);

mysql>     INSERT INTO test VALUES('California');
Query OK, 1 row affected (0.00 sec)

mysql>     INSERT INTO test VALUES('california');
ERROR 1062 (23000): Duplicate entry 'california' for key 'name'

mysql>     INSERT INTO test VALUES('cAlifornia');
ERROR 1062 (23000): Duplicate entry 'cAlifornia' for key 'name'

mysql>     INSERT INTO test VALUES('cALifornia');
ERROR 1062 (23000): Duplicate entry 'cALifornia' for key 'name'

mysql> SELECT * FROM test;
+------------+
| name       |
+------------+
| California |
+------------+
1 row in set (0.00 sec)

如果需要配置大小写敏感则需要使用 BINARY

mysql>     CREATE TABLE test
    ->     (
    ->         name varchar(20) BINARY,
    ->         UNIQUE(name)
    ->     );
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql>     INSERT INTO test VALUES('California');
Query OK, 1 row affected (0.00 sec)

mysql>
mysql>     INSERT INTO test VALUES('california');
Query OK, 1 row affected (0.00 sec)

mysql>     INSERT INTO test VALUES('cAlifornia');
Query OK, 1 row affected (0.00 sec)

mysql>     INSERT INTO test VALUES('cALifornia');
Query OK, 1 row affected (0.00 sec)

mysql>
mysql>     SELECT * FROM test;
+------------+
| name       |
+------------+
| California |
| cALifornia |
| cAlifornia |
| california |
+------------+
4 rows in set (0.00 sec)

查询区分大小写

当然在建库,或者建表时已经排序规则之后就要按照之前的约定,如果没有约定,按照默认则需要自己指定。

强制让 where 语句中区分大小写需要在 where 后添加 binary

select * from table where binary name='Abc'

配置表名大小写不敏感

需要修改配置

/etc/mysql/my.cnf

在 [mysqld] 配置下面:

lower_case_table_names = 1

然后需要重新加载 mysql 配置或者重启 MySQL 服务。

reference


2016-04-01 mysql , sql , index

查看当前正在使用哪种 Shell

当前正在运行的 shell 路径被保存在 $0 环境变量中,可以使用如下方式查看

echo $0

根据不同系统的实现,输出可能会是当前正在运行的 shell,或者是当前运行的 shell 的路径。

prompt:~$ echo $0
/bin/bash
prompt:~$ sh
sh-4.0$ echo $0
sh
sh-4.0$ exit
exit
prompt:~$ /bin/sh
sh-4.0$ echo $0
/bin/sh
sh-4.0$

$SHELL 变量保存了用户偏好的 shell,而不是当前正在运行的 shell。

更多关于 shell 的默认特殊变量,可以查看之前的总结


2016-03-27 linux , shell , bash , sh , zsh

推荐网站之邮件签名:htmlsig

推荐好用的网站系列之生成邮件签名 htmlsig 。想要一个漂亮的邮件签名,又不想自己写 html,最好的方法就是找一个模板然后自己填写内容。这个网站就是这样的。

官网地址:https://htmlsig.com/

样式1 htmlsig 1

样式2 htmlsig 2

样式3 htmlsig 3

样式4 htmlsig 4

当然我本人最喜欢样式2.

如果稍微懂一点 html 知识,将模板下载下来然后自己手动修改倒也是不错的选择。

生成自己的模板之后,Gmail 和 Inbox 都可以使用复制粘贴的方式将签名添加进去。


2016-03-23 website , 推荐网站

电子书

本站提供服务

最近文章

  • Glance 个人自定义 Dashboard Glance 是一个可以自行架设的个人 Dashboard 以及 RSS 订阅信息面板。
  • Fileball 一款 iOS tvOS 上的媒体播放器及文件管理器 Fileball 是一款 iOS,tvOS 上的本地文件管理器,本地音乐播放器,本地视频播放器,以及文本编辑器,Fileball 可以在 iPhone,iPad,Apple TV 上使用。Fileball 可以连接网络共享,支持 SMB,FTP,SFTP,Synology,NFS,WebDAV 等,支持 Emby,Jellyfin 等,还可以连接百度网盘,Box,Dropbox,Google Drive,OneDrive,pCloud 等,可以作为 [[Infuse]] ,[[VidHub]] 等播放器的平替,高级版本价格也比较合适。Fileball 也支持 [[IPTV]]。
  • 在日本申请入台证材料及在线提交注意事项 本文记录入台证办理的材料及提交手续,以及在使用线上提交系统的时候需要注意的点。入台证是中华民国台湾地区出入境许可证的俗称,所有进入台湾的人都需要申请此许可证。
  • 从 Buffer 消费图学习 CCPM 项目管理方法 CCPM(Critical Chain Project Management)中文叫做关键链项目管理方法,是 Eliyahu M. Goldratt 在其著作 Critical Chain 中踢出来的项目管理方法,它侧重于项目执行所需要的资源,通过识别和管理项目关键链的方法来有效的监控项目工期,以及提高项目交付率。
  • AI Shell 让 AI 在命令行下提供 Shell 命令 AI Shell 是一款在命令行下的 AI 自动补全工具,当你想要实现一个功能,敲一大段命令又记不住的时候,使用自然语言让 AI 给你生成一个可执行的命令,然后确认之后执行。