LittleQ

爱好:写代码

IDEA相比Eclipse的好处我这里就不多说了,反正感觉无论是界面还是与其他插件的集成都做的非常好,特别是git和数据库这块,做的时想当好。

安装

首先根据系统下载对应IDEA的压缩包,以Ubuntu 14.04的64位系统为例

1
2
3
sudo tar -xvf ideaIU-14.0.3.tar.gz -C /usr/dev
cd /usr/dev/idea-IU-139.1117.1/bin
./idea.sh

注意:正常情况下,在你启动成功之后,可以在Ubuntu应用里直接启动,但是我的总是不行,没办法,在用户根目录下建了一个脚本,内容如下:

1
2
#!/bin/sh
/usr/dev/idea-IU-139.1117.1/bin/idea.sh &

然后对脚本赋可执行权限

常用配置

必装插件:

1
2
3
Eclipse Code Formatter
Lombok plugin
Vim Emulation

激活服务器搭建:http://blog.lanyus.com/archives/174.html

无法切换中文输入法

修改启动脚本/usr/dev/idea-IU-139.1117.1/bin/idea.sh,头部加入下面几行:

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

前提是你用的是fcitx架构的输入法.

序列化ID警告

I am not sure if you have an old version of IntelliJ but If I go File => Settings… => Inspections => Serialization issues => Serializable class without ‘serialVersionUID’ enabled, the class you provide give me warnings

文件头模板d定制

文件上右击–New–Edit File Templates–Includes–File Header

首先测试一下电脑安装git没有

1
git --version

安装git

没有安装按照以下步骤来:

1
sudo apt-get install git-core git-gui git-doc gitk

安装完毕看看是否安装成功,如果安装成功的版本低于1.9.5则说明Ubuntu版本太低,进行如下操作:

1
2
3
sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

安装成功之后再次测试,版本就应该是比较高了。

配置git

基本配置

1
2
3
4
5
6
7
git config --global user.name "zhang.san"             # 请换成你自己的名字,除非你凑巧也叫zhang.san
git config --global user.email "zhang.san@163.com" # 同上
git config --global merge.tool "kdiff3" # 要是没装KDiff3就不用设这一行
git config --global push.default simple # 要是你非要用低版本的Git(比如1.7.x),好吧,那就不设simple设current,否则你的Git不支持
git config --global core.autocrlf false # 让Git不要管Windows/Unix换行符转换的事
git config --global gui.encoding utf-8 # 避免git gui中的中文乱码
git config --global core.quotepath off # 避免git status显示的中文文件名乱码

如果你不习惯使用Vim,可以修改git默认的编辑器

1
git config --global core.editor nano

设置SSH

要和git服务器打交道,还要设置ssh,如果你之前已经有则不需要再次生成,命令:

1
ssh-keygen -t rsa -C "zhang.san@163.com"

然后一路回车,不要输入任何密码之类,生成ssh key pair。如果在Linux上,需要把其中的私钥告诉本地系统

1
ssh-add ~/.ssh/id_rsa

查看公钥内容

1
cat ~/.ssh/id_rsa.pub

最后把公钥的内容复制到git服务器上,以github为例
登陆github,在Settings-->SSH keys--> Add SSH key,把公钥的内容复制到key里面,title不用管。(windows下的用户目录找到.ssh文件夹进去就可以看到)的内容paste进去。不需要填title,title会自动生成。
要是Git服务器报“不是有效的key”之类的错误,可能是你没去除注意去除多余的回车符,也可能是paste之前copy的时候,没copy最开头的ssh-rsa这几个字。
测试一下成功了没

1
2
3
ssh -T git@github.com
Warning: Permanently added the RSA host key for IP address '192.30.252.129' to the list of known hosts.
Hi zhang.san! You've successfully authenticated, but GitHub does not provide shell access.

前面的文章介绍了如何安装hexo和使用hexo,但是关于hexo的常用配置,还是需要自己折腾一下。

给文章添加分类

在根目录下的scaffolds目录下,修改post.md文件,内容改为如下:

1
2
3
4
5
title: {{ title }}
date: {{ date }}
tags:
categories:
---

注意: 目前貌似标签可以有很多个,语法类似于tags: [tag1,tag2,tag3]这样,但是分类好像只能填一个,类似于categories: 测试

更换Hexo博客模板

这里以Jackman配置为例,首先在github官网下载主题

1
git clone https://github.com/wuchong/jacman.git themes/jacman

NOTE: 百度云备份地址,提取密码:s7r6。

themes文件夹下的jacman文件夹复制到你的Hexo项目的themes文件夹下面

1
2
cd themes
sudo mv jacman ~/Documents/blog/themes

然后修改blog文件夹下的_config.yml文件:

1
2
3
4
# Extensions
## Plugins: http://hexo.io/plugins/
## Themes: http://hexo.io/themes/
theme: landscape

theme:landscape修改为theme:jacman

Hexo使用公式

我是使用的jacman的主题,这个主题使用公式很简单,只需要修改主题文件夹下的_config.yml文件即可.具体为修改themes/jacman/_config.yml文件.
将文件中的:

1
2
close_aside: false  #close sidebar in post page if true
mathjax: false #enable mathjax if true

里的mathjax对应的值改为true就可以了,测试一下:
$$E=MC^2$$
公式写法参见MathJax使用LaTeX语法编写数学公式教程

Hexo常见为题

  • Error: watch ENOSPC
1
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

先申明,如果你不是非常需要和服务器以及服务器上的日志打交道,其实vim只会简单的光标移动以及插入,删除,复制,粘贴,保存即可。学习Vim和学习乐器很像,需要很长时间的练习,如果你平时很少用到vim,我建议是不用学的太深入,懂一些简单的即可。如果需要经常和日志打交道,那么,好好学学Vim,这可以很大的提升你的工作效率,当然学习成本很大。

