fedora19更换fcitx输入法

发布在 Linux

今天上午实在是忍受不了ibus的折磨更换输入法,首先删除ibus

1
2
sudo yum remove ibus
gsettings set org.gnome.settings-daemon.plugins.keyboard active false

之后安装fcitx:sudo yum install fcitx*

配置fcitx

在~/.bashrc中添加:

1
2
3
export GTK_IM_MODULE=fcitx  
export QT_IM_MODULE=fcitx
export XMODIFIERS="@im=fcitx"

正常情况下重启就应该可以使用了。如果fcitx没自动启动,则在终端中启动,或者输入
gnome-session-properties
新建一个选项 /usr/bin/fcitx 就搞定了。

不过我不知道什么原因会出现错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-xkbdbus.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-table.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-notificationitem.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-xkb.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-kimpanel-ui.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-unicode.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-punc.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-quickphrase.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-remote-module.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-chttrans.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-dbus.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-classic-ui.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-qw.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-fullwidth-char.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-ipc.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-keyboard.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-freedesktop-notify.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-x11.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-xim.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-imselector.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-autoeng.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-spell.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-vk.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-pinyin-enhance.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-pinyin.conf
(INFO-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/addon.c:151) 加载附加组件配置文件: fcitx-clipboard.conf
(WARN-1370 /build/fcitx/src/fcitx-4.2.8/src/module/dbus/dbusstuff.c:246) DBus Service Already Exists
(ERROR-1370 /build/fcitx/src/fcitx-4.2.8/src/lib/fcitx/instance.c:424) Exiting.

折腾N次无果,怒删fcitx重装,结果不知道为什么自己又好使了。

一个坑爹的问题就是,只能输入英文和郑码 于是终端中输入im-chooser打开输入法选择器,双击fcitx把拼音那两个选项提到上面即可。

评论和分享

linux用vps翻墙(ssh篇)

发布在 Linux

最近买了一个VPS玩,提供了SSH功能,那就用它来翻翻墙吧。

编写一个脚本文件,内容如下

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/expect -f
set port 7070
set user xxxx
set host IP地址
set password xxxx
set timeout -1
spawn ssh -fND $port $user@$host
expect "*assword:*"
send "$passwordr"
expect eof

如果提示spawn命令不存在一类的错误则安装expect、spawn

修改userhostpassword 为你自己的再给上面的脚本添加执行权限。

用root用户执行。

如果是firefox浏览器并使用了autoproxy插件,则设置默认代理为ssh-D,端口根据情况修改,使用socket5。

谷歌浏览器同理

友情提示:速度和流量限制要根据你购买的VPS服务决定哈~

评论和分享

fedora19安装codeblocks

发布在 Linux

嫌麻烦的可以用yum install codeblocks安装,不过版本是10.05

爱尝鲜的可以去官网下最新版本12.11,功能多了很多。目前没有fedora19的不过18的也可以用。

下载codeblocks-12.11-1.el18.x86_64.tar.bz2后解压得到4个文件,全部安装即可。其实只安装codeblocks-12.11-1.el18.x86_64.rpm就可以使用了,全都安装后功能更多一些。

如果是用yum安装的,运行程序时终端十分丑陋,可以设置

1
Settings->Environment->"Terminal to launch console programs" 为 "gnome-terminal --geometry 80x20+100+100 --hide-menubar -t $TITLE -x"(不包含引号)。

参数可以自己修改。

评论和分享

django文件上传功能

发布在 Django

