try-with-resources 表达式就是在 try 语句中定义了一个或者多个资源,resource 必须要在程序结束后关闭,try-with-resources 表达式保证了 resource 会在表达式结束时自动关闭,有点像 python 的 with 语句。所有实现了 java.lang.AutoCloseable
接口的类都可以作为 try 中的 resource。
下面的例子中 BufferedReader
需要被关闭。在 Java SE 7 以后,BufferedReader 实现了 AutoCloseable 接口,所以定义在 try 语句中的的 br 对象,不管正常执行,或者异常,都会在表达式结束时自动关闭。
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
在 Java SE 7 以前需要使用 finally 来保证
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
当然在 try 语句中多个语句也是可以的。
如果要实现 try-with-resources
需要资源实现 AutoCloseable
接口,重写 close
方法。
然后 Java 程序在编译的时候,编译器就会根据实现的 close 方法来自动生成 try-finally 方法块。
Closeable 继承了 AutoCloseable:
public interface Closeable extends AutoCloseable {
void close() throws IOException;
}
Closeable 的 close 方法抛出的是 IOException
.
OpenSSH 毫无疑问是世界上使用最广泛允许用户通过终端安全连接远程主机的工具了,但是 OpenSSH 存在一个比较大的问题就是不能在多台主机中执行相同的命令,OpenSSH 并不是设计做此用途的。所以 Parallel SSH 或者简称 PSSH 就出现了。PSSH 是一个 python 编写的用来在多台主机中并行执行相同命令的工具。
PSSH 工具集包含如下命令:
sudo apt install python-pip
sudo pip install pssh
首先创建 pssh host 文件
192.168.0.10:22
192.168.0.11:22
比如执行 echo
pssh -h pssh-hosts-file -l root -A echo "TEST"
比如查看硬盘使用情况
pssh -h pssh-hosts-file -l root -A -i "df -hT"
同理
pssh -h pssh-hosts-file -l root -A -i "uptime"
PSSH 工具适合用来在管理员需要在多台主机上执行重复命令时。
最近在安装 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 里拖。
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
在官网根据自己的机器选择合适的 client 下载并解压。并运行:
./btsync
即可。
默认的 Web GUI 地址是 : http://127.0.0.1:8888
更加详细的安装指南可以参考这篇
类似 Linux 下安装,官网下载并解压 btsync 文件。
tar -zxvf BitTorrent-Sync_x64.tar.gz
然后执行:
./btsync --dump-sample-config > btsync.conf
创建配置文件,然后修改 btsync.conf
配置文件中的:
"listen" : "0.0.0.0:8888"
还有 login
和 password
, 端口默认是 8888,可修改成其他没有冲突的。login
和 password
是登陆用户名和密码。其他配置看注释修改即可。参考官网 config 文章.
然后保存配置文件,启动:
./btsync --config btsync.conf
在浏览器中就能够在 http://ip:port/ 访问 Web GUI。
然后在本地获取同步 key ,和 VPS 上同步即可。
如果你已经同步了一个文件夹,比如在 ~/books
,现在想要将该同步的目录移动到 ~/btsync/books
目录下。 就像 Dropbox 同步已经存在的文件夹 一样,如果单纯的再重新下载一边太麻烦了。所以幸好 btsync 和 dropbox 都有这样的性质,同步的内容都有文件记录,将文件重新加入索引,等索引完之后就可以继续和其他的文件同步了。
默认 btsync 的 web gui 是没有启用加密的,如果想要使用 https://ip:port/gui 来访问,则需要使用 config 配置,并在 config 配置中设置 force_https
, ssl_certificate
,ssl_private_key
,然后重启 btsync 。
如果觉得这样让 btsync 直接获取证书不安全,这里 还有另外一种配置,利用 nginx 的代理。
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 .
最近迷上了360度全景,搞了得图800,和理光 theta m15的全景相机玩。然后就对周边的全景处理App都体验了一下。最早接触到 Sphere Photo 也要归功于 Google 的原生 Camera, 然而因为不知道的原因,在 Android kitkat 之后的版本中这个小行星视图就消失不见了。而我还是依然很怀念这样的视图。下面就是一些 Play Store 中存在的制作小行星视图的App。
完整却不够完美 市场上唯一一款收费的小行星app,但是给我的感觉却是做的不够精致和完美,今天竟然处理出不完整的人脸。处理图像甚至比不上另一款免费的app。
除了开始的广告一切还好 开始的广告可能是让很多人打低分的原因,但是这款app,确实达到了我的需求,并且实现的很好。开发者可以尝试提供pro版本来去除广告或者内购去广告。
广告多功能简单 太多影响操作的广告,横幅广告侵占了操作预览区域。功能比不上其他app。
功能简单广告影响使用 功能几乎没有,处理时间太长。广告占据太多篇幅。
最后推荐 Little Planet , 虽然在App开始出现了全屏广告,但是效果及功能和收费的 Tiny Planet FX Pro 相差不大。
大多数时候我没有时间用 Google Camera 照完整个全景,这个时候如果可以后期合成当然是最好的,于是就有了这样一篇文章 ,只要有一张全景照片,利用 Photoshop 同样可以实现 Sphere Photo。 同样也可以参考这篇文章。
最后推荐一个社区 https://plus.google.com/u/0/communities/115970110085205516914 ,社群的简介里面有很多教程,并且分享的 Post,质量都很高。
The Web Server Gateway Interface(WSGI) 是网络服务器软件和网络应用程序之前的标准接口。通过共同的网关标准接口可以让同一个应用支持不同的服务器。只有网络服务器或者编程框架的作者需要熟悉 WSGI 设计,如果使用现存的框架则不太需要关心更底层的网关接口。
wsgiref 是 Python 的 WSGI 标准实现,可以用来帮助实现网络服务器和应用框架。他提供了一系列工具用来操作 WSGI 环境变量和响应头,也提供了基础的类来实现 WSGI 服务器,提供了简单的 HTTP 服务来给 WSGI 应用提供服务器,提供了一个符合 WSGI 标准(PEP 3333) 的验证工具来验证 WSGI 服务器和应用。
文档
wsgiref.util 这个模块提供了一系列工具用来操作 WSGI environments。
该模块提供了一个简单的类 Headers
用来操纵 WSGI 相应头。
该模块基于 http.server 实现了一个简单的 HTTP 服务器,这个服务器能够给 WSGI 应用提供服务。每一个服务器实例在特定的 host 和 port 上提供一个 WSGI 应用服务。如果要在听一个 host 和 port 上给不同应用程序提供服务,那么你需要创建一个 WSGI 应用,并且传入 PATH_INFO
来选择哪一个应用程序来来被每一次请求调用。
验证模块。
该模块提供了实现 WSGI 服务器和网关的基础类。这些基础类能够处理和 WSGI 应用的大部分通信。
简单的例子
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()
MyBatis 自动生成的 Java client generator 会产生如下的方法;
前面一些方法看名字都能知道其用法,但是有些还是有些模棱两可。比如 withBLOBs 和 没有 BLOB 方法的区别。
如需检索的字段中包含大字段类型时,必须用 selectByExampleWithBLOBs,不检索大字段时,用 selectByExample 就足够了。update 同样如此。
MyBatis GeneratorXML 配置文件在大多数情况下由 XML 配置提供。文件会配置 MyBatis Generator :
下面是基础的模板
<?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>
元素用来定义生成 Object 的环境,子元素用来定义数据库连接方式,生成对象的类型,和需要生成的 table. 多个 <context>
标签可以配置在 <generatorConfiguration>
下,允许配置多个数据库连接。
顾名思义,连接数据库配置
<plugin>
下定义一些插件,这些插件用来扩展或者修改 MyBatis Generator 生成的代码。plugin 是 context 的子元素。
generatorConfiguration 配置,文档地址这里,每个子元素文档都存在。
这个标签用来配置 MySQL 数据类型到 Java 类型转换过程的精度,比如使用 forceBigDecimals
那么就是默认尝试使用 java.math.BigDecial
来处理 Decimal 和 Numberic 字段。
简单的解压列表和元组就省略,如果在解压时想要忽略一个元素,之前我们知道可以使用 _
来忽略
first, _ = ("Ein", "Verne")
这是第二个元素不关心,也就不取了,但是如果要忽略一批元素呢
>>> record = ('ACME', 50, 3.14, (06,04,1989))
>>> name, *_, (*_, year) = record
这时就可以批量忽略中间的 50, 3.14 还有括号中的月份日期了。
之前在看 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 中新模式,如果文件存在会创建失败所以可以总结一些规律
+
如果放在 r
后,是读写,放在 w
后也是 读写,所以有 +
模式表示读和写例子
# 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
类型类型转换
将 string 转换为 raw bytes
str.encode()
或者 str(B, encoding)
将 raw bytes 转变为 str
bytes(S, encoding)
或者 bytes.decode()
在处理 Unicode 编码文本,Python 支持
在处理 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 编码时,可能会用到之前提到的 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!)
如果我们使用 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
是一个将类方法伪装成为一个属性。
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 通常被用来作为构造函数重载。
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
方法。
对于这个例子,is_date_valid
方法不需要关心类内部的其他变量和方法,但是这个 valid 方法和 Date 相关,可以定义为静态方法。和其他语言中的静态方法可以一起理解。
拦截 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.py
和 celebrity.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 在 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)
关于输出字符串各种方式的优缺点、性能比较可以参考这篇
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() |
---|---|
实例方法 | 类方法 |
判断本线程 | 判断当前线程 |
仅读取中断状态 | 读取并清除中断状态 |
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
默认情况下 MySQL 中存储内容不是大小写敏感的。MySQL 的大小写和建数据库时的排序规则有关。
utf8_bin
则是将字符串中的每一个字符用二进制存储,bin 是 binary case sensitive collation,区分大小写utf8_general_ci
不区分大小写,ci 为 case insensitiveutf8_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 服务。