1小时学会Python:撸代码法

不用怀疑!如果已经有代码编程经验,或许只需要半小时就能学会Python。好方法必能提升学习效率。本文档为你提供一种高效的学习Python语言的方法:撸代码法。 这是所有学习编程者的基本方法,只是照着某一本参考书边咬文嚼字边调试书中的参考代码。跟着一本参考书通过撸代码学编程或许会帮助我们更好地理解相关概念, 然而效率确实低了些,谁会记住多少概念呢?大多数人依靠验证才能get编程的概念。本文档直接给出一组由浅入深(直到Advanced topics)的、 Python的主要知识点和关键概念全覆盖的示例代码,只要你有些许的代码编程知识,一小时内将本文档的代码撸一遍,掌握Python编程语言绝非难事儿。

当然,开工之前需要一点准备工作。请自行在电脑上安装好Python 3.x解释器(直接到python.org网站下载并安装),他自带编辑器和字符控制台; 或者,你已经安装MU编辑器(见“使用BlueFi之前的准备工作”),将MU编辑器的模式(点击左上角按钮选择)切换为“Python3.x”。


使用标准Python 3.x解释器或MU编辑器内置的Python3.x解释器,逐行地阅读并执行下面的每一行代码,第一次学习本文档时可以跳过第5~7等三个部分。

  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
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
# 从这里开始,这是一个注释语句。单行的注释是以“#”号开始

""" 多行的注释语句
    可以使用3个双引号(")包括所有注释行
      """

''' 多行的注释语句
    还可以使用3个单引号(')包括所有注释行
'''

####################################################
## 1. 简单的数据类型和运算符
####################################################

# 一个数字
3  # => 3

# 数学表达式
1 + 1  # => 2
8 - 1  # => 7
10 * 2  # => 20
35 / 5  # => 7.0 (自动给出浮点型的商)
11 / 4  # => 2.75
11 / 3  # => 3.6666666666666665 (这是个无理数,精度足够高)
# 整除,商是整数,采用向下圆整
5 // 2  # => 2

# 无论是正数或负数,整除的商都是向下圆整
-5 // 2  # => -3
5 // 3     # => 1
-5 // 3  # => -2
# 浮点数也支持整除,整数型商仍使用浮点型
5.6 // 3.3 # => 1.0
-5.2 // 3.0 # => -2.0

# 在Python 2.x中,导入“division” 模块可保持与Python 3.x一致的除法运算
11/4   # 2  (Python 2.x)
from __future__ import division
11/4    # => 2.75
11//4   # => 2

      # 注意,从Python 3.x开始,除法运算的结果取整数和浮点数
      # 仅取决于使用的“//”(整数结果)和“/”(浮点数结果)运算符

# 取余运算
7 % 3 # => 1

# 求幂运算
2 ** 4 # => 16

# 使用括号指定强制的运算优先级
(1 + 3) * 2  # => 8

# 布尔运算
# 注意:“and”和“or”运算符是区分大小写的
# 注意:“True”和“False”两个常数也是区分大小写的
True and False #=> False
False or True  #=> True

# 整数用于布尔运算(回想数值的二进制表示形式)
0 and 2 #=> 0 (按位“与”运算的结果,非布尔型)
-5 or 0 #=> -5 (按位“或”运算的结果,非布尔型)
0 == False #=> True
2 == True  #=> False
1 == True  #=> True

# 用“not”取反
not True  # => False
not False  # => True

# 使用“==”判断是否相等
1 == 1  # => True
2 == 1  # => False

# 使用“!=”判断是否不相等
1 != 1  # => False
2 != 1  # => True

# 更多比较运算
1 < 10  # => True
1 > 10  # => False
2 <= 2  # => True
2 >= 2  # => True

# 比较也可以写成链状!
1 < 2 < 3  # => True
2 < 3 < 2  # => False

# 使用 " 或 ' 创建字符串 (单引号和双引号必须成对)
"This is a string."
'This is also a string.'

# 字符串相加(拼接)!
"Hello " + "world!"  # => "Hello world!"
# 没有 + 号的字符串拼接
"Hello " "world!"  # => "Hello world!"

# 字符串多次复制拼接
"Hello" * 3  # => "HelloHelloHello"

# 一个字符串也可以当作一种字符列表(稍后就会遇到列表型数据集)
"This is a string"[0]  # => 'T'