初级命令

Ubuntu系统都自带了vi,你可以把Vim看成是Vi的升级版,Vim兼容Vi的所有命令,虽然vi
也可以用,但是有个不太好的地方,当你想在Vi打开的文件中插入东西时,它并没有提示,也就是不太好分清Normal模式和Insert模式,这个很容易搞混,一般就是多按几下Esc来确保是在Normal模式。所以我还是建议安装一个Vim。

简单认识vim

当你安装好Vim之后,一定项输入点东西,很多新手也就在这里止步了,很多人都不知道如何在Vim中插入字符,所以Vim给很多人的第一印象是难用,甚至不如记事本好用,其实Vim不是这样的,安装好之后,请按照下面的命令操作:

  1. 启动Vim后,Vim在Normal模式下
  2. 按下i,进入Insert模式,这时Vim左下角会出现-- INSERT --,这个时候你可以像使用记事本那样,输入你想要输入的东西
  3. Esc,可以从Insert模式返回到Normal模式

现在你已经掌握了基本的在Normal和Insert模式的切换了,下面是一些比较常用的命令:

1
2
3
4
5
i    # Insert 模式,按Esc返回Normal模式
x # 删除当前光标所在的一个字符,你也可以试试delete键,效果是一样的
:wq # 保存并且退出
dd # 删除光标所在那一行
p # 粘贴剪贴板

注意: :w存盘,后面也可以跟文件名 空格隔开。:q退出

移动光标

Vim里移动光标有三种方式

  • 第一种:当然是用鼠标了,还可以用滚轮就不说了
  • 第二种:←↓↑→,最简单易记的移动光标方式
  • 第三种:hjkl,最常用的使用方式

但是,最常用的其实是第三种,想想你为什么要放弃那么多好用的编辑器甚至IDE,其实很重要的一个理由是,用Vim可以做到基本不用鼠标,毕竟程序员需要频繁的在键盘和鼠标之间切换,有时候如果键盘可以完成的事,都是懒得去用鼠标点的,所以日常操作也会记一些经常用到的系统快捷键,所以,这里道理一样,并且使用←↓↑→,手指并不是很方便,所以大家习惯了使用hjkl。确实有点不好记,不过熟了就习惯了,有个技巧就是:j看上去像一个向下的箭头。

建议:如果你不长用Vim,或者写代码的机会不是那么多,那么你只需要记住上面的几个命令就足够了,这几个命令可以让你能基本使用Vim来编辑文件,做简单的修改。再说个题外话,一般的编辑器,如果你需要拷贝一段文字的时候,一般是Ctrl-c配合Ctrl-v,Ctrl扮演的就是功能键的作用,即当功能键被按下,c便不再是c,变成了一个命令或者快捷键,在Vim的Normal模式下,所有的键都是功能键

中级命令

下面在介绍的时候,多半是一些快捷键,如果是Ctrl-key,统一写成<C-key>。并且以:开始的命令需要输入回车,例如退出命令::q<enter>
为了更高效的使用Vim,一些简单的命令还是不行的,拿还不如使用IDE和其他文本编辑器更加方便,以下所有的命令都是在Normal模式下输入的,如果不确定是不是在Normal下,多敲几下Esc键。

  • 各种插入模式
1
2
3
4
a	# 在光标后插入
o # 在光标所在行后免插入一个新行
O # 大写字母o,表示在光标所在行前插入一个新行
cw # 替换光标所在位置后一直到光标所在单词结尾的字符,就是删除掉
  • 各种移动光标
1
2
3
4
5
0		# 数字0,到行头
^ # 到本行第一个不是空白的位置,空白包括空格,tab,换行,回车等
$ # 到本行行尾
g_ # 到本行最后一个不是空白的位置
/pattern # 搜索pattern的字符串,多个匹配可以按n跳到下一个
  • 拷贝/粘贴
1
2
3
p		# 粘贴,在当前位置之后粘贴
P # 粘贴,在当前位置之前粘贴
yy # 拷贝当前行
  • 撤销/重做
1
2
u		# undo 撤销
<C-r> # redo 重做
  • 打开/保存/退出/改变文件
1
2
3
4
5
6
7
8
9
10
:e <path/to/file>		# 打开一个文件,空格隔开
:w # 存盘
:saveas <path/to/file> # 另存为<path/to/file> 空格隔开
:x # 保存并退出
ZZ # 保存并退出
:wq # 保存并退出
:q! # 退出,但不保存
:qa! # 强行退出所有正在编辑的文件
:bn # 切换到打开的下一个文件
:bp # 切换到挡开的上一个文件

注意: 其实只是切换文件可以用:n,表示到下一个文件。

高效命令

在处理文本的时候,有时候需要做很多重复的动作,下面来看看Vim如何重复自己

  • 重复命令
1
2
.		# 小数点,可以重复上一次命令,当然你要记住上次你干了啥
N<command> # 重复某个命令N次,N为数字,命令要是有效的vim命令

看看示例:

1
2
3
4
dd			# 删除一行,并且删除的内容会存放到剪贴板
2dd # 2dd表示删除从光标开始的两行
3p # 粘贴文本3次,内容是剪贴板的内容,假设先执行了2dd,再3p,则会粘贴6行新内容
100icontent [Esc] # 中间有个空格 插入100遍content<space>