今天需要一个文件上传功能,所以代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def ci_test(request):
try:
if request.POST.has_key("send"):
xml_string=""
final_xml = ""
file_obj = request.FILES.get('file', None)
for keys in request.POST:
if request.POST[keys]:
print keys,request.POST[keys]
xml_string = "<%s>%s</%s>n%s" % (keys,request.POST[keys],keys,xml_string)
final_xml = "<root>n%s</root>" % xml_string
dirname = os.path.dirname(os.path.abspath(__file__))
parent = os.path.split(dirname)[0]
if request.POST["source"] == "text" and file_obj:
if file_obj.name.endswith(".txt"):
#print parent
filepath = "%s/core/emaillist.txt" % parent
#print filepath
open(filepath,'w').write(file_obj.read()) #注意这里
else:
raise forms.ValidationError("上传文件类型错误!")
path = "%s/core/config/%s.xml" % (parent,request.POST['txtDate'])
open(path,'w').write(final_xml.encode('utf-8'))
else:
smtp = request.POST['smtp']
username = request.POST['username']
passwd = request.POST['passwd']
title = request.POST['title'] #邮件标题
content = request.POST['content'] #邮件内容
attach = request.POST['useattach'] #是否是附件发送
ctype = request.POST['c_type'] #邮件格式
testsend = request.POST['testsend']#测试邮箱
subtem = u"%s: %s" % (u"测试",title)
conn = creat_conn(smtp, username, passwd)
tem = testsend.split(';')
if ctype.upper() == "HTML":
final_body = creat_htmlbody(content)
#测试发送,不用记录日志直接传列表
final_testmail(subtem,final_body,username,tem,conn,attach)
print "test send to %s sucess!" % tem
else:
final_testmail(subtem,content,username,tem,conn,"test")
print "test send to %s sucess!" % tem
return render(request,'test.html',{"msg":"请求已经提交,关闭本页面即可"})
except forms.ValidationError:
print "in my error"
return render(request,'test.html',{{"msg":"文件类型错误,请重新操作!"}})
except Exception:
return render(request,'test.html',{{"msg":"发生错误,请重新操作!"}})

此处需要注意模版文件中form的写法:

1
2
3
<form action="ci_test" method="post" onsubmit="return validate_form(this);" enctype="multipart/form-data">
<input type="file" name="file"/>
</form>

不过此处有个奇怪的问题,根据流程来看,如果上传的不是.txt文件则引发异常,也确实输出了”in my error”这句话,不过随后就引发了下面的异常,不知道render为什么错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
TypeError at /mailinfo/ci_test
unhashable type: 'dict'
Request Method: POST
Request URL: http://127.0.0.1:8000/mailinfo/ci_test
Django Version: 1.5.3
Exception Type: TypeError
Exception Value:
unhashable type: 'dict'
Exception Location: /home/xingsongyan/workspace/send/mailinfo/views.py in ci_test, line 66
Python Executable: /usr/bin/python2.7
Python Version: 2.7.5
Python Path:
['/home/xingsongyan/workspace/send',
'/usr/lib/python2.7/site-packages/pip-1.4.1-py2.7.egg',
'/home/xingsongyan/workspace/send',
'/usr/share/eclipse/dropins/pydev/eclipse/plugins/org.python.pydev_2.8.2.2013090511/pysrc',
'/usr/lib64/python27.zip',
'/usr/lib64/python2.7',
'/usr/lib64/python2.7/plat-linux2',
'/usr/lib64/python2.7/lib-tk',
'/usr/lib64/python2.7/lib-old',
'/usr/lib64/python2.7/lib-dynload',
'/usr/lib64/python2.7/site-packages',
'/usr/lib64/python2.7/site-packages/gtk-2.0',
'/usr/lib64/python2.7/site-packages/wx-2.8-gtk2-unicode',
'/usr/lib/python2.7/site-packages',
'/usr/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg-info',
'/usr/lib64/python2.7/site-packages/PIL']
Server time: Wed, 4 Dec 2013 16:05:25 +0800

评论和分享

python分离中、英文

发布在 Python