# 使用“len(str)”函数确定一个字符串的长度
len("This is a string")  # => 16

# 使用“%”格式化字符串
# 尽管字符串的“%”运算符在Python 3.1及以后的版本中被废弃,但了解它怎么用仍是有益的
x = 'apple'
y = 'lemon'
z = "The items in the basket are %s and %s" % (x,y)

# “format”是一种更新的格式化字符串的方法,代替“%”的方法
# 在Python 3.x中,这是首选的方法
"{} is a {}".format("This", "placeholder")
"{0} can be {1}".format("strings", "formatted")
# 如果不想数数,你可以使用关键词,关键词的顺序不重要
"{who} wants to eat {food}".format(who="Bob", food="lasagna")

# None是一个对象
None  # => None

# 禁止使用“==”来判断某个对象是否为None
# 使用“is”代替“==”
"etc" is None  # => False
None is None  # => True

# “is”操作符用来判断对象的合法性
# 用“is”处理简单数值不是很有用,但处理对象十分有用

# 任何一个对象都可以用作布尔型
# 下面的这些值是False:
#    - None
#    - 所有数值型类型的0 (e.g., 0, 0L, 0.0, 0j)
#    - 空的序列 (e.g., '', (), [])
#    - 空的容器 (e.g., {}, set())
#    - 符合某些条件的用户自定义类的实例
# 详情见:https://docs.python.org/2/reference/datamodel.html#object.__nonzero__
# 除了下面两行之外,其他所有都为True(使用bool()函数返回True)
bool(0)  # => False
bool("")  # => False


####################################################
## 2. 变量和集合
####################################################

# Python的print方法(输出字符串到字符控制台)
print("I'm Python. Nice to meet you!") # => I'm Python. Nice to meet you!

# 从字符控制台获取输入数据的简单方法
input_string_var = raw_input("Enter some data: ") # 返回一个String型的值
input_var = input("Enter some data: ") # 返回一个Int型的值
# 警告:使用input()方法必须要谨慎
# 注意:在Python 3,原input()被弃用,并将原raw_input()改名为input()

# 给变量赋值之前没有必要先声明该变量
some_var = 5   # 变量赋值
some_var  # => 5

# 访问之前没有声明的变量会引起异常
# 前往“流程控制”学习如何处理异常
some_other_var  # 引起一个变量名错误

# “if”可用在表达式中,实现C语言中的三目运算
      # “(测试条)? 条件成立时的值:条件不成立时的值”
"baidu!" if 3 > 2 else "google!"  # => "baidu!"

# 列表(存储序列)
li = []
# 可以使用预先填充的列表
other_li = [4, 5, 6]

# 使用“append”方法向列表尾项添加列表项
li.append(1)    # li is now [1]
li.append(2)    # li is now [1, 2]
li.append(4)    # li is now [1, 2, 4]
li.append(3)    # li is now [1, 2, 4, 3]
# 通过“pop”移除列表尾项
li.pop()        # => 3 and li is now [1, 2, 4]
# 再将其加入进来
li.append(3)    # li is now [1, 2, 4, 3] again.

# 访问列表中的某一项就像使用数组一样
li[0]  # => 1
# 使用“=”为已经存在的索引项赋于新的值
li[0] = 42
li[0]  # => 42
li[0] = 1  # 注意,现在再重新赋于原始值
# 查看最后一个元素(列表的尾项),这与访问数组有区别!
li[-1]  # => 3

# 越界访问会报IndexError
li[4]  # 引起一个IndexError

# 通过列表切片获取列表中的部分内容,即获取列表的片段
li[1:3]  # => [2, 4]
# 省略结尾
li[2:]  # => [4, 3]
# 省略开头
li[:3]  # => [1, 2, 4]
# 隔两个步长访问
li[::2]   # =>[1, 4]
# 列表反转
li[::-1]   # => [3, 4, 2, 1]
# 使用li[开始:结束:步长]来实现不同的切分

# 使用“del”删除指定位置的元素
del li[2]   # li is now [1, 2, 3]

# 两个列表相加(合并列表)
li + other_li   # => [1, 2, 3, 4, 5, 6]
# 注意:li和other_list中的数据是没有被修改的

# 使用“extend()”方法来扩展列表
li.extend(other_li)   # Now li is [1, 2, 3, 4, 5, 6]

