UTF-8编码是费内存的,但是却是安全的,如果是GBK编码时,下面的表达式返回True:
'嵌' in '我们都是中国人'
注意UTF-8编码也有两字节的,而且跟三字节的模样还挺像:
In [1]: '»'
Out[1]: '\xc2\xbb'
In [2]: '》'
Out[2]: '\xe3\x80\x8b'
其他一些有趣的符号:
raquo »laquo «rsaquo ›lsaquo ‹rdquo ”ldquo “rsquo ’lsquo ‘
日元符号:
In [5]: '¥'
Out[5]: '\xc2\xa5'
人民币符号:
In [6]: '¥'
Out[6]: '\xef\xbf\xa5'
Queue是一个线程安全的队列,初始化的maxsize<=0时,表示队列容量无限。Queue是一个线程安全的队列,内部自行加锁。 put和get的时候,要注意Queue.Full和Queue.Empty异常,有趣的是,默认会阻塞,直到put或get成功。
q = Queue.Queue(1024)
q.put(self, item, block=True, timeout=None)
q.get(self, block=True, timeout=None)
要么就设置block=False,这样timeout就被忽略了,相当于put_nowait()或者get_nowait()。要么就设置一个timeout值。
collections.defaultdict跟普通dict一样,只是在没有设置时,会根据初始化的默认工厂函数设置一个默认值。
dd = collections.defaultdict(list)
collections.namedtuple跟普通tuple也一样,只是它是有名字的tuple,更像是C++里的结构体。当传递多个值时, 使用namedtuple比直接使用tuple更优雅:
Student = collections.namedtuple('Student', 'name age school x y')
s = Student('wangyang', 20, 'hust', x=100, y=200)
s.name #像类一样访问成员
s[0] #像tuple一样用下标访问
list(s)
name,age = s[:2]
就像xrange和range的差别,前者是每次循环执行一步,而后者是循环一个list,前者更省内存。 有两种方法来实现,其一,实现一个类的__iter__()
和next()
方法,这样每次循环的时候,推进一步:
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration()
for n in Fab(5):
print n
其二,就是使用yield,当遇到yield时,循环取一次值,下一次循环时,再次从上次yield处开始执行,函数返回时,表示循环结束:
def Fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n += 1
for i in Fab(5):
print(i)
is None
和is not None
,==
和!=
会调用__eq__
函数。expr
和not expr
,道理同上。==
和!=
,语义更清晰。python正则模块提供如下一些核心方法:
上面函数的参数大体是pattern, string, flags=0
这么三个,pattern可以是正则表达式,也可以是一个编译好的pattern对象, flags是一些bit位或起来,控制正则形为。flags也可以在编译正则的时候给出:
re.compile(r'<div[^>]*content[^>]*>(.*?)[\n ]</div>', re.MULTILINE | re.DOTALL)
re.MULTILINE
表示多行匹配,默认是按行匹配的,通常搭配上re.DOTALL
,表示点(.)可以匹配包括回车换行在内的任何字符, 否则是不能匹配回车换行的。.*?
中的问号表示使用非贪婪算法。默认* + ?
都是贪婪的,后面加个问题成*? +? ??
就成非贪婪的了。
在没有设置UNICODE标志情况下,有下表常用匹配符:
匹配符 | 意义 |
---|---|
\A | 匹配字符串开头 |
\b | 匹配一个词的开头或者结尾 |
\B | 匹配一个词的词中,词中字符集等于\w |
\d | [0-9] |
\D | [^0-9] |
\s | [ \t\n\r\f\v] |
\S | [^ \t\n\r\f\v] |
\w | [a-zA-Z0-9_] |
\W | [^a-zA-Z0-9_] |
\Z | 匹配字符串的结尾 |
函数默认参数使用常量,否则有调用者传入,不然很容易产生非预期结果,代码也很让人费解:
def get_now(time = time.time()):
print(time)
反复调用上面的函数,输出是不会有变化的。函数的成员函数道理也是一样的。
不加s的版本,都是针对文件的读写:
with open("output.txt", 'a+') as f:
json.dump(d, f, ensure_ascii=False, indent=4)
f.write("\n")
indent
会多行缩进,优雅打印。加载进来的时候,文件中只能是一个json:
with open('output.txt') as f:
a = json.load(f)
针对字符串时,应该使用json.dumps
和json.loads
。python在加载json时,要求json里使用双引号:
json.loads("{'name':123, 'age':'123'}") #Error
json.loads('{"name":123, "age":"123"}') #OK
而且带引号的"123"会被解析为字符串,而123会被解析为整型,null会被解析为None:
>>> json.loads('{"name":null, "age":"128"}')
>>> {u'age': u'128', u'name': None}
使用argparse,可以很方便地让脚本获取启动时的命令参数,举个例子:
import argparse
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('--name', dest='name', required=True, help='your name')
parser.add_argument('-a', dest='age', nargs=1, type=int, help='your age')
parser.add_argument('-s', dest='scores', nargs='+', default=[0], help='your english scores')
parser.print_help()
ns = parser.parse_args('--name wangyang -a 100 -s 60 70 80'.split())
print(ns.name, ns.age, ns.scores)
参数非常多,大体为:
?
、+
、*
。parser.parse_args()
参数为空时,就会使用sys.argv。python读取配置格式比较宽松:
[My Section]
foodir: %(dir)s/whatever
dir=frob
long: this value continues
in the next line
可以使用冒号(:)或者等号(=),整行注释,可使用井号(#)或者分号(;),行尾注释只能使用分号(;)。
import ConfigParser
config = ConfigParser.SafeConfigParser()
config.read('/tmp/spider.conf')
config.has_section('spider')
url = config.get('spider', 'target_url')