注意: 如果在100icontent [Esc]之后在输入小数点.。那么会再插入100遍content<space>,即重复上条命令。如果再输入3.`,会再输入3个content

  • 更快的移动光标
1
2
3
4
5
NG		# 到第N行,G必须大写
gg # 到第一行
G # 到最后一行
w # 到下一个单词的开头
e # 到下一个单词的结尾

注意: 默认情况,单词是由字母,数字,下划线组成,如果认为是blank字符分隔,则需要使用EW,如下如所示:
e,w和E,W区别

其实这并不是最强的光标移动,下面来看看最快的光标如何移动:

1
2
3
%		# 匹配括号移动,包括(,{,[,这个对于编程来匹配括号非常好用,记住你需要把光标先移到括号上,然后就可以匹配到与之对应的反括号
* # 匹配光标当前所在单词,移动到下一个,以blank字符为分隔符
# # 匹配光标当前所在单词,移动到上一个,以blank字符为分隔符
  • 选中

一定要记住光标的移动快捷键,很多命令可以通过光标的移动来实现联动,比如从某个地方拷贝到某个地方,删除从某个位置到另一个位置,语法类似下面

command

例如:0y$命令意味着:

0 # 先到行头
y # 从光标处开始拷贝
$ # 拷贝到本行最后一个字符

类似这样的命令还有:ye,从当前位置拷贝到本单词的最后一个字符。y2/foo,拷贝两个foo之间的字符串。不一定按y才会拷贝,下面的命令也会拷贝:

1
d		# 删除

常用命令

1
2
3
:g/^$/de		# 删除空白行
:set encoding # 查看文件编码
:set list # 显示不可见字符,一般来看每一行结尾是否有空格

最近刚接触数据处理,线上的服务器有大概10台,并且hadoopHive的数据非常多,有些数据需要迁移,首先要登陆跳板机,然后跳板机再登陆线上的机器,这样切换非常麻烦,多个终端窗口切换非常乱,所以找了一下如何使用一款多窗口终端软件

Terminator(终结者)

终端安装

1
2
3
4
5
sudo apt-get install terminator
cd ~/.config/
sudo mkdir terminator
cd terminator
sudo touch config

安装完了之后,打开一个窗口,类似于下面:
Terminator 窗口

修改默认配置

下面配置一下这个终端的颜色,我使用solarized配色,修改配置文件:

1
sudo subl ~/.config/terminator/config

sublSublime Text 3编辑器,用你有的工具修改即可,把文件内容替换成如下:

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
[global_config]
title_transmit_bg_color = "#d30102"
focus = system
[keybindings]
[profiles]
[[default]]
# solarized-dark
#palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3"
#foreground_color = "#eee8d5"
#background_color = "#002b36"
#cursor_color = "#eee8d5"

[[solarized-dark]]
palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3"
foreground_color = "#eee8d5"
background_color = "#002b36"
cursor_color = "#eee8d5"

[[solarized-light]]
palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3"
background_color = "#eee8d5"
foreground_color = "#002b36"
cursor_color = "#002b36"

[layouts]
[[default]]
[[[child1]]]
type = Terminal
parent = window0
profile = solarized-dark
[[[window0]]]
type = Window
parent = ""
[plugins]

或者还可以直接导入配置:

1
2
sudo apt-get install curl
curl https://raw.githubusercontent.com/ghuntley/terminator-solarized/master/config > ~/.config/terminator/config

NOTE: 这个配置项目的github 地址有可能会变动,如果不行可以复制我的配置文件内容,按前一种方式修改即可,,我的配置文件如下:

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
[global_config]
title_transmit_bg_color = "#d30102"
focus = system
suppress_multiple_term_dialog = True
[keybindings]
[profiles]
[[default]]
palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3"
copy_on_selection = True
background_image = None
background_darkness = 0.95
background_type = transparent
use_system_font = False
cursor_color = "#eee8d5"
foreground_color = "#839496"
show_titlebar = False
font = Monospace 11
background_color = "#002b36"
[[solarized-dark]]
palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3"
background_color = "#002b36"
background_image = None
cursor_color = "#eee8d5"
foreground_color = "#839496"
[[solarized-light]]
palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3"
background_color = "#fdf6e3"
background_image = None
cursor_color = "#002b36"
foreground_color = "#657b83"
[layouts]
[[default]]
[[[child1]]]
type = Terminal
parent = window0
profile = default
[[[window0]]]
type = Window
parent = ""
[plugins]

更换目录配色方案

不过这个主题在文件和文件夹的颜色上区分不明显,都是灰色的,配置目录的颜色,修改目录配色:

1
curl https://raw.githubusercontent.com/seebi/dircolors-solarized/master/dircolors.ansi-dark > ~/.dircolors

吐过下载不下来,同样可以自己建一个文件叫.dircolors,内容如下:

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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# Below, there should be one TERM entry for each termtype that is colorizable
TERM ansi
TERM color_xterm
TERM color-xterm
TERM con132x25
TERM con132x30
TERM con132x43
TERM con132x60
TERM con80x25
TERM con80x28
TERM con80x30
TERM con80x43
TERM con80x50
TERM con80x60
TERM cons25
TERM console
TERM cygwin
TERM dtterm
TERM dvtm
TERM dvtm-256color
TERM Eterm
TERM eterm-color
TERM fbterm
TERM gnome
TERM gnome-256color
TERM jfbterm
TERM konsole
TERM konsole-256color
TERM kterm
TERM linux
TERM linux-c
TERM mach-color
TERM mlterm
TERM nxterm
TERM putty
TERM putty-256color
TERM rxvt
TERM rxvt-256color
TERM rxvt-cygwin
TERM rxvt-cygwin-native
TERM rxvt-unicode
TERM rxvt-unicode256
TERM rxvt-unicode-256color
TERM screen
TERM screen-16color
TERM screen-16color-bce
TERM screen-16color-s
TERM screen-16color-bce-s
TERM screen-256color
TERM screen-256color-bce
TERM screen-256color-s
TERM screen-256color-bce-s
TERM screen-256color-italic
TERM screen-bce
TERM screen-w
TERM screen.linux
TERM screen.xterm-256color
TERM screen.xterm-new
TERM st
TERM st-meta
TERM st-256color
TERM st-meta-256color
TERM vt100
TERM xterm
TERM xterm-new
TERM xterm-16color
TERM xterm-256color
TERM xterm-256color-italic
TERM xterm-88color
TERM xterm-color
TERM xterm-debian
TERM xterm-termite

# EIGHTBIT, followed by '1' for on, '0' for off. (8-bit output)
EIGHTBIT 1

#############################################################################
# Below are the color init strings for the basic file types. A color init
# string consists of one or more of the following numeric codes:
#
# Attribute codes:
# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
# Text color codes:
# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
# Background color codes:
# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
#
# NOTES:
# - See http://www.oreilly.com/catalog/wdnut/excerpt/color_names.html
# - Color combinations
# ANSI Color code Solarized Notes Universal SolDark SolLight
# ~~~~~~~~~~~~~~~ ~~~~~~~~~ ~~~~~ ~~~~~~~~~ ~~~~~~~ ~~~~~~~~
# 00 none NORMAL, FILE <SAME> <SAME>
# 30 black base02
# 01;30 bright black base03 bg of SolDark
# 31 red red docs & mm src <SAME> <SAME>
# 01;31 bright red orange EXEC <SAME> <SAME>
# 32 green green editable text <SAME> <SAME>
# 01;32 bright green base01 unimportant text <SAME>
# 33 yellow yellow unclear in light bg multimedia <SAME> <SAME>
# 01;33 bright yellow base00 fg of SolLight unimportant non-text
# 34 blue blue unclear in dark bg user customized <SAME> <SAME>
# 01;34 bright blue base0 fg in SolDark unimportant text
# 35 magenta magenta LINK <SAME> <SAME>
# 01;35 bright magenta violet archive/compressed <SAME> <SAME>
# 36 cyan cyan DIR <SAME> <SAME>
# 01;36 bright cyan base1 unimportant non-text <SAME>
# 37 white base2
# 01;37 bright white base3 bg in SolLight
# 05;37;41 unclear in Putty dark


### By file type

# global default
NORMAL 00
# normal file
FILE 00
# directory
DIR 34
# 777 directory
OTHER_WRITABLE 34;40
# symbolic link
LINK 35

# pipe, socket, block device, character device (blue bg)
FIFO 30;44
SOCK 35;44
DOOR 35;44 # Solaris 2.5 and later
BLK 33;44
CHR 37;44


#############################################################################
### By file attributes

# Orphaned symlinks (blinking white on red)
# Blink may or may not work (works on iTerm dark or light, and Putty dark)
ORPHAN 05;37;41
# ... and the files that orphaned symlinks point to (blinking white on red)
MISSING 05;37;41

# files with execute permission
EXEC 01;31 # Unix
.cmd 01;31 # Win
.exe 01;31 # Win
.com 01;31 # Win
.bat 01;31 # Win
.reg 01;31 # Win
.app 01;31 # OSX

#############################################################################
### By extension

# List any file extensions like '.gz' or '.tar' that you would like ls
# to colorize below. Put the extension, a space, and the color init string.
# (and any comments you want to add after a '#')

### Text formats

# Text that we can edit with a regular editor
.txt 32
.org 32
.md 32
.mkd 32

# Source text
.h 32
.c 32
.C 32
.cc 32
.cpp 32
.cxx 32
.objc 32
.sh 32
.bash 32
.csh 32
.zsh 32
.el 32
.vim 32
.java 32
.pl 32
.pm 32
.py 32
.rb 32
.hs 32
.php 32
.htm 32
.html 32
.shtml 32
.erb 32
.haml 32
.xml 32
.rdf 32
.css 32
.sass 32
.scss 32
.less 32
.js 32
.coffee 32
.man 32
.0 32
.1 32
.2 32
.3 32
.4 32
.5 32
.6 32
.7 32
.8 32
.9 32
.l 32
.n 32
.p 32
.pod 32
.tex 32
.go 32
.sql 32

### Multimedia formats

# Image
.bmp 33
.cgm 33
.dl 33
.dvi 33
.emf 33
.eps 33
.gif 33
.jpeg 33
.jpg 33
.JPG 33
.mng 33
.pbm 33
.pcx 33
.pdf 33
.pgm 33
.png 33
.PNG 33
.ppm 33
.pps 33
.ppsx 33
.ps 33
.svg 33
.svgz 33
.tga 33
.tif 33
.tiff 33
.xbm 33
.xcf 33
.xpm 33
.xwd 33
.xwd 33
.yuv 33

# Audio
.aac 33
.au 33
.flac 33
.m4a 33
.mid 33
.midi 33
.mka 33
.mp3 33
.mpa 33
.mpeg 33
.mpg 33
.ogg 33
.ra 33
.wav 33

# Video
.anx 33
.asf 33
.avi 33
.axv 33
.flc 33
.fli 33
.flv 33
.gl 33
.m2v 33
.m4v 33
.mkv 33
.mov 33
.MOV 33
.mp4 33
.mp4v 33
.mpeg 33
.mpg 33
.nuv 33
.ogm 33
.ogv 33
.ogx 33
.qt 33
.rm 33
.rmvb 33
.swf 33
.vob 33
.webm 33
.wmv 33

### Misc

# Binary document formats and multimedia source
.doc 31
.docx 31
.rtf 31
.odt 31
.dot 31
.dotx 31
.ott 31
.xls 31
.xlsx 31
.ods 31
.ots 31
.ppt 31
.pptx 31
.odp 31
.otp 31
.fla 31
.psd 31

# Archives, compressed
.7z 1;35
.apk 1;35
.arj 1;35
.bin 1;35
.bz 1;35
.bz2 1;35
.cab 1;35 # Win
.deb 1;35
.dmg 1;35 # OSX
.gem 1;35
.gz 1;35
.iso 1;35
.jar 1;35
.msi 1;35 # Win
.rar 1;35
.rpm 1;35
.tar 1;35
.tbz 1;35
.tbz2 1;35
.tgz 1;35
.tx 1;35
.war 1;35
.xpi 1;35
.xz 1;35
.z 1;35
.Z 1;35
.zip 1;35

# For testing
.ANSI-30-black 30
.ANSI-01;30-brblack 01;30
.ANSI-31-red 31
.ANSI-01;31-brred 01;31
.ANSI-32-green 32
.ANSI-01;32-brgreen 01;32
.ANSI-33-yellow 33
.ANSI-01;33-bryellow 01;33
.ANSI-34-blue 34
.ANSI-01;34-brblue 01;34
.ANSI-35-magenta 35
.ANSI-01;35-brmagenta 01;35
.ANSI-36-cyan 36
.ANSI-01;36-brcyan 01;36
.ANSI-37-white 37
.ANSI-01;37-brwhite 01;37

#############################################################################
# Your customizations

# Unimportant text files
# For universal scheme, use brightgreen 01;32
# For optimal on light bg (but too prominent on dark bg), use white 01;34
.log 01;32
*~ 01;32
*# 01;32
#.log 01;34
#*~ 01;34
#*# 01;34

# Unimportant non-text files
# For universal scheme, use brightcyan 01;36
# For optimal on dark bg (but too prominent on light bg), change to 01;33
#.bak 01;36
#.BAK 01;36
#.old 01;36
#.OLD 01;36
#.org_archive 01;36
#.off 01;36
#.OFF 01;36
#.dist 01;36
#.DIST 01;36
#.orig 01;36
#.ORIG 01;36
#.swp 01;36
#.swo 01;36
#*,v 01;36
.bak 01;33
.BAK 01;33
.old 01;33
.OLD 01;33
.org_archive 01;33
.off 01;33
.OFF 01;33
.dist 01;33
.DIST 01;33
.orig 01;33
.ORIG 01;33
.swp 01;33
.swo 01;33
*,v 01;33

# The brightmagenta (Solarized: purple) color is free for you to use for your
# custom file type
.gpg 34
.gpg 34
.pgp 34
.asc 34
.3des 34
.aes 34
.enc 34
.sqlite 34


修改~/.bashrc配置,我安装了oh-my-zsh,所以我修改的文件是~/.zshrc。加入如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'

alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi

# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

dircolors-solarized github地址最后效果如下:
dircolors-solarized配色

分屏操作

在终端上的某个终端窗口右键,就可以Split Horizontally以及Split Vertically进行屏幕分割,这个操作可以类推,效果类似于:
最终分屏效果

使用Python连接数据库,需要安装MySQLdb模块。

系统:Ubuntu 14.04 64bit
mysql:Server version: 5.5.44-0ubuntu0.14.04.1 (Ubuntu)

最近在进行数据迁移,把常用的Hive命令整理一下。

导入分区数据

把一个Hive表中的数据导入到另一个表中,但是这两个表都是有分区的,需要动态导入,假设想把表table_a的数据导入到表table_b。这两个表都是按照时间分区的,例如表A的建表语句如下:

1
2
3
4
5
6
7
8
CREATE TABLE table_a (
id int,
name string comment '姓名',)
comment '表A'
PARTITIONED BY (dt string)
ROW format delimited fields terminated by '\t'
lines terminated by '\n'
stored as textfile;

现在新建一个表B,建表语句和表A完全一样,把表A的数据导入到表B,可以这么做:

1
2
INSERT OVERWRITE TABLE table_b partition(dt)
select * from table_a

终端命令

  • 登陆Hive
1
sudo -u${user_name} /home/q/hive/hive-0.12.0/bin/hive -database database_name

修改命令

  • 重命名表名
1
alter table table_name rename to new_table_name
  • 重命名分区
1
alter table table_name partition(dt='20151014') rename to partition(dt='20151014old');
  • 删除表
1
drop table if exists table_name;
  • 删除/添加分区
1
2
3
alter table table_name drop partition(dt='20151014');
alter table table_name add if not exists partition(dt='20151018');
alter table table_name add if not exists partition(dt<'20151018'); # 批量删除分区
  • 清空表数据
1
insert overwrite table table_name select * from table_name where 1=0;
  • 删除指定条件的数据
1
2
3
4
# 把Hive表中link_end_date字段为'2099-12-31'的数据删掉,即只要不等于这个值就再插回源表中
insert overwrite table ap_fuwu_tb_complaint_his
select * from ap_fuwu_tb_complaint_his where
link_end_date<>'2099-12-31';
  • 将数据插入到指定分区
1
2
3
alter table table_name add if not exists partition(dt='20151021old');
insert overwrite table table_name partition(dt='20151021old')
SELECT * FROM table_name WHERE dt='20151021';

注意: 如果列不等,则把*换成对应的列。

  • 重命名列名
1
2
3
4
5
6
7
8
alter table table_name CHANGE old_col_name new_col_name field_type;

# 表结构列替换,通常用于
alter table table_name replace columns (
col_name data_type [comment col_comment],
col_name data_type [comment col_comment],
col_name data_type [comment col_comment]
);
  • 改变列顺序
1
2
# 把old_col_name改名为new_col_name并且把这列放在another_col_name列后面
alter table table_name CHANGE old_col_name new_col_name field_type after another_col_name;
  • 复制表
1
2
create table new_table like old_table;	# 只复制表结构,不复制数据
create table new_table as select * from old_table; # 复制数据

**注意:**对于分区表,如果使用create table xxx as select * from xxx这样新表就不是分区表了,分区字段会作为一个字段插入到新表中。
所以如果想保证新表也是分区表,需要下面这样,假设分区字段为dt

1
2
create table new_table like old_table;
insert overwrite table new_table partition(dt) select * from old_table;

展示信息命令

  • 展示建表语句
1
show create table table_name;
  • 展示表详情
1
desc table_name;
  • 模糊查询

使用like可以进行模糊查询使用like可以进行模糊查询,其中_表示单个字符,%表示任意数量的字符.要注意如果是用否定,语法是:

1
2
# 语法类似下面这样
select * from table where NOT 'key' like 'fff%';

RLIKE:

1
2
3
4
# 字符串a符合java正则表达式b的正则语法则返回true
# 语法:A rlike b
hive> select 1 from tabe_name where 'footbar' rlike '^f.*r$’;
1

还有个和rlike功能一样的操作:REGEXP

1
2
hive> select 1 from table_name where 'footbar' REGEXP '^f.*r$';
1

查看命令

  • 查看Hive表大小
1
2
hadoop fs -ls  /user/hive/warehouse/test_table/ds=20151111|awk -F ' ' '{print $5}'|awk '{a+=$1}END{print a/(1024*1024*1024)}'
hadoop fs -du /user/hive/warehouse/test_table|awk ' { SUM += $1 } END { print SUM/(1024*1024*1024)}'

Python崇尚的是代码越少越好,借鉴了其他各类语言的特性,另外考虑到日常编程中的一些非常繁琐的操作,Python对有一些非常常用的操作提供了简单的实现。

Python高级特性

切片

取一个listtuple中的部分元素,当然其他语言,例如java也可以使用截取函数,传入区间进行截取,但是Python提供了一个更简单的操作

1
2
3
>>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> L[0:3]
['Michael', 'Sarah', 'Tracy']

注意,3表示的不是截取的元素个数,而是索引结束位置,即不包括索引为3的元素,如果开始索引为0,还可以省略

1
2
3
4
>>> L[1:3]
['Sarah', 'Tracy']
>>> L[:3]
['Michael', 'Sarah', 'Tracy']

前面也提到过,Python取元素还支持L[-1]这种取倒数第一个元素的操作

1
2
3
4
>>> L[-2:]
['Bob', 'Jack']
>>> L[-2:-1]
['Bob']

L[:],这个表示复制一个list,其实就是默认把整个list切片。

迭代

这个和Java也差不多,在Java中也有迭代器以及foreach(element: elements)这种循环语句,在Python中,使用for ... in

1
2
3
4
5
6
>>> for ch in 'abc':
... print ch
...
a
b
c

默认情况下,dict通过key迭代。也可以通过value来迭代:for value in d.itervalues()。也可以同时迭代keyvaluefor k, v in d.iteritems()
所以,只要判断一个对象是可迭代对象就可以使用for ... in这种循环,通过collections模块的Iterable类型判断:

1
2
3
4
5
6
7
>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整数是否可迭代
False

有时候也需要里列表里的下标,这点Python也提供了一个内置的enumerate函数,可以把一个list变成索引-元素对,这样就可以做到在for循环中迭代索引和元素本身。

1
2
3
4
5
6
>>> for i, value in enumerate(['A', 'B', 'C']):
... print i, value
...
0 A
1 B
2 C

还可以同时引用两个变量

1
2
3
4
5
6
>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
... print x, y
...
1 1
2 4
3 9

列表生成式

即创建列表的方式,最笨的方法就是写循环逐个生成,前面也介绍过可以使用range()函数来生成,不过只能生成线性列表,下面看看更为高级的生成方式:

1
2
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。
你甚至可以在后面加上if判断:

1
2
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

循环嵌套,全排列:

1
2
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

看一个简单应用,列出当前目录下所有文件和目录:

1
2
3
>>> import os
>>> [d for d in os.listdir('.')]
['README.md', '.git', 'image', 'os', 'lib', 'sublime-imfix', 'src']

前面也说过Python里循环中可以同时引用两个变量,所以生成变量也可以:

1
2
3
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.iteritems()]
['y=B', 'x=A', 'z=C']

也可以通过一个list生成另一个list,例如把一个list中所有字符串变为小写:

1
2
3
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']

但是这里有个问题,list中如果有其他非字符串类型,那么lower()会报错,解决办法:

1
2
3
>>> L = ['Hello', 'World', 'IBM', 'Apple', 12, 34]
>>> [s.lower() if isinstance(s,str) else s for s in L]
['hello', 'world', 'ibm', 'apple', 12, 34]

生成器

列表生成式虽然强大,但是也会有一个问题,当我们想生成一个很大的列表时,会非常耗时,并且占用很大的存储空间,关键是这里面的元素可能你只需要用到前面很少的一部分,大部分的空间和时间都浪费了。Python提供了一种边计算边使用的机制,称为生成器(Generator),创建一个Generator最简单的方法就是把[]改为()

1
2
3
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x7fe73eb85cd0>

如果要一个一个打印出来,可以通过generator的next()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> g.next()
0
>>> g.next()
1
>>> g.next()
4
>>> g.next()
9
>>> g.next()
16
>>> g.next()
25
>>> g.next()
36
>>> g.next()
49
>>> g.next()
64
>>> g.next()
81
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

其实generator object也是可迭代的,所以可以用循环打印,还不会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> g = (x * x for x in range(10))
>>> for n in g:
... print n
...
0
1
4
9
16
25
36
49
64
81

这是简单的推算算法,但是如果算法比较复杂,写在()里就不太合适了,我们可以换一种方式,使用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, …

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

1
2
3
4
5
6
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a + b
n = n + 1

上面的函数可以输出斐波那契数列的前N个数,这个也是通过前面的数推算出后面的,所以可以把函数变成generator object,只需要把print b改为yield b即可。

1
2
3
4
5
6
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1

如果一个函数定义中包含了yield关键字,这个函数就不在是普通函数,而是一个generator object

1
2
3
4
>>> fib(6)
<generator object fib at 0x7fa1c3fcdaf0>
>>> fib(6).next()
1

所以要想调用这个函数,需要使用next()函数,并且遇到yield语句返回(可以把yield理解为return):

1
2
3
4
5
6
7
def odd():
print 'step 1'
yield 1
print 'step 2'
yield 3
print 'step 3'
yield 5

看看调用输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

同样也可以改为for循环语句输出。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def odd():
print 'step 1'
yield 1
print 'step 2'
yield 2
print 'step 3'
yield 3

if __name__ == '__main__':
o = odd()
while True:
try:
print o.next()
except:
break

Python的函数定义提供了默认参数这个选择,使得函数的定义和使用更加的灵活,但是也会带来一些坑,例如之前的一个例子:
函数定义:

1
2
3
def add_end(L=[]):
L.append('END')
return L

调用函数的结果:

1
2
3
4
5
6
7
8
9
10
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

很明显这个与函数的定义初衷不符,用一句话解释就是:

Default values are computed once, then re-used.

为了深入研究这个问题,我们来看看另一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# coding=utf-8

def a():
print "a executed"
return []

def b(x=a()):
print "id(x):", id(x)
x.append(5)
print "x:", x

for i in range(2):
print "不带参数调用,使用默认参数"
b()
print b.__defaults__
print "id(b.__defaults__[0]):", id(b.__defaults__[0])

for i in range(2):
print "带参数调用,传入一个list"
b(list())
print b.__defaults__
print "id(b.__defaults__[0]):", id(b.__defaults__[0])

**NOTE:**稍微解释一下,所有默认值都存储在函数对象的__defaults__属性中,这是一个列表,每一个元素均为一个默认参数值。
来看看输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a executed
不带参数调用,使用默认参数
id(x): 140038854650552
x: [5]
([5],)
id(b.__defaults__[0]): 140038854650552
不带参数调用,使用默认参数
id(x): 140038854650552
x: [5, 5]
([5, 5],)
id(b.__defaults__[0]): 140038854650552
带参数调用,传入一个list
id(x): 140038854732400
x: [5]
([5, 5],)
id(b.__defaults__[0]): 140038854650552
带参数调用,传入一个list
id(x): 140038854732472
x: [5]
([5, 5],)
id(b.__defaults__[0]): 140038854650552

简单分析一下输出结果:

  • 第1行
    在定义函数b(),即执行def语句,代码第7行def b(x=a()):的时候,这句话使用了默认参数,所以在定义的时候会计算默认参数x的值,这个时候会调用a(),所以打印出了a executed

  • 第2~6行
    第一次执行循环,代码第14行调用b()没有传递参数,使用默认参数,此时x=[],所以调用一次之后

    1
    print b.__defaults__

    输出结果为

    1
    ([5],)
  • 第7~11行
    第二次循环,代码第14行调用b()没有传递参数,使用默认参数。
    注意:默认参数只会计算一次,也就是说那个内存区域就固定了,但是这个地址所指向的是一个list,内容可以改变,此时由于上一次调用x: [5],所以

    1
    print b.__defaults__

    输出结果为

    1
    ([5, 5],)
  • 第12~16行
    第二个循环语句,第一次循环,代码第20行传入一个空的list,所以不使用默认参数,此时x=[],所以

    1
    print b.__defaults__

    输出结果为

    1
    ([5],)
  • 第18~21行
    第二个循环语句,第二次循环,代码第20行传入一个空的list,所以也不使用默认参数,此时仍然是x=[],所以

    1
    print b.__defaults__

    输出结果依然为

    1
    ([5],)

函数也是对象,因此定义的时候就被执行,默认参数是函数的属性,它的值可能会随着函数被调用而改变。其他对象不都是如此吗?
牢记: 默认参数必须指向不变对象!代码改一下如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# coding=utf-8

def a():
print "a executed"
return None

def b(x=a()):
print "id(x):", id(x)
if x is None:
x = []
x.append(5)
print "x:", x

for i in range(2):
print "不带参数调用,使用默认参数"
b()
print b.__defaults__
print "id(b.__defaults__[0]):", id(b.__defaults__[0])

for i in range(2):
print "带参数调用,传入一个list"
b(list())
print b.__defaults__
print "id(b.__defaults__[0]):", id(b.__defaults__[0])

此时的输出结果看看是什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a executed
不带参数调用,使用默认参数
id(x): 9568656
x: [5]
(None,)
id(b.__defaults__[0]): 9568656
不带参数调用,使用默认参数
id(x): 9568656
x: [5]
(None,)
id(b.__defaults__[0]): 9568656
带参数调用,传入一个list
id(x): 140725126699632
x: [5]
(None,)
id(b.__defaults__[0]): 9568656
带参数调用,传入一个list
id(x): 140725126699704
x: [5]
(None,)
id(b.__defaults__[0]): 9568656

方法或者说函数的使用,这个和其他编程语言Java/C++没什么区别,使用正确的方法名加参数就可以,python还有一个比较人性化的地方:在交互命令行下通过help(functionName)可以查看指定函数的使用帮助。例如:

1
>>> help(range)

会出现如下内容,按q退出:

1
2
3
4
5
6
7
8
9
10
11
12
Help on built-in function range in module __builtin__:

range(...)
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers

Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
These are exactly the valid indices for a list of 4 elements.
(END)

函数

  • 定义函数
    在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
    我们以自定义一个求绝对值的my_abs函数为例:

    1
    2
    3
    4
    5
    def my_abs(x):
    if x >= 0:
    return x
    else:
    return -x
  • 空函数

    1
    2
    def nop():
    pass

    pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
    pass还可以用在其他语句里,比如:

    1
    2
    if age >= 18:
    pass

    缺少了pass,代码运行就会有语法错误。

  • 参数检查
    调用函数时,如果参数个数不对,Python解释器会自动检查出来,并抛出TypeError

    1
    2
    3
    4
    >>> my_abs(1, 2)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: my_abs() takes exactly 1 argument (2 given)

但是如果参数类型不对,Python解释器就无法帮我们检查。试试my_abs和内置函数abs的差别:

1
2
3
4
5
6
>>> my_abs('A')
'A'
>>> abs('A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

当传入了不恰当的参数时,内置函数abs会检查出参数错误,而我们定义的my_abs没有参数检查,所以,这个函数定义不够完善。

让我们修改一下my_abs的定义,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用内置函数isinstance实现:

1
2
3
4
5
6
7
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x

添加了参数检查后,如果传入错误的参数类型,函数就可以抛出一个错误:

1
2
3
4
5
>>> my_abs('A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in my_abs
TypeError: bad operand type

错误和异常处理将在后续讲到,此处只需要大概知道这个可以抛出一个异常就行了。

  • 返回多个值
    一般像Java/C++这样的语言,要想函数返回多个值,通常有两种方式:第一种,如果返回值的类型一样,那么一般就是返回一个列表或者数组对象,然后要用就去列表里取;第二种,返回值类型不一样,这种情况通常是定义一个结构体或者类来接收。但是对于Python,就不用这么麻烦了,看下面的代码:

    1
    2
    3
    4
    5
    6
    import math

    def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny

    在命令式交互行里看看返回值,xy也可以直接单独使用:

    1
    2
    3
    >>> x, y = move(100, 100, 60, math.pi / 6)
    >>> print x, y
    151.961524227 70.0

    注意:虽然可以这么用,但是具体中间的过程还必须了解,其实返回值还是单一值,看下面:

    1
    2
    3
    >>> r = move(100, 100, 60, math.pi / 6)
    >>> print r
    (151.96152422706632, 70.0)

    可以看到,返回值是一个tuple!,但是python的语法上返回一个tuple可以省略括号,同时多个变量又可以同事接收一个tuple,即相当于

    1
    x,y = r
  • 函数参数
    C++里函数可以设置缺省参数,Java不可以,只能通过重载的方式来实现,python里也可以设置默认参数,最大的好处就是降低函数难度,函数的定义只有一个,并且python是动态语言,在同一名称空间里不能有想多名称的函数,如果出现了,那么后出现的会覆盖前面的函数

    1
    2
    3
    4
    5
    6
    def power(x, n=2):
    s = 1
    while n > 0:
    n = n - 1
    s = s * x
    return s

    看看结果:

    1
    2
    3
    4
    >>> power(5)
    25
    >>> power(5,3)
    125

    注意: 必选参数在前,默认参数在后,否则Python的解释器会报错。
    建议:*当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。

默认参数也有坑,看看下面的代码,先定义一个list,添加一个end再返回:

1
2
3
def add_end(L=[]):
L.append('END')
return L

看看调用结果:

1
2
3
4
5
6
7
8
9
10
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

这里需要解释一下,Python函数在定义的时候,默认参数L的值就被计算出来了,即[]。此时L指向[]。所以如果L中的内容改变了,下次调用引用的内容也就不再是[]了。所以要牢记一点定义默认参数必须指向不可变对象!。具体想深入了解可以看看Python 默认参数陷阱

  • 可变参数
    第一种方法,传入的参数为一个list或者tuple

    1
    2
    3
    4
    5
    def calc(numbers):
    sum = 0
    for n in numbers:
    sum = sum + n * n
    return sum

    调用方式:

    1
    2
    3
    4
    >>> calc([1, 2, 3])
    14
    >>> calc((1, 3, 5, 7))
    84

    第二种方式,直接传入多个参数,函数内部会自动用一个tuple接收。

    1
    2
    3
    4
    5
    def calc(*numbers):
    sum = 0
    for n in numbers:
    sum = sum + n * n
    return sum

    调用方式:

    1
    2
    3
    4
    >>> calc(1, 2)
    5
    >>> calc()
    0

    这个时候如果还想把一个list或者tuple里的数据传进去,可以这样:

    1
    2
    3
    >>> nums = [1, 2, 3]
    >>> calc(*nums)
    14
  • 关键字参数
    关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

    1
    2
    def person(name, age, **kw):
    print 'name:', name, 'age:', age, 'other:', kw

    调用示例:

    1
    2
    3
    4
    5
    6
    >>> person('Michael', 30)
    name: Michael age: 30 other: {}
    >>> person('Bob', 35, city='Beijing')
    name: Bob age: 35 other: {'city': 'Beijing'}
    >>> person('Adam', 45, gender='M', job='Engineer')
    name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
  • 参数组合
    在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。

  • 递归函数
    基本的也没什么可讲的,和Java/C++里一样,就是调用本身的一种。这里重点介绍一下尾递归优化。事实上尾递归和循环效果是一样的,很显然的一个优点那就是可以防止递归调用栈溢出。
    定义:在函数返回的时候调用自身,并且,return语句不能包含表达式。编译器或者解释器可以对其做优化,无论调用多少次,只占用一个栈帧,不会出现溢出的情况。
    举个简单的例子,以阶乘函数为例:

    1
    2
    3
    4
    def fact(n):
    if n==1:
    return 1
    return n * fact(n - 1)

    如果传入的n很大,就可能会溢出,这是由于return n * fact(n - 1)引入了乘法表达式,就不是尾递归了。把代码改一下:

    1
    2
    3
    4
    5
    6
    7
    def fact(n):
    return fact_iter(n, 1)

    def fact_iter(num, product):
    if num == 1:
    return product
    return fact_iter(num - 1, num * product)

    但是一般不要用,有两点原因:1.python不支持尾递归优化;2.这样优化的代码可读性和逻辑性没有之前单纯的递归清晰。

0%