# 删除第一个被找到对应值的元素
li.remove(2)  # li is now [1, 3, 4, 5, 6]
li.remove(2)  # 引起一个ValueError,因为2已经不在li中了

# 在指定的位置插入一个元素
li.insert(1, 2)  # li is now [1, 2, 3, 4, 5, 6] again

# 找到对应值的位置
li.index(2)  # => 1
li.index(7)  # 引起一个ValueError,因为7不在li中

# 使用“in”查看列表中是否存在该元素
1 in li   # => True

# 使用“len()”方法获取列表的长度
len(li)   # => 6

# 元组(Tuples)像列表,但是它是不可变的
tup = (1, 2, 3)
tup[0]   # => 1
tup[0] = 3  # 引起一个TypeError

# 你可以对元组做下面所有列表的操作
len(tup)   # => 3
tup + (4, 5, 6)   # => (1, 2, 3, 4, 5, 6)
tup[:2]   # => (1, 2)
2 in tup   # => True

# 你可以将元组(或列表)中的数据取到变量中
a, b, c = (1, 2, 3)     # a is now 1, b is now 2 and c is now 3
d, e, f = 4, 5, 6       # you can leave out the parentheses
# 不使用“()”也可以创建元组
g = 4, 5, 6             # => (4, 5, 6)
# 简单的交换两个变量的值
e, d = d, e     # d is now 5 and e is now 4

# 字典(dict)用来存储映射型信息,即{key:value}型
empty_dict = {}
# 这是一个预先定义的字典
filled_dict = {"one": 1, "two": 2, "three": 3}

# 使用“[]”查看字典中的值
filled_dict["one"]   # => 1

# 使用“keys()”方法获得一个字典中所有键的列表
filled_dict.keys()   # => ["three", "two", "one"]
# 注意:字典中键的排序是无规律的
# 你的结果可能和这个列表不完全相同

# 使用“values()”方法获得一个字典中所有值的列表
filled_dict.values()   # => [3, 2, 1]
# 注意:值的排序同上面键的排序

# 使用“in”查看指定的键是否在字典中
"one" in filled_dict   # => True
1 in filled_dict   # => False

# 试图访问一个不存在的键时会引起KeyError
filled_dict["four"]   # 引起一个KeyError

# 使用“get()”方法获取指定键的值但避免产生KeyError
filled_dict.get("one")   # => 1
filled_dict.get("four")   # => None
# 这个get方法,当查找的键不存在时,返回给定默认值
filled_dict.get("one", 4)   # => 1
filled_dict.get("four", 4)   # => 4
# 记住filled_dict.get("four") 仍然会返回None
# (get方法不会在字典中设置值)

# 可以使用与列表一样的方法设置指定键的值
filled_dict["four"] = 4  # now, filled_dict["four"] => 4

# “setdefault()”方法只有在字典中不存在指定键的时候才插入
filled_dict.setdefault("five", 5)  # filled_dict["five"] is set to 5
filled_dict.setdefault("five", 6)  # filled_dict["five"] is still 5

# 集合(set)是无序的无重复元素的序列
empty_set = set()
# 使用一批数值初始化一个集合
some_set = set([1, 2, 2, 3, 4])   # some_set is now set([1, 2, 3, 4])

# 无序是常态,即使看起来像排好序的
another_set = set([4, 3, 2, 2, 1])  # another_set is now set([1, 2, 3, 4])

# 从Python 2.7开始,允许用“{}”来声明一个集合
filled_set = {1, 2, 2, 3, 4}   # => {1, 2, 3, 4}

# 向集合中添加一个元素
filled_set.add(5)   # filled_set is now {1, 2, 3, 4, 5}

# 两集合间使用“&”做交集运算
other_set = {3, 4, 5, 6}
filled_set & other_set   # => {3, 4, 5}

# 两集合间使用“|”做并集运算
filled_set | other_set   # => {1, 2, 3, 4, 5, 6}

# 两集合间使用“-”做差集运算
{1, 2, 3, 4} - {2, 3, 5}   # => {1, 4}

# 两集合间使用“^”做对称差分运算(交集的补集)
{1, 2, 3, 4} ^ {2, 3, 5}  # => {1, 4, 5}

# 检查右边的集合是否是左边的子集
{1, 2} >= {1, 2, 3} # => False

# 检查左边的集合是否是右边的子集
{1, 2} <= {1, 2, 3} # => True