本来打算使用正则表达式,但是发现实际情况不能简单的用正则表达式处理,于是参考 http://blog.sina.com.cn/s/blog_933dc4350100x6mu.html 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# coding=utf-8
'''
@CreateDate: 2013年 12月 03日 星期二 11:11:39 CST
@FileName:extract.py
@Description:负责对话中产品型号的提取
'''
import re
#restr = r"型号 : (.*), 数量"
restr = u"型号 : (.*), 数量"
p_tem = re.compile(restr, re.I)
numstr = r"^d+.d+"
p_num = re.compile(numstr,re.I)
numstrt = r"^d+*d+"
p_numt = re.compile(numstr,re.I)
timestr = r"^d+:d+:d+"
p_time = re.compile(timestr,re.I)
def is_numt(strs):
if p_numt.findall(strs):
return True
return False
def is_time(strs):
if p_time.findall(strs):
return True
return False
def is_num(strs):
if p_num.findall(strs):
return True
else:
return False
def get_type(temp_str):
'''从回答模版中提取型号
'''
#temp_str = temp_str.encode('utf-8')
types = p_tem.findall(temp_str)
return types
def is_zh(c):
'''判断c是否是中文字符,这里的c必须是unicode编码后的
'''
x = ord(c) # 转换ascii码
# Punct & Radicals
if x >= 0x2e80 and x <= 0x33ff:
return True
# Fullwidth Latin Characters
elif x >= 0xff00 and x <= 0xffef:
return True
# CJK Unified Ideographs &
# CJK Unified Ideographs Extension A
elif x >= 0x4e00 and x <= 0x9fbb:
return True
# CJK Compatibility Ideographs
elif x >= 0xf900 and x <= 0xfad9:
return True
# CJK Unified Ideographs Extension B
elif x >= 0x20000 and x <= 0x2a6d6:
return True
# CJK Compatibility Supplement
elif x >= 0x2f800 and x <= 0x2fa1d:
return True
else:
return False
def split_zh_en(zh_en_str):
'''提取非中文字符,由于不需要中文部分所以先把有关中文部分代码注释
'''
en_group = []
#zh_group = []
#zh_gather = ""
en_gather = ""
zh_status = False
for c in zh_en_str:
if not zh_status and is_zh(c):
zh_status = True
if en_gather != "":
en_group.append(en_gather)
en_gather = ""
elif not is_zh(c) and zh_status:
zh_status = False
# if zh_gather != "":
# zh_group.append(zh_gather)
if zh_status:
#zh_gather += c
pass
else:
en_gather += c
#zh_gather = ""
if en_gather != "":
en_group.append(en_gather)
# elif zh_gather != "":
# zh_group.append(zh_gather)
return en_group
if __name__ == "__main__":
#s = u"阿"
#print s, ord(s), hex(ord(s))
#m = is_zh(s)
#print m
#st = u"型号 : MAL214699112E3 , 数量 : 210片 "
#stt = u"AT45DB161E-MHD-T 2450个"
#x = split_zh_en(stt)
#print x

评论和分享

fedora19下装XMind

发布在 Linux

本来用bubbl这个在线的思维导图还凑合,不过他这个未付费用户只能存储3张,只好换回本地应用。

安装freemind很简单,直接yum即可,不过界面和功能上有待加强。

换成xmind这个强大的跨平台软件,发现只有deb包,那么想在fedora中使用进行下面操作即可:

首先,下载对应版本的deb包,32bit系统下载32bit软件包,64bit系统下载64bit软件包

ar -x xmind-xxxxx.deb解包,得到data.tar.gz 和control.tar.gz 两个归档文件

解压data.tar.gz tar xf data.tar.gz

得到一个usr文件夹,把此文件夹下的xmind子文件夹复制到/opt/文件夹下,share子文件夹移动到/usr/文件夹下和已有的share文件夹合并。命令如下

1
2
sudo cp -r usr/local/xmind/ /opt
sudo cp -r usr/share/ /usr/

解压control.tar.gz tar xf control.tar.gz 执行解压出来的postinst文件sudo sh postinst

如果出现Unknown media type in type ‘all/all’一类的提示忽略就好,据说是因为gnome和kde的问题。

接着修改/usr/share/applications/xmind.desktop文件内容为以下内容

1
2
3
4
5
6
7
8
9
10
11
[Desktop Entry]
Encoding=UTF-8
Name=XMind
Comment=Launch XMind 2013
Exec=/opt/xmind/XMind        #修改这里的位置
Terminal=false
Type=Application
Icon=/opt/xmind/xmind-logo-35.png    #修改这里的位置
StartupNotify=true
Categories=Office;
MimeType=application/xmind;

评论和分享

python线程小学习

发布在 Python

以前我写多线程程序时候,经常把一个线程类单独封装,然后使用全局锁来控制竞争资源的处理。今天看了这样一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Fetcher:
def __init__(self,threads):
self.opener = urllib2.build_opener(urllib2.HTTPHandler)
self.lock = Lock() #线程锁
self.q_req = Queue() #任务队列
self.q_ans = Queue() #完成队列
self.threads = threads
for i in range(threads):
t = Thread(target=self.threadget)
t.setDaemon(True)
t.start()
self.running = 0
def __del__(self): #解构时需等待两个队列完成
time.sleep(0.5)
self.q_req.join()
self.q_ans.join()
def taskleft(self):
return self.q_req.qsize()+self.q_ans.qsize()+self.running
def push(self,req):
self.q_req.put(req)
def pop(self):
return self.q_ans.get()
def threadget(self):
while True:
req = self.q_req.get()
with self.lock: #要保证该操作的原子性,进入critical area
self.running += 1
try:
ans = self.opener.open(req).read()
except Exception, what:
ans = ''
print what
self.q_ans.put((req,ans))
with self.lock:
self.running -= 1
self.q_req.task_done()
time.sleep(0.1) # don't spam

原文链接: http://www.pythonclub.org/python-network-application/observer-spider

从上面文章收获了不少。

把一个类作为一个线程池,进而从内部控制加锁或者释放锁,这样代码更加清晰。

评论和分享

Python 深入理解yield

发布在 Python

不知道原文出处,向原作者表示感谢。

yield的英文单词意思是生产,刚接触Python的时候感到非常困惑,一直没弄明白yield的用法。只是粗略的知道yield可以用来为一个函数返回值塞数据,比如下面的例子:

1
2
3
def addlist(alist):
for i in alist:
yield i + 1

取出alist的每一项,然后把i + 1塞进去。然后通过调用取出每一项:

1
2
3
alist = [1, 2, 3, 4]
for x in addlist(alist):
print x,

这的确是yield应用的一个例子,但是,看过limodou的文章《2.5版yield之学习心得》,并自己反复体验后,对yield有了一个全新的理解。

包含yield的函数

假如你看到某个函数包含了yield,这意味着这个函数已经是一个Generator,它的执行会和其他普通的函数有很多不同。比如下面的简单的函数:

1
2
3
4
def h():
print 'To be brave'
yield 5
h()

可以看到,调用h()之后,print 语句并没有执行!这就是yield,那么,如何让print 语句执行呢?这就是后面要讨论的问题,通过后面的讨论和学习,就会明白yield的工作原理了。

yield是一个表达式

Python2.5以前,yield是一个语句,但现在2.5中,yield是一个表达式(Expression),比如:m = yield 5

表达式(yield 5)的返回值将赋值给m,所以,认为 m = 5 是错误的。那么如何获取(yield 5)的返回值呢?需要用到后面要介绍的send(msg)方法。

透过next()语句看原理

现在,我们来揭晓yield的工作原理。我们知道,我们上面的h()被调用后并没有执行,因为它有yield表达式,因此,我们通过next()语句让它执行。next()语句将恢复Generator执行,并直到下一个yield表达式处。比如:

1
2
3
4
5
6
def h():
print 'Wen Chuan'
yield 5
print 'Fighting!'
c = h()
c.next()

c.next()调用后,h()开始执行,直到遇到yield 5,因此输出结果:Wen Chuan

当我们再次调用c.next()时,会继续执行,直到找到下一个yield表达式。由于后面没有yield了,因此会拋出异常:

1
2
3
4
5
6
Wen Chuan
Fighting!
Traceback (most recent call last):
File "/home/evergreen/Codes/yidld.py", line 11, in <module>
c.next()
StopIteration

send(msg) 与 next()

了解了next()如何让包含yield的函数执行后,我们再来看另外一个非常重要的函数send(msg)。其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。

来看这个例子:

1
2
3
4
5
6
7
8
9
def h():
print 'Wen Chuan',
m = yield 5 # Fighting!
print m
d = yield 12
print 'We are together!'
c = h()
c.next() #相当于c.send(None)
c.send('Fighting!') #(yield 5)表达式被赋予了'Fighting!'

输出的结果为:Wen Chuan Fighting!

需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。

send(msg) 与 next()的返回值

send(msg) 和 next()是有返回值的,它们的返回值很特殊,返回的是下一个yield表达式的参数。比如yield 5,则返回 5 。到这里,是不是明白了一些什么东西?本文第一个例子中,通过for i in alist 遍历 Generator,其实是每次都调用了alist.Next(),而每次alist.Next()的返回值正是yield的参数,即我们开始认为被压进去的东东。我们再延续上面的例子:

1
2
3
4
5
6
7
8
9
10
def h():
print 'Wen Chuan',
m = yield 5 # Fighting!
print m
d = yield 12
print 'We are together!'
c = h()
m = c.next() #m 获取了yield 5 的参数值 5
d = c.send('Fighting!') #d 获取了yield 12 的参数值12
print 'We will never forget the date', m, '.', d

输出结果:

1
2
Wen Chuan Fighting!
We will never forget the date 5 . 12

throw() 与 close()中断 Generator

中断Generator是一个非常灵活的技巧,可以通过throw抛出一个GeneratorExit异常来终止Generator。Close()方法作用是一样的,其实内部它是调用了throw(GeneratorExit)的。我们看:

1
2
3
4
5
6
7
8
def close(self):
try:
self.throw(GeneratorExit)
except (GeneratorExit, StopIteration):
pass
else:
raise RuntimeError("generator ignored GeneratorExit")
# Other exceptions are not caught