# 使用“in”检查指定的元素是否属于集合中的元素
2 in filled_set   # => True
10 in filled_set   # => False


      ####################################################
      ## 3. 流程控制
      ####################################################

# 让我们来创建一个变量
some_var = 5

# 下面是一些if语句。“:”和程序行缩进是保持Python程序块的关键!
#       print( "some_var is smaller than 10." )缩进一个 Tab键
if some_var > 10:
  print( "some_var is totally bigger than 10." )
elif some_var < 10:    # 这个elif代码块是可选的
  print( "some_var is smaller than 10." )
else:           # 这个同样是可选的
  print( "some_var is indeed 10." )


"""
使用“for”循环遍历列表
prints:
  dog is a mammal
  cat is a mammal
  mouse is a mammal
"""
for animal in ["dog", "cat", "mouse"]:
  # 你可以使用“{0}”占位符来插入字符串(详情见上)
  print( "{0} is a mammal".format(animal) )

"""
“range(number)”返回一个从0到number-1的连续整数列表
prints:
  0
  1
  2
  3
"""
for i in range(4):
  print( i )

"""
“range(number1, number2)”返回一个从number1到number2-1的连续整数列表
prints:
  4
  5
  6
  7
"""
for i in range(4, 8):
  print( i )

"""
“range(number1, number2, steplength)”返回一个从number1开始到number2为止的
固定间隔的整数列表(number2肯定不会包含在列表中),间隔/步长为steplength
prints:
  4
  6
"""
for i in range(4, 8, 2):
  print( i )

"""
While可以一直循环到条件不成立
prints:
  0
  1
  2
  3
"""
x = 0
while x < 4:
  print( x )
  x += 1  # 这是“x = x + 1”的速写形式

# 通过try/except代码段来处理异常

# 请在Python2.6以后可以使用:
try:
  # 使用“raise”抛出一个异常
  raise IndexError("This is an index error")
except IndexError as e:
  pass    # Pass就是一个空语句(占位语句)。通常需要你在这里处理异常
except (TypeError, NameError):
  pass    # 如果有必要,同时处理多种异常
else:   # 这是try/except代码段可选的条件。必须要跟在所有的except语句之后
  print( "All good!" )  # 仅仅在try代码中没有出现异常时才执行
finally: #  在所有语句执行完毕之后执行
  print( "We can clean up resources here" )

# 使用with语句代替try/finally语句清空资源
with open("myfile.txt") as f:
  for line in f:
    print( line )


####################################################
## 4. 函数
####################################################

# 使用“def”来创建一个函数
# 注意,函数是一个程序块,使用“:”和缩进保持程序块
def add(x, y):
  print( "x is {0} and y is {1}".format(x, y) )
  return x + y    # 通过return语句返回结果

# 调用带有多个参数的函数,多个参数按定义函数时的参数顺序传递
add(5, 6)   # => prints out "x is 5 and y is 6" and returns 11

# 另一种调用带有参数的函数,通过关键字传递参数,参数的顺序不重要了
add(y=6, x=5)   # Keyword arguments can arrive in any order.

# 定义一个能够接受参数个数可变的函数,使用“*”将参数解释成元组类型
def varargs(*args):
  return args

varargs(1, 2, 3)   # => (1, 2, 3)

# 定义一个能够接受参数个数可变的函数,使用“*”将参数解释成字典类型
def keyword_args(**kwargs):
  return kwargs

# 让我们看看调用这种函数时会发生什么
keyword_args(big="foot", loch="ness")   # => {"big": "foot", "loch": "ness"}

# 当然,如果你喜欢还可以同时使用它俩
def all_the_args(*args, **kwargs):
  print( args )
  print( kwargs )
"""
all_the_args(1, 2, a=3, b=4) prints:
  (1, 2)
  {"a": 3, "b": 4}
"""

# 当你调用函数的时候,你可以选择参数,使用“*”和“**”传递不同类型的参数
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
all_the_args(*args)   # equivalent to foo(1, 2, 3, 4)
all_the_args(**kwargs)   # equivalent to foo(a=3, b=4)
all_the_args(*args, **kwargs)   # equivalent to foo(1, 2, 3, 4, a=3, b=4)

def pass_all_the_args(*args, **kwargs):
  all_the_args(*args, **kwargs)
  print( varargs(*args) )
  print( keyword_args(**kwargs) )

# 函数的作用范围
x = 5  # the "x" is a global variable

def set_x(num):
  # 函数当前的变量x和全局的变量x是不同的
  x = num # => 43
  print( x )# => 43

def set_global_x(num):
  global x
  print( x )# => 5
  x = num # 全局的变量x现在变成了6
  print( x )# => 6

set_x(43)
set_global_x(6)

# Python的第一类函数(第一类对象)
def create_adder(x):
  def adder(y):
    return x + y
  return adder

add_10 = create_adder(10) # Python函数是一种对象,可以赋值为一个变量
add_10(3)   # => 13

# 当然也有匿名函数(lambda函数)
(lambda x: x > 2)(3)   # => True
(lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5

# Python也有很多内建的高阶函数
map(add_10, [1, 2, 3])   # => [11, 12, 13]
map(max, [1, 2, 3], [4, 2, 1])   # => [4, 2, 3]

filter(lambda x: x > 5, [3, 4, 5, 6, 7])   # => [6, 7]

# 我们可以使用列表构造出漂亮的map和滤波器
[add_10(i) for i in [1, 2, 3]]  # => [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5]   # => [6, 7]

# 还可以构造出集合和字典
{x for x in 'abcddeef' if x in 'abc'}  # => {'a', 'b', 'c'}
{x: x ** 2 for x in range(5)}  # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}


####################################################
## 5. 类
####################################################

# 我们从object中派生出一个子类
class Human(object):

  # 一个类的属性。它被这个类的所有实例所共享
  species = "H. sapiens"

  # 基本初始化,当这个类被实例化时将自动调用
  # 注意前后的双下划线表示对象或者属性由Python使用,但是它处在用户控制的命名空间中
  # 你不应该这样创建自己的名字
  def __init__(self, name):
    # 声明变量 _name,并将 name 参数赋值给该变量
    self._name = name

    # 初始化属性
    self._age = 0

  # 实例的一个方法。所有的方法都将“self”作为第一个参数
  def say(self, msg):
    return "{0}: {1}".format(self._name, msg)

  # 一个类中的方法被所有的实例对象所共享
  # 它们通过第一个参数所属的类被其类所调用
  @classmethod
  def get_species(cls):
    return cls.species

  # 一个静态的方法,不通过一个类或者一个实例所调用
  @staticmethod
  def grunt():
    return "*grunt*"

  # “property”就像是getter方法
  # 它将返回方法age的只读的属性
  @property
  def age(self):
    return self._age

  # 下面的方法是对属性赋值
  @age.setter
  def age(self, value):
    self._age = value

  # 下面的方法是将属性删除掉
  @age.deleter
  def age(self):
    del self._age

# 实例化一个类
i = Human(name="Ian")
print( i.say("hi") )    # prints out "Ian: hi"

j = Human("Joel")
print( j.say("hello") ) # prints out "Joel: hello"

# 调用类中的方法
i.get_species()   # => "H. sapiens"

# 修改共享的属性
Human.species = "H. neanderthalensis"
i.get_species()   # => "H. neanderthalensis"
j.get_species()   # => "H. neanderthalensis"

# 调用静态方法
Human.grunt()   # => "*grunt*"

# 更新/设置属性值
i.age = 42

# 获取属性值
i.age # => 42

# 删除属性
del i.age
i.age  # => raises an AttributeError


####################################################
## 6. 模块
####################################################

# 导入模块
import math

print( math.sqrt(16) ) # => 4.0

# 从一个模块中导入指定的函数/方法
from math import ceil, floor

print( ceil(3.7) ) # => 4.0
print( floor(3.7) )  # => 3.0

# 从一个模块中导入所有的函数
# 警告:这种方法是不建议的,建议使用 import moduleName
from math import *

# 下面的方式可以缩短模块名称
import math as m

math.sqrt(16) == m.sqrt(16)   # => True
# 测试这些函数的等价性
from math import sqrt

math.sqrt == m.sqrt == sqrt  # => True

# Python的模块(module)仅仅是普通的python文件。你可以编写自己的Python模块然后导入它们
# Python模块的名称和文件名称必须相同

# 使用“dir(module)”查找一个模块中的方法和属性
import math

dir(math)

# 如果有一个Python脚本文件,名叫“math.py”,正好在当前执行的Python脚本程序文件夹中
# 当前文件夹中的这个“math.py”文件将替代Python内建的"math"模块被加载
# 这是因为,本地文件夹内的模块优先级高于内建的库/模块


####################################################
## 7. 高级(生成器和装饰器)
####################################################


# 生成器(Generators)
# 一个生成器能够按要求“产生”值,而不是事先存储的值

# 下面的方法( **不是** 生成器)将翻倍每一个值并存储到“double_arr”中
# 对于一个大的迭代器,需要很大的存储空间!
def double_numbers(iterable):
  double_arr = []
  for i in iterable:
    double_arr.append(i + i)
  return double_arr

# 运行下面代码,我们将首先翻倍每一个值,然后返回所有值并根据条件来判断
for value in double_numbers(range(1000000)):  # `test_non_generator`
  print( value )
  if value > 5:
    break

# 现在我们用生成器代替“产生”翻倍值,但这是根据需要进行的
def double_numbers_generator(iterable):
  for i in iterable:
    yield i + i

# 现在运行前面相同的代码,但这次使用生成器,随着程序逻辑的需要以迭代的形式翻倍数值
# 当满足“value > 5”条件时,循环终止,这样的程序执行不需要所有翻倍后的数值(速度更快!内存更少!)
for value in double_numbers_generator(xrange(1000000)):  # `test_generator`
  print( value )
  if value > 5:
    break

# 顺便提及,你是否注意到“test_non_generator”这一行的“range()”函数和“test_generator”这一行的“xrange()”?
# 如果说“double_numbers_generator”是“double_numbers”的生成器版本,关键是“xrange()”是“range()”的生成器版本
# “range(1000000)”返回列表“[0, 1, .., 999999]”,但“xrange(1000000)”仅仅是一个0~999999之间数值的生成器
# 只会根据我们程序要求/随着迭代返回其中的单个值
#
# 就像创建一个列表一样地创建一个生成器 (values **是** 一个生成器)
values = (-x for x in [1, 2, 3, 4, 5])
for x in values:
  print( x )  # prints -1 -2 -3 -4 -5 to console/terminal

# 值得注意,Python3.x弃用“xrange()”,使用“range()”代替Python2.x中的“xrange()”
# 换句话说,Python3.x中的“range()”已经是生成器!

# 完全可以将一个生成器直接转换成一个列表
values = (-x for x in [1, 2, 3, 4, 5])
gen_to_list = list(values)
print( gen_to_list )  # => [-1, -2, -3, -4, -5]

# 装饰器(Decorators)
# 装饰器是一种高阶函数,他是修改其他函数的功能的函数
# 简单的用法示例:“add_apples”装饰器将“Apple”元素添加到“fruits”列表中,通过“get_fruits”函数返回他
def add_apples(func):
  def get_fruits():
    fruits = func()
    fruits.append('Apple')
    return fruits
  return get_fruits

@add_apples
def get_fruits():
    return ['Banana', 'Mango', 'Orange']

# Prints out the list of fruits with 'Apple' element in it:
# Banana, Mango, Orange, Apple
print( ', '.join(get_fruits()) )

# in this example "beg" wraps "say"
# "beg" will call "say". If "say_please" is True then it will change the returned
# message
from functools import wraps

def beg(target_function):
  @wraps(target_function)
  def wrapper(*args, **kwargs):
    msg, say_please = target_function(*args, **kwargs)
    if say_please:
      return "{} {}".format( msg, "Please! I am poor :(" )
    return msg
  return wrapper

@beg
def say(say_please=False):
  msg = "Can you buy me a beer?"
  return msg, say_please

print( say() ) # Can you buy me a beer?
print( say(say_please=True) ) # Can you buy me a beer? Please! I am poor :(

如果已经认真地执行到这里(允许跳过第5~7部分),祝贺你已经学会Python!数值及其运算、字符串、变量和函数,这些基本概念在Python语言中有哪些特殊之处? 列表、元组(只读型列表)、字典、集合等数据结构还在哪些编程语言中用到?Python使用“:”和行缩进的形式来组织程序块,你熟悉的编程语言分别都是如何组织程序块的呢? 导入模块的思想是Python特有的吗?其他编程语言如何导入模块呢?再多找一些能够与你所熟悉的代码编程语言形成对比的概念,更好地加深理解和掌握。

如果你觉得把这些代码撸一遍不能掌握Python的话,那就多撸几遍吧!