因此,当我们调用了close()方法后,再调用next()或是send(msg)的话会抛出一个异常:

1
2
3
4
Traceback (most recent call last):
File "/home/evergreen/Codes/yidld.py", line 14, in <module>
d = c.send('Fighting!') #d 获取了yield 12 的参数值12
StopIteration</pre>

评论和分享

Python关键字yield详解

发布在 Python

伯乐在线 –刘志军编译自stackoverflow Python标签中投票率最高的一个问题《The Python yield keyword explained》,e-satis 详细回答了关于yield 以及 generator、iterable、iterator、iteration之间的关系。

迭代器(Iterator)

为了理解yield是什么,首先要明白生成器(generator)是什么,在讲生成器之前先说说迭代器(iterator),当创建一个列表(list)时,你可以逐个的读取每一项,这就叫做迭代(iteration)。

1
2
3
4
5
6
mylist = [1, 2, 3]
for i in mylist :
print(i)
1
2
3

Mylist就是一个迭代器,不管是使用复杂的表达式列表,还是直接创建一个列表,都是可迭代的对象。

1
2
3
4
5
6
mylist = [x*x for x in range(3)]
for i in mylist :
print(i)
0
1
4

你可以使用“for··· in ···”来操作可迭代对象,如:list,string,files,这些迭代对象非常方便我们使用,因为你可以按照你的意愿进行重复的读取。但是你不得不预先存储所有的元素在内存中,那些对象里有很多元素时,并不是每一项都对你有用。

生成器(Generators)

生成器同样是可迭代对象,但是你只能读取一次,因为它并没有把所有值存放内存中,它动态的生成值:

1
2
3
4
5
6
mygenerator = (x*x for x in range(3))
for i in mygenerator :
print(i)
0
1
4

使用()和[]结果是一样的,但是,第二次执行“ for in mygenerator”不会有任何结果返回,因为它只能使用一次。首先计算0,然后计算1,之后计算4,依次类推。

Yield

Yield是关键字, 用起来像return,yield在告诉程序,要求函数返回一个生成器。

1
2
3
4
5
6
7
8
9
10
11
12
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,首先必须理解的是:当你调用生成器函数的时候,如 上例中的createGenerator(),程序并不会执行函数体内的代码,它仅仅只是返回生成器对象,这种方式颇为微妙。函数体内的代码只有直到每次 循环迭代(for)生成器的时候才会运行。 函数第一次运行时,它会从函数开始处直到碰到yield时,就返回循环的第一个值,然后,交互的运行、返回,直到没有值返回为止。如果函数在运行但是并没有遇到yield,就认为该生成器是空,原因可能是循环终止,或者没有满足任何”if/else”。

接下来读一小段代码来理解生成器的优点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
>>> class Bank(): # 创建银行,构造ATM机
... crisis = False
... def create_atm(self) :
... while not self.crisis :
... yield "$100"
>>> hsbc = Bank() # 没有危机时,你想要多少,ATM就可以吐多少
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # 危机来临,银行没钱了
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.ceate_atm() # 新建ATM,银行仍然没钱
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # 麻烦就是,即使危机过后银行还是空的
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # 构造新的ATM,恢复业务
>>> for cash in brand_new_atm :
... print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100

对于访问控制资源,生成器显得非常有用。

迭代工具,你最好的朋友

迭代工具模块包含了操做指定的函数用于操作迭代器。想复制一个迭代器出来?链接两个迭代器?以one liner(这里的one-liner只需一行代码能搞定的任务)用内嵌的列表组合一组值?不使用list创建Map/Zip?···,你要做的就是 import itertools,举个例子吧: 四匹马赛跑到达终点排名的所有可能性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]

理解迭代的内部机制:

迭代(iteration)就是对可迭代对象(iterables,实现了__iter__()方法)和迭代器(iterators,实现了__next__()方法)的一个操作过程。可迭代对象是任何可返回一个迭代器的对象,迭代器是应用在迭代对象中迭代的对象,换一种方式说的话就 是:iterable对象的__iter__()方法可以返回iterator对象,iterator通过调用next()方法获取其中的每一个值(译者 注),读者可以结合Java API中的 Iterable接口和Iterator接口进行类比。
http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/ 这篇循序渐进,讲的挺好的。顺便分享下。

评论和分享

  • 第 1 页 共 1 页
作者的图片

Roy

微信公众号:hi-roy


野生程序猿


China