简明 Python3 教程 | 学习笔记

GitBook 原电子书地址:简明 Python 教程

《A Byte of Python》是一本由 Swaroop C H 编写,旨在于介绍如何使用 Python 语言进行编程的自由图书。它以教材与指南的形式为入门者介绍 Python 语言。如果你对电脑知识的了解仅限于如何保存文本文件的话,那这本书就是为你准备的。
2005 年,沈洁元将本书的 1.20 版引进中国,并完成了全本翻译,将本书的译名定为《简明 Python 教程》。2017年,漠伦基于原书 4.0 版重新翻译,制作了本版全新译本,并沿用同样的译名。
本版译本定义为 4.08c 版。最后修订于 2018 年 2 月 4 日。

本人仅在该教程上,提炼自身薄弱的知识点,以及需注意的重点。该笔记不具有参考意义,有需要的读者可看原 GitBook 电子书。—-ZJ


格式化方法: format()

有时候我们会想要从其他信息中构建字符串。这正是 format() 方法大有用武之地的地方。

age = 20
name = 'Swaroop'

print('{0} was {1} years old when he wrote this book'.format(name, age))
print('Why is {0} playing with that python?'.format(name))
Swaroop was 20 years old when he wrote this book
Why is Swaroop playing with that python?
name  + ' is '+ str(age) + ' years old'
'Swaroop is 20 years old'
# 对于浮点数 '0.333' 保留小数点(.)后三位
print('{0:.3f}'.format(1.0/3))
# 使用下划线填充文本,并保持文字处于中间位置
# 使用 (^) 定义 '___hello___'字符串长度为 11
print('{0:_^11}'.format('hello'))
# 基于关键词输出 'Swaroop wrote A Byte of Python'
print('{name} wrote {book}'.format(name='Swaroop',book='A byte of Python'))
0.333
___hello___
Swaroop wrote A byte of Python

由于我们正在讨论格式问题,就要注意 print 总是会以一个不可见的“新一行”字符( \n )
结尾,因此重复调用 print 将会在相互独立的一行中分别打印。为防止打印过程中出现这一
换行符,你可以通过 end 指定其应以空白结尾:

print('wow')
print('a',end='')
print('b',end='')
print()
print('c', end=' ')
print('d', end=' ')
wow
ab
c d 

转义序列(Escape Sequence)

  • 通过 \ 来指定单引号:要注意它可是反斜杠。
  • 双引号,必须使用转义序列 \ 来指定反斜杠本身。
  • \n 来表示新一行的开始
print('what\'s your name?')
print("what's your name?")
print('This is the first line.\nThis is the second line.')
what's your name?
what's your name?
This is the first line.
This is the second line.

原始字符串

如果你需要指定一些未经过特殊处理的字符串,比如转义序列,那么你需要在字符串前增加 r 或 R 来指定一个 原始(Raw) 字符串 。

针对正则表达式用户的提示
在处理正则表达式时应全程使用原始字符串。否则,将会有大量 Backwhacking 需要处理。举例说明的话,反向引用可以通过 ‘\1’ 或 r’\1’ 来实现。

print(r"Newlines are indicated by \n")
Newlines are indicated by \n
i = 5
print(i)
i = i + 1
print(i)

s = '''This is a multi-line string.
This is the second line'''
print(s)
5
6
This is a multi-line string.
This is the second line
'''
强烈建议你对于每一行物理行最多只写入一行逻辑行。这个观点就是说你不应该使
用分号。实际上,我从未在 Python 程序中使用、甚至是见过一个分号。

在一类情况下这一方法会颇为有用:如果你有一行非常长的代码,你可以通过使用反斜杠将
其拆分成多个物理行。这被称作显式行连接(Explicit Line Joining)

注意: \ 后面不要有空格

'''

s = 'This is a string. \
This continues the string.'
print(s)
This is a string. This continues the string.
i = \
5
print(i)
5

运算符

  • // (整除)
    • x 除以 y 并对结果向下取整至最接近的整数。
    • 13 // 3 输出 4 。
    • -13 // 3 输出 -5 。
  • % (取模)

    • 返回除法运算后的余数。
    • 13 % 3 输出 1 。 -25.5 % 2.25 输出 1.5 。
    • 对于整型数a,b来说,取模运算或者求余运算的方法都是:

      • 1.求 整数商: c = a/b;
      • 2.计算模或者余数: r = a - c*b.
    • 归纳:

      • 当a和b符号一致时,求模运算和求余运算所得的c的值一致,因此结果一致。
      • 当符号不一致时,结果不一样。求模运算结果的符号和b一致,求余运算结果的符号和a一致。
  • << (左移)

    • 将数字的位向左移动指定的位数。(每个数字在内存中以二进制数表示,即 0 和1)
    • 2 << 2 输出 8 。 2 用二进制数表示为 10 。
    • 向左移 2 位会得到 1000 这一结果,表示十进制中的 8 。
  • >> (右移)
    • 将数字的位向右移动指定的位数。
    • 11 >> 1 输出 5 。
    • 11 在二进制中表示为 1011 ,右移一位后输出 101 这一结果,表示十进制中的 5 。
13//3
4
-13//3 # 向下取整 -4.多 向下取整是 -5
-5
13%3
1
'''
c = a/b; -25.5/2.25 = -12 (向下取整)
r = a - c*b. r = -25.5 - (-12 * 2.25) = 1.5
'''
-25.5%2.25
1.5
'''
2  ----- 10 
左移两位

8  ----- 1000 

(2**3, 2**2, 2**1, 2**0)

'''
2<<2
8
'''
11 ---- 1011 (8+2+1)
右移 1 位
5  ----- 101 (4+1) 

'''

11>>1
5
  • & (按位与)
    • 对数字进行按位与操作。
    • 5 & 3 输出 1 。
  • | (按位或)
    • 对数字进行按位或操作。运算规则:0 ^ 0 = 0;0 ^ 1 = 1;1 ^ 0 = 1;1 ^ 1 = 0;
    • 5 | 3 输出 7 。
  • ^ (按位异或)
    • 对数字进行按位异或操作。
    • 5 ^ 3 输出 6 。
  • ~ (按位取反)
  • < (小于)
    • 返回 x 是否小于 y。所有的比较运算符返回的结果均为 True 或 False 。请注意这些名称之中的大写字母。
    • 5 < 3 输出 False , 3 < 6 输出 True 。
print(5 < 3)
print(~5)
a = 2
a *= 3
print(a)
False
-6
6
number = 23
guess = int(input('Enter an integer :'))

if guess == number:
    print('Congratulations, you guessed it.')
    print('(but you do not win any prizes!)')
# 新块在这里结束
elif guess < number:
# 另一代码块
    print('No, it is a little higher than that')
# 你可以在此做任何你希望在该代码块内进行的事情
else:
    print('No, it is a little lower than that')
# 你必须通过猜测一个大于(>)设置数的数字来到达这里。
print('Done')
Enter an integer :89
No, it is a little lower than that
Done
number = 23
running = True

while running:
    guess = int(input('Enter an integer:'))

    if guess == number:
        print('Congratulations, you guessed it.')
        # 这将导致 while 循环中止
        running = False
    elif guess < number:
        print('No, it is a little higher than that.')
    else:
        print('No, it is a little lower than that.')
else:
    print('The while loop is over.')
# 在这里你可以做你想做的任何事
print('Done')
Enter an integer:90
No, it is a little lower than that.
Enter an integer:11
No, it is a little higher than that.
Enter an integer:23
Congratulations, you guessed it.
The while loop is over.
Done
for i in range(1,5):
    print(i)
else:
    print('The for loop is over')
1
2
3
4
The for loop is over
while True:
    s = input('Enter something:')
    if s == 'quit':
        break
    print('Length of the string is', len(s))
print('Done')    
Enter something:what?
Length of the string is 5
Enter something:quit
Done
# 用 continue 语句跳过代码块中的其余语句。
while True:
    s = input('Enter something:')
    if s == 'quit':
        break
    if len(s) < 3:
        print('Too small')
        continue
    print('Input is of sufficient length')    
Enter something:hello
Input is of sufficient length
Enter something:o
Too small
Enter something:quit
def say(message, times=1):
    print(message * times)

say('Hello ')    
say('World ', 5)
Hello 
World World World World World 
'''
关键字参数(Keyword Arguments)
'''
def func(a, b=5, c=10):
    print('a is',a, 'and b is', b, 'and c is', c)

func(3,7)    
func(35, c= 30)
func(c=80,b=9,a=888)
a is 3 and b is 7 and c is 10
a is 35 and b is 5 and c is 30
a is 888 and b is 9 and c is 80
'''
可变参数
'''
def total(a=5, *numbers, **phonebook):
    print('a', a)

    for single_item in numbers:
        print('single_item', single_item)

    for first_part,second_part in phonebook.items():
        print(first_part,second_part)

print(total(10,1,2,3,Jack=101010,John=22323,Inge=1889))
a 10
single_item 1
single_item 2
single_item 3
Jack 101010
John 22323
Inge 1889
None
'''
文档字符串(Documentation Strings)

该文档字符串所约定的是一串多行字符串,其中第一行以某一大写字母开始,以句号结束。
第二行为空行,后跟的第三行开始是任何详细的解释说明。 在此强烈建议你在你所有重要功
能的所有文档字符串中都遵循这一约定。

'''


def print_max(x, y):
    '''打印两个数值中的最大数。

    这两个数都应该是整数'''
    # 如果可能,将其转换至整数类型
    x = int(x)
    y = int(y)
    if x > y:
        print(x, 'is maximum')
    else:
        print(y, 'is maximum')

print_max(3, 5)
print(print_max.__doc__)
5 is maximum
打印两个数值中的最大数。

    这两个数都应该是整数
help(print_max)
Help on function print_max in module __main__:

print_max(x, y)
    打印两个数值中的最大数。

    这两个数都应该是整数
import sys

print('The command line arguments are:')
for i in sys.argv:
    print(i)

print('\n\n The PYTHONPATH is',sys.path,'\n') 
>python module_using_sys.py we are arguments
The command line arguments are:
module_using_sys.py
we
are
arguments


 The Python Path is ['D:\\github\\python\\Deep-Learning\\python', 'D:\\Program Files\\Python36\\python36.zip', 'D:\\Program Files\\Python36\\DLLs', 'D:\\Program Files\\Python36\\lib', 'D:\\Program Files\\Python36', 'C:\\Users\\qhtf\\AppData\\Roaming\\Python\\Python36\\site-packages', 'D:\\Program Files\\Python36\\lib\\site-packages']
import os

print(os.getcwd())
D:\github\python\Deep-Learning\python
from sys import argv
from math import sqrt

help(sqrt)
print('Square root of 16 is', sqrt(16))
Help on built-in function sqrt in module math:

sqrt(...)
    sqrt(x)

    Return the square root of x.

Square root of 16 is 4.0
import mymodule

mymodule.say_hi()
print('Version', mymodule.__version__)
Hi, this is mymodule speaking.
Version 0.1
from mymodule import say_hi,__version__

say_hi()
print('Version',__version__)
Hi, this is mymodule speaking.
Version 0.1
import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
import sys

# 给出 sys 模块中的属性名称
dir(sys)

# 给出当前模块的属性名称
dir()

包(Packages)

包是指一个包含模块与一个特殊的 init.py 文件的文件夹,后者向 Python 表明这一文件夹是特别的,因为其包含了 Python 模块。
让我们这样设想:你想创建一个名为“world”的包,其中还包含着“asia”、“africa”等其它子包,同时这些子包都包含了诸如“india”、 “madagascar”等模块。

数据结构

数据结构(Data Structures)基本上人如其名——它们只是一种结构,能够将一些数据聚合在一起。换句话说,它们是用来存储一系列相关数据的集合。

Python 中有四种内置的数据结构——列表(List)、元组(Tuple)、字典(Dictionary)和集合(Set)。我们将了解如何使用它们,并利用它们将我们的编程之路变得更加简单。

列表是可变的(Mutable)而字符串是不可变的(Immutable)。

'''
list 列表
'''
shoplist = ['apple', 'mango', 'carrot','banana']

print('I have', len(shoplist), 'items to purchase')
print('I have %d items to purchase'% len(shoplist))

print('These items are:', end=' ')
for item in shoplist:
    print(item, end=' ')

print('\n I also have to buy rice.')    
shoplist.append('rice')
print('My shopping list is now', shoplist)

print('I will sort my list now')
shoplist.sort()
print('Sorted shopping list is now', shoplist)

print('The first item I will buy is', shoplist[0])
olditem = shoplist[0]

del shoplist[0]

print('I bought the',olditem)

print('My shopping list is now',shoplist)
I have 4 items to purchase
I have 4 items to purchase
These items are: apple mango carrot banana 
 I also have to buy rice.
My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice']
I will sort my list now
Sorted shopping list is now ['apple', 'banana', 'carrot', 'mango', 'rice']
The first item I will buy is apple
I bought the apple
My shopping list is now ['banana', 'carrot', 'mango', 'rice']

元组(Tuple)

元组(Tuple)用于将多个对象保存到一起。你可以将它们近似地看作列表,但是元组不能提供列表类能够提供给你的广泛的功能。元组的一大特征类似于字符串,它们是不可变的,也就是说,你不能编辑或更改元组。

zoo = ('python','elephant','penguin')
print('Number od animals in the zoo is',len(zoo))

new_zoo = 'monkey','camel',zoo

print('Number of cages in the new zoo is', len(new_zoo))
print('All animals in the zoo are',new_zoo)
print('Animals brought from old zoo are', new_zoo[2])

print('Last animal brought from old zoo is',new_zoo[2][2])
print('Number of animals in the new zoo is',len(new_zoo)-1 + len(new_zoo[2]))
Number od animals in the zoo is 3
Number of cages in the new zoo is 3
All animals in the zoo are ('monkey', 'camel', ('python', 'elephant', 'penguin'))
Animals brought from old zoo are ('python', 'elephant', 'penguin')
Last animal brought from old zoo is penguin
Number of animals in the new zoo is 5
'''
Dictionary 字典

'''
ab = {
    'Swaroop': 'swaroop@swaroopch.com',
    'Larry': 'larry@wall.org',
    'Matsumoto': 'matz@ruby-lang.org',
    'Spammer': 'spammer@hotmail.com'
}

print("Swaroop's address is", ab['Swaroop'])

del ab['Spammer']

print('\nThere are {} contacts in the address-book\n'.format(len(ab)))
print('There are %d contacts in the address-book\n'%len(ab))

for name, address in ab.items():
    print('Contact {} at {}'.format(name, address))

ab['Guido'] = 'guido@python.org'

if 'Guido' in ab:
    print("\nGuido's address is",ab['Guido'])
Swaroop's address is swaroop@swaroopch.com

There are 3 contacts in the address-book

There are 3 contacts in the address-book

Contact Swaroop at swaroop@swaroopch.com
Contact Larry at larry@wall.org
Contact Matsumoto at matz@ruby-lang.org

Guido's address is guido@python.org
shoplist = ['apple', 'mango', 'carrot', 'banana']
name = 'swaroop'

# Indexing or 'Subscription' operation #
# 索引或“下标(Subscription)”操作符 #
print('Item 0 is', shoplist[0])
print('Item 1 is', shoplist[1])
print('Item 2 is', shoplist[2])
print('Item 3 is', shoplist[3])
print('Item -1 is', shoplist[-1])
print('Item -2 is', shoplist[-2])
print('Character 0 is', name[0])
Item 0 is apple
Item 1 is mango
Item 2 is carrot
Item 3 is banana
Item -1 is banana
Item -2 is carrot
Character 0 is s
# Slicing on a list shoplist = ['apple', 'mango', 'carrot', 'banana']#
print('Item 1 to 3 is', shoplist[1:3]) # 索引 1 开始 到 3 不包括3 
print('Item 2 to end is', shoplist[2:])
print('Item 1 to -1 is', shoplist[1:-1])
print('Item start to end is', shoplist[:])
Item 1 to 3 is ['mango', 'carrot']
Item 2 to end is ['carrot', 'banana']
Item 1 to -1 is ['mango', 'carrot']
Item start to end is ['apple', 'mango', 'carrot', 'banana']
# 从某一字符串中切片 name = 'swaroop'#
print('characters 1 to 3 is', name[1:3])
print('characters 2 to end is', name[2:])
print('characters 1 to -1 is', name[1:-1])
print('characters start to end is', name[:])
characters 1 to 3 is wa
characters 2 to end is aroop
characters 1 to -1 is waroo
characters start to end is swaroop

你同样可以在切片操作中提供第三个参数,这一参数将被视为切片的步长(Step)(在默认情况下,步长大小为 1):

ablist = ['a','b','c','d','e','f']

print(ablist[::1])
print(ablist[::2])
print(ablist[::3])
print(ablist[::-1])
print(ablist[::-2])
['a', 'b', 'c', 'd', 'e', 'f']
['a', 'c', 'e']
['a', 'd']
['f', 'e', 'd', 'c', 'b', 'a']
['f', 'd', 'b']
bri = set(['brazil', 'russia', 'india'])
'india' in bri
True
bric = bri.copy()
bric.add('china')
bric.issuperset(bri)
True
bri.add('russia')
bri.remove('russia')
print(bri & bric)
print(bri.intersection(bric))
{'india', 'brazil'}
{'india', 'brazil'}

引用

当你创建了一个对象并将其分配给某个变量时,变量只会查阅(Refer)某个对象,并且它也不会代表对象本身。也就是说,变量名只是指向你计算机内存中存储了相应对象的那一部分。这叫作将名称绑定(Binding)给那一个对象。

print('Simple Assignment')
shoplist = ['apple', 'mango', 'carrot', 'banana']
# mylist 只是指向同一对象的另一种名称
mylist = shoplist

del shoplist[0]

print('shoplist is', shoplist)
print('mylist is', mylist)

# 注意到 shoplist 和 mylist 二者都
# 打印出了其中都没有 apple 的同样的列表,以此我们确认
# 它们指向的是同一个对象
Simple Assignment
shoplist is ['mango', 'carrot', 'banana']
mylist is ['mango', 'carrot', 'banana']
print('Copy by making a full slice')

# 通过生成一份完整的切片制作一份列表的副本
shoplist = ['apple', 'mango', 'carrot', 'banana']

mylist = shoplist[:]
del mylist[0]

print('shoplist is', shoplist)
print('mylist is', mylist)

# 注意到现在两份列表已出现不同
Copy by making a full slice
shoplist is ['apple', 'mango', 'carrot', 'banana']
mylist is ['mango', 'carrot', 'banana']

有关字符串的更多内容

  • startswith 方法用于查找字符串是否以给定的字符串内容开头。
  • in 运算符用以检查给定的字符串是否是查询的字符串中的一部分。
  • find 方法用于定位字符串中给定的子字符串的位置。如果找不到相应的子字符串, find会返回 -1。
  • str 类同样还拥有一个简洁的方法用以 联结(Join) 序列中的项目,其中字符串将会作为每一项目之间的分隔符,并以此生成并返回一串更大的字符串。
'''
有关字符串的更多内容

'''
# 这是一个字符串对象
name = 'Swaroop'

if name.startswith('Swa'):
    print('Yes, the string starts with "Swa"')

if  'a' in name:
    print('Yes, it contains the string "a"')

if name.find('war') != -1:    
    print('Yes, it contains the string "war"')

delimiter = '_*_'    
mylist = ['Brazil', 'Russia', 'India', 'China']
print(delimiter.join(mylist))

Yes, the string starts with "Swa"
Yes, it contains the string "a"
Yes, it contains the string "war"
Brazil_*_Russia_*_India_*_China

问题

我们希望解决的问题如下:

我想要一款程序来备份我所有的重要文件。

分析(Analysis)— 例如,我们应该如何指定哪些文件是我们需要备份
的?它们应该如何进行备份?储存到哪里?

设计(Design)

  • 需要备份的文件与目录应在一份列表中予以指定。
  • 备份必须存储在一个主备份目录中。
  • 备份文件将打包压缩成 zip 文件。
  • zip 压缩文件的文件名由当前日期与时间构成。
  • 我们使用在任何 GNU/Linux 或 Unix 发行版中都会默认提供的标准 zip 命令进行打包。
  • 在这里你需要了解到只要有命令行界面,你就可以使用任何需要用到的压缩或归档命令。
'''
第一版


'''

import os
import time

# 1. 需要备份的文件与目录将被
# 指定在一个列表中。
# 例如在 Windows 下:
# source = ['"C:\\My Documents"', 'C:\\Code']
# 又例如在 Mac OS X 与 Linux 下: source = ['/Users/swa/notes']

source = ["D:\\github\\python\\Deep-Learning\\python\\source"]

# 在这里要注意到我们必须在字符串中使用双引号
# 用以括起其中包含空格的名称。

#2. 备份文件必须存储在一个
#主备份目录中
#例如在 Windows 下:
# target_dir = 'E:\\Backup'
# 又例如在 Mac OS X 和 Linux 下:target_dir = '/Users/swa/backup'
target_dir = 'E:\\qqfile\\backup'

# 要记得将这里的目录地址修改至你将使用的路径

# 3. 备份文件将打包压缩成 zip 文件。
# 4. zip 压缩文件的文件名由当前日期与时间构成。
target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + 'zip'

# 如果目标目录还不存在,则进行创建

if not os.path.exists(target_dir):
    os.mkdir(target_dir) # 创建目录

# 5. 我们使用 zip 命令将文件打包成 zip 格式
zip_command = 'zip -r {0} {1}'.format(target,' '.join(source))

# 运行备份   
print('Zip command is:')
print(zip_command)
print('Running:')
if os.system(zip_command) == 0:
    print('Successful backup to', target)
else:
    print('Backup Failed')

Zip command is:
zip -r E:\qqfile\backup\20180313152803zip D:\github\python\Deep-Learning\python\source
Running:
Successful backup to E:\qqfile\backup\20180313152803zip

os.sep 变量的使用方式——它将根据你的操作系统给出相应的分隔符,在
GNU/Linux 与 Unix 中它会是 ‘/’ ,在 Windows 中它会是 ‘\’ ,在 Mac OS 中它会是’:’ 。

第二版

我们的第一版脚本已经能够工作了。然而,我们还可以对它作出一些改进,从而使它能够更好地在每一天都可以正常工作。我们将这一阶段称之为软件的维护(Maintenance)阶段。

我认为有一种颇为有用的改进是起用一种更好的文件命名机制——使用时间作为文件名,存储在以当前日期为名字的文件夹中,这一文件夹则照常存储在主备份目录下。
- 这种机制的第一个优点在于你的备份会以分层的形式予以存储,从而使得它们能更易于管理。
- 第二个优点是文件名能够更短。
- 第三个优点在于由于只有当天进行了备份才会创建相应的目录,独立的目录能够帮助你快速地检查每天是否都进行了备份。

'''
第2版

'''

import os
import time

# 1. 需要备份的文件与目录将被
# 指定在一个列表中。
# 例如在 Windows 下:
# source = ['"C:\\My Documents"', 'C:\\Code']
# 又例如在 Mac OS X 与 Linux 下: source = ['/Users/swa/notes']

source = ["D:\\github\\python\\Deep-Learning\\python\\source"]

# 在这里要注意到我们必须在字符串中使用双引号
# 用以括起其中包含空格的名称。

#2. 备份文件必须存储在一个
#主备份目录中
#例如在 Windows 下:
# target_dir = 'E:\\Backup'
# 又例如在 Mac OS X 和 Linux 下:target_dir = '/Users/swa/backup'
target_dir = 'E:\\qqfile\\backup'

# 要记得将这里的目录地址修改至你将使用的路径

if not os.path.exists(target_dir):
    os.mkdir(target_dir) # 创建目录

# 3. 备份文件将打包压缩成 zip 文件。
# 4. 将当前日期作为主备份目录下的子目录名称
today = target_dir + os.sep + time.strftime('%Y%m%d')
# 将当前时间作为 zip 文件的文件名
now = time.strftime('%H%M%S')
# 如果目标目录还不存在,则进行创建

# zip 文件名称格式
target = today + os.sep + now +'.zip'

if not os.path.exists(today):
    os.mkdir(today) # 创建目录
    print('Successfully created directory', today)

# 5. 我们使用 zip 命令将文件打包成 zip 格式
zip_command = 'zip -r {0} {1}'.format(target,' '.join(source))

# 运行备份   
print('Zip command is:')
print(zip_command)
print('Running:')
if os.system(zip_command) == 0:
    print('Successful backup to', target)
else:
    print('Backup Failed')

Successfully created directory E:\qqfile\backup\20180313
Zip command is:
zip -r E:\qqfile\backup\20180313\154421.zip D:\github\python\Deep-Learning\python\source
Running:
Successful backup to E:\qqfile\backup\20180313\154421.zip

第三版

第二版在我要制作多份备份时能够正常工作,但当备份数量过于庞大时,我便很难找出备份之间有什么区别了。例如,我可能对我的程序或者演示文稿做了重大修改,然后我想将这些修改与 zip 文件的文件名产生关联。这可以通过将用户提供的注释内容添加到文件名中来实现。

预先提醒:下面给出的程序将不会正常工作,所以不必惊慌,只需跟着案例去做因为你要在里面学上一课。

'''
第3版

'''

import os
import time

# 1. 需要备份的文件与目录将被
# 指定在一个列表中。
# 例如在 Windows 下:
# source = ['"C:\\My Documents"', 'C:\\Code']
# 又例如在 Mac OS X 与 Linux 下: source = ['/Users/swa/notes']

source = ["D:\\github\\python\\Deep-Learning\\python\\source"]

# 在这里要注意到我们必须在字符串中使用双引号
# 用以括起其中包含空格的名称。

#2. 备份文件必须存储在一个
#主备份目录中
#例如在 Windows 下:
# target_dir = 'E:\\Backup'
# 又例如在 Mac OS X 和 Linux 下:target_dir = '/Users/swa/backup'
target_dir = 'E:\\qqfile\\backup'

# 要记得将这里的目录地址修改至你将使用的路径

if not os.path.exists(target_dir):
    os.mkdir(target_dir) # 创建目录

# 3. 备份文件将打包压缩成 zip 文件。
# 4. 将当前日期作为主备份目录下的子目录名称
today = target_dir + os.sep + time.strftime('%Y%m%d')
# 将当前时间作为 zip 文件的文件名
now = time.strftime('%H%M%S')
# 如果目标目录还不存在,则进行创建

# 添加一条来自用户的注释以创建
# zip 文件的文件名
comment = input('Enter a comment -->')
# 检查是否有评论键入

if len(comment) == 0:
    target = today + os.sep + now + '_' + comment.replace(' ','_') + '.zip'
else:
    target = today + os.sep + now + '_' + 
    comment.replace(' ','_') + '.zip'


if not os.path.exists(today):
    os.mkdir(today) # 创建目录
    print('Successfully created directory', today)

# 5. 我们使用 zip 命令将文件打包成 zip 格式
zip_command = 'zip -r {0} {1}'.format(target,' '.join(source))

# 运行备份   
print('Zip command is:')
print(zip_command)
print('Running:')
if os.system(zip_command) == 0:
    print('Successful backup to', target)
else:
    print('Backup Failed')

  File "<ipython-input-2-a0cbe1ca32a2>", line 47
    target = today + os.sep + now + '_' +
                                          ^
SyntaxError: invalid syntax

它是如何(不)工作的

这个程序它跑不起来!Python 会说程序之中存在着语法错误,这意味着脚本并未拥有 Python期望看见的结构。当我们观察 Python 给出的错误时,会看见它同时也告诉我们它检测到错误的地方。所以我们开始从那个地方开始对我们的程序进行 Debug 工作。仔细观察,我们会发现有一独立的逻辑行被分成了两行物理行,但我们并未指定这两行物理行应该是一起的。基本上,Python 已经发现了该逻辑行中的加法运算符( + )没有任何操作数,因此它不知道接下来应当如何继续。因此,我们在程序中作出修正。当我们发现程序中的错误并对其进行修正时,我们称为“错误修复(Bug Fixing)”。

'''
第 4 版

'''

import os
import time

# 1. 需要备份的文件与目录将被
# 指定在一个列表中。
# 例如在 Windows 下:
# source = ['"C:\\My Documents"', 'C:\\Code']
# 又例如在 Mac OS X 与 Linux 下: source = ['/Users/swa/notes']

source = ["D:\\github\\python\\Deep-Learning\\python\\source"]

# 在这里要注意到我们必须在字符串中使用双引号
# 用以括起其中包含空格的名称。

#2. 备份文件必须存储在一个
#主备份目录中
#例如在 Windows 下:
# target_dir = 'E:\\Backup'
# 又例如在 Mac OS X 和 Linux 下:target_dir = '/Users/swa/backup'
target_dir = 'E:\\qqfile\\backup'

# 要记得将这里的目录地址修改至你将使用的路径

if not os.path.exists(target_dir):
    os.mkdir(target_dir) # 创建目录

# 3. 备份文件将打包压缩成 zip 文件。
# 4. 将当前日期作为主备份目录下的子目录名称
today = target_dir + os.sep + time.strftime('%Y%m%d')
# 将当前时间作为 zip 文件的文件名
now = time.strftime('%H%M%S')
# 如果目标目录还不存在,则进行创建

# 添加一条来自用户的注释以创建
# zip 文件的文件名
comment = input('Enter a comment -->')
# 检查是否有评论键入

if len(comment) == 0:
    target = today + os.sep + now + '_' + comment.replace(' ','_') + '.zip'
else:
    target = today + os.sep + now + '_' +\
    comment.replace(' ','_') + '.zip'


if not os.path.exists(today):
    os.mkdir(today) # 创建目录
    print('Successfully created directory', today)

# 5. 我们使用 zip 命令将文件打包成 zip 格式
zip_command = 'zip -r -v {0} {1}'.format(target,' '.join(source))

# 运行备份   
print('Zip command is:')
print(zip_command)
print('Running:')
if os.system(zip_command) == 0:
    print('Successful backup to', target)
else:
    print('Backup Failed')

# 这里没有错误的,原书中给出的是 带有错误的示例 for bug fixing
Enter a comment -->test
Zip command is:
zip -r -v E:\qqfile\backup\20180314\102221_test.zip D:\github\python\Deep-Learning\python\source
Running:
Successful backup to E:\qqfile\backup\20180314\102221_test.zip
'''
第 5 版

使用 zipfile 
'''

软件开发流程

  1. What/做什么(分析)
  2. How/怎么做(设计)
  3. Do It/开始做(执行)
  4. Test/测试(测试与修复错误)
  5. Use/使用(操作或开发)
  6. Maintain/维护(改进)

面向对象编程

self

你一定会在想 Python 是如何给 self 赋值的,以及为什么你不必给它一个值。一个例子或许会让这些疑问得到解答。假设你有一个 MyClass 的类,这个类下有一个实例 myobject 。当你调用一个这个对象的方法,如myobject.method(arg1, arg2) 时,Python 将会自动将其转换成 MyClass.method(myobject, arg1, arg2) ——这就是 self 的全部特殊之处所在。这同时意味着,如果你有一个没有参数的方法,你依旧必须拥有一个参数—— self

class Person:
    pass

p = Person()
print(p)
<__main__.Person object at 0x000001C5D62DEE10>
class Person:
    def say_hi(self): # 这个参数 self 是必须有的
        print('Hello,how are you?')

p = Person()
p.say_hi()
Hello,how are you?

init_ 方法

__init__方法会在类的对象被实例化(Instantiated)时立即运行。这一方法可以对任何你想进行操作的目标对象进行初始化(Initialization)操作。这里你要注意在 init 前后加上的双下划线。

class Person:
    def __init__(self, name):
        self.name = name

    def say_hi(self):
        print('Hello, my name is', self.name)

p = Person('Hinton')        
p.say_hi()

Person('Jack').say_hi()
Hello, my name is Hinton
Hello, my name is Jack

类变量与对象变量

我们已经讨论过了类与对象的功能部分(即方法),现在让我们来学习它们的数据部分。数据部分——也就是字段——只不过是绑定(Bound)到类与对象的命名空间(Namespace)的普通变量。这就代表着这些名称仅在这些类与对象所存在的上下文中有效。这就是它们被称作“命名空间”的原因。

字段(Field)有两种类型——类变量与对象变量,它们根据究竟是类还是对象拥有这些变量来进行分类。
类变量(Class Variable)是共享的(Shared)——它们可以被属于该类的所有实例访问。

该类变量只拥有一个副本,当任何一个对象对类变量作出改变时,发生的变动将在其它所有实例中都会得到体现。

对象变量(Object variable)由类的每一个独立的对象或实例所拥有。在这种情况下,每个对象都拥有属于它自己的字段的副本,也就是说,它们不会被共享,也不会以任何方式与其它不同实例中的相同名称的字段产生关联。

# coding=UTF-8

class Robot:
    """表示有一个带有名字的机器人。"""

    # 一个类变量,用来计数机器人的数量
    population = 0

    def __init__(self, name):
        """初始化数据"""
        # 对象变量          
        self.name = name
        print('(Initializing {})'.format(self.name))

        # 当有人被创建时,机器人
        # 将会增加人口数量
        Robot.population +=1

    def die(self):
        """我挂了。"""
        print('{} is being destroyed!'.format(self.name))

        Robot.population -= 1

        if Robot.population == 0:
            print('{} was the last one.'.format(self.name))
        else:
            print("There are still {:d} robots working.".format(Robot.population))


    def say_hi(self):
        """来自机器人的诚挚问候

        没问题,你做得到。"""
        print("Greetings, my masters call me {}".format(self.name))


    @classmethod
    def how_many(cls):
        """打印出当前的人口数量"""
        print("we have {:d} robots.".format(cls.population))


droid1 = Robot("R2-D2")        
droid1.say_hi()
Robot.how_many()

droid2 = Robot('C-3PO')
droid2.say_hi()
Robot.how_many()


print("\nRobots can do some work here.\n")

print("Robots have finished their work. So let's destroy them.")

droid1.die()
droid2.die()

Robot.how_many()
(Initializing R2-D2)
Greetings, my masters call me R2-D2
we have 1 robots.
(Initializing C-3PO)
Greetings, my masters call me C-3PO
we have 2 robots.

Robots can do some work here.

Robots have finished their work. So let's destroy them.
R2-D2 is being destroyed!
There are still 1 robots working.
C-3PO is being destroyed!
C-3PO was the last one.
we have 0 robots.
print(Robot.__doc__)
Robot.say_hi.__doc__
表示有一个带有名字的机器人。





'来自机器人的诚挚问候\n\n        没问题,你做得到。'

继承

面向对象编程的一大优点是对代码的重用(Reuse),重用的一种实现方法就是通过继承(Inheritance)机制。继承最好是想象成在类之间实现类型与子类型(Type and Subtype)关系的工具。

SchoolMember 类会被称作基类(Base Class) 或是超类(Superclass)。 Teacher 和 Student 类会被称作派生类(Derived Classes) 或是子类(Subclass)。

# coding=UTF-8

class SchoolMember:
    '''代表任何学校里的成员。'''
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print('(Initialized SchoolMember: %s)'%self.name)

    def tell(self):
        '''告诉我有关我的细节。'''
        print('Name:"{}" Age:"{}"'.format(self.name, self.age),end=" ")

class Teacher(SchoolMember):
    '''代表一位老师。'''
    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)
        self.salary = salary
        print('(Initialized Teacher: {})'.format(self.name))

    def tell(self):
        SchoolMember.tell(self)
        print('Salary: "{:d}"'.format(self.salary))


class Student(SchoolMember):
    '''代表一位学生。'''
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)
        self.marks = marks
        print('(Initialized Student: {})'.format(self.name))

    def tell(self):
        SchoolMember.tell(self)
        print('Marks: "{:d}"'.format(self.marks))


t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 25, 75)


print()

members = [t, s]

for member in members:
    member.tell()




(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)

Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"25" Marks: "75"

输入与输出

有些时候你的程序会与用户产生交互。举个例子,你会希望获取用户的输入内容,并向用户打印出一些返回的结果。我们可以分别通过 input() 函数与 print 函数来实现这一需求。
对于输入,我们还可以使用 str (String,字符串)类的各种方法。例如,你可以使用rjust 方法来获得一个右对齐到指定宽度的字符串。你可以查看 help(str) 来了解更多细节。
另一个常见的输入输出类型是处理文件。创建、读取与写入文件对于很多程序来说是必不可少的功能,而我们将在本章探讨这一方面。

'''
用户输入内容

palindrome 回文
'''

def reverse(text):
    # 切片功能翻转文本 ,-1 从倒数第一个开始倒着输出
    return text[::-1] 

def is_palindrome(text):
    return text == reverse(text)


something  = input('Enter text:')

if is_palindrome(something):
    print('Yes, it is a palindrome')
else:
    print('No, it is not a palindrome')

Enter text:txtxtxt
Yes, it is a palindrome

我们已经了解了我们可以通过使用 seq[a:b] 来从位置 a 开始到位置 b 结束来对序列进行切片 。我们同样可以提供第三个参数来确定切片的步长(Step)。默认的步长为 1 ,它会返回一份连续的文本。如果给定一个负数步长,如 -1 ,
将返回翻转过的文本。

作业练习

要想检查文本是否属于回文需要忽略其中的标点、空格与大小写。例如,“Rise to vote, sir.”是一段回文文本,但是我们现有的程序不会这么认为。你可以改进上面的程序以使它能够识别这段回文吗?

'''
作业练习

检查文本是否属于回文,忽略其中的标点、空格与大小写

提示:

使用一个元组(你可以在这里找到一份列出所有标点符号的列表)来保存所有需要禁
用的字符,然后使用成员资格测试来确定一个字符是否应该被移除,即 forbidden = ( ! ,
? , . , ...)。
'''

文件

你可以通过创建一个属于 file 类的对象并适当使用它的 read 、 readline 、 write 方法来打开或使用文件,并对它们进行读取或写入。读取或写入文件的能力取决于你指定以何种方式打开文件。最后,当你完成了文件,你可以调用 close 方法来告诉 Python 我们已经完成了对该文件的使用。

poem = '''\
Programming is fun
When the work is done
if you wanna make your work also fun:
    use Python!
'''

# 打开文件以编辑('w'riting)
f = open('test.txt', 'w')
# 向文件中编写文本
f.write(poem)
# 关闭文件
f.close()


# 如果没有特别指定,
# 将假定启用默认的阅读('r'ead)模式
f = open('test.txt', 'r')
while True:
    line = f.readline()
    # 零长度指示 EOF
    if len(line) == 0:
        break
    # 每行(`line`)的末尾
    # 都已经有了换行符
    #因为它是从一个文件中进行读取的
    print(line, end='')
# 关闭文件
f.close()
Programming is fun
When the work is done
if you wanna make your work also fun:
    use Python!

首先,我们使用内置的 open 函数并指定文件名以及我们所希望使用的打开模式来打开一个文件。打开模式可以是阅读模式( ‘r’ ),写入模式( ‘w’ )和追加模式( ‘a’ )。我们还可以选择是通过文本模式( ‘t’ )还是二进制模式( ‘b’ )来读取、写入或追加文本。实际上还有其它更多的模式可用, help(open) 会给你有关它们的更多细节。在默认情况下, open() 会将文件视作文本(text)文件,并以阅读(read)模式打开它。

Pickle

Python 提供了一个叫作 Pickle 的标准模块,通过它你可以将任何纯 Python 对象存储到一个文件中,并在稍后将其取回。这叫作持久地(Persistently)存储对象。

import pickle


# 我们存储相关对象的文件的名称
shoplistfile = 'shoplist.data'
# 需要购买的物品清单
shoplist = ['apple', 'mango', 'carrot']

# 准备写入文件
f = open(shoplistfile, 'wb')
# 转储对象至文件
pickle.dump(shoplist, f)
f.close()

# 清除 shoplist 变量
del shoplist

# 重新打开存储文件
f = open(shoplistfile, 'rb')

# 从文件中载入对象
storedlist = pickle.load(f)
print(storedlist)
['apple', 'mango', 'carrot']

要想将一个对象存储到一个文件中,我们首先需要通过 open 以写入(write)二进制(binary)模式打开文件,然后调用 pickle 模块的 dump 函数。这一过程被称作封装(Pickling)。

接着,我们通过 pickle 模块的 load 函数接收返回的对象。这个过程被称作拆封(Unpickling)。

Unicode

截止到现在,当我们编写或使用字符串、读取或写入某一文件时,我们用到的只是简单的英语字符。

当我们阅读或写入某一文件或当我们希望与互联网上的其它计算机通信时,我们需要将我们的 Unicode 字符串转换至一个能够被发送和接收的格式,这个格式叫作“UTF-8”。我们可以在这一格式下进行读取与写入,只需使用一个简单的关键字参数到我们的标准 open 函数中:

print(u"Hello, world")
type(u'Hello, world')
Hello, world





str
# encoding=UTF-8
import io

f = io.open('test.txt', 'at', encoding='utf-8')
f.write(u'Imagine non-English language here')
f.close()

text = io.open('test.txt', encoding='utf-8').read()
print(text)
Programming is fun
When the work is done
if you wanna make your work also fun:
    use Python!
Imagine non-English language hereImagine non-English language here

每当我们诸如上面那番使用 Unicode 字面量编写一款程序时,我们必须确保 Python 程序已经被告知我们使用的是 UTF-8,因此我们必须将 # encoding=utf-8 这一注释放置在我们程序的顶端。

异常

Print("Hello World")
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
NameError: name 'Print' is not defined

错误

NameError 错误被抛出,同时 Python 还会打印出检测到的错误发生的位
置。这就是一个错误错误处理器(Error Handler)

s = input('Enter something --> ')
Enter something --> Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
EOFError

此处 Python 指出了一个称作 EOFError 的错误,代表着它发现了一个文件结尾(End of File)符号(由 ctrl-d 实现)在不该出现的时候出现了。

处理异常

我们可以通过使用 try..except 来处理异常状况。一般来说我们会把通常的语句放在 try 代码块中,将我们的错误处理器代码放置在 except 代码块中。

try:
    text = input('Enter something --> ')
except EOFError:
    print('Why did you do an EOF on me?')
except KeyboardInterrupt:
    print('You cancelled the operation.')
else:
    print('You entered {}'.format(text))
Enter something --> what
You entered what
# Press ctrl + d
$ python exceptions_handle.py
Enter something --> Why did you do an EOF on me?

# Press ctrl + c
$ python exceptions_handle.py
Enter something --> ^CYou cancelled the operation.

$ python exceptions_handle.py
Enter something --> No exceptions
You entered No exceptions

抛出异常

你可以通过 raise 语句来引发一次异常,具体方法是提供错误名或异常名以及要抛出(Thrown)异常的对象。
你能够引发的错误或异常必须是直接或间接从属于 Exception (异常) 类的派生类。

# encoding=utf-8

class ShortInputException(Exception):
    '''一个由用户定义的异常类'''
    def __init__(self, length, atleast):
        Exception.__init__(self)
        self.length = length
        self.atleast = atleast

try:
    text = input('Enter something -->')
    if len(text) < 3:
        raise ShortInputException(len(text), 3)
    # 其他工作能在此处继续正常运行
except EOFError:
    print('Why did you do an EOF on me?')
except  ShortInputException  as ex:
    print(('ShortInputException: The input was ' + '{0} long, expected at least {1}').format(ex.length, ex.atleast))
else:
    print('No exception was raised.')
Enter something -->w
ShortInputException: The input was 1 long, expected at least 3

Try … Finally

假设你正在你的读取中读取一份文件。你应该如何确保文件对象被正确关闭,无论是否会发生异常?这可以通过 finally 块来完成。

import sys
import time

f = None
try:
    f = open('test.txt')
    # 我们常用的文件阅读风格
    while True:
        line  = f.readline()
        if len(line) == 0:
            break
        print(line, end='')
        sys.stdout.flush()
        print('Press ctrl +c now')
        # 为了确保它能运行一段时间
        time.sleep(2)
except IOError:        
    print("Could not find file poem.txt")
except KeyboardInterrupt:
    print("!! You cancelled the reading from the file.")
finally:
    if f:
        f.close()
    print("(Cleaning up: Closed the file)")  
Programming is fun
Press ctrl +c now
When the work is done
Press ctrl +c now
if you wanna make your work also fun:
Press ctrl +c now
    use Python!
Press ctrl +c now
Imagine non-English language hereImagine non-English language herePress ctrl +c now
(Cleaning up: Closed the file)

with 语句

在 try 块中获取资源,然后在 finally 块中释放资源是一种常见的模式。因此,还有一个with 语句使得这一过程可以以一种干净的姿态得以完成。

with open('test.txt') as f:
    for line in f:
        print(line, end='')
Programming is fun
When the work is done
if you wanna make your work also fun:
    use Python!
Imagine non-English language hereImagine non-English language here

程序输出的内容应与上一个案例所呈现的相同。本例的不同之处在于我们使用的是 open 函数与 with 语句——我们将关闭文件的操作交由 with open 来自动完成。

在幕后发生的事情是有一项 with 语句所使用的协议(Protocol)。它会获取由 open 语句返回的对象,在本案例中就是“thefile”。

它总会在代码块开始之前调用 thefile.enter 函数,并且总会在代码块执行完毕之后调用 thefile.exit

因此,我们在 finally 代码块中编写的代码应该格外留心 exit 方法的自动操作。这能够帮助我们避免重复显式使用 try..finally 语句。

标准库

Python 标准库(Python Standrad Library)中包含了大量有用的模块,同时也是每个标准的Python 安装包中的一部分。熟悉 Python 标准库十分重要,因为只要你熟知这些库可以做到什么事,许多问题都能够轻易解决。

我们将探索这个库中的一些常用模块。你能在你的 Python 安装包中附带的文档中的“库概览(Library Reference)” 部分中查找到所有模块的全部细节。

sys 模块

sys 模块包括了一些针对特定系统的功能。我们已经了解过 sys.argv 列表中包括了命令行参数。

import sys
sys.version_info
sys.version_info(major=3, minor=6, micro=2, releaselevel='final', serial=0)
sys.version_info.major == 3
True

sys 模块包含一个 version_info 元组,它提供给我们版本信息。第一个条目是主版本信息。我们可以调出这些信息并使用它。

日志模块

如果你想将一些调试(Debugging)信息或一些重要的信息储存在某个地方,以便你可以检查你的程序是否如你所期望那般运行,应该怎么做?你应该如何将这些信息“储存在某个地方”?这可以通过 logging 模块来实现。

import os
import platform
import logging

if platform.platform().startswith('Windows'):
    logging_file = os.path.join(os.getenv('HOMEDRIVE'),
                                os.getenv('HOMEPATH'),'test.log')
else:
    logging_file = os.path.join(os.getenv('HOME'),'test.log')

print("Logging to ",logging_file)    

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s : %(levelname)s : %(message)s',
    filename=logging_file,
    filemode='w')

logging.debug('"Start of the program')
logging.info('Doing something')
logging.warning('Dying now')
Logging to  C:\Users\qhtf\test.log

format=’%(asctime)s : %(levelname)s : %(message)s’

2018-03-15 10:03:40,392 : DEBUG : “Start of the program
2018-03-15 10:03:40,393 : INFO : Doing something
2018-03-15 10:03:40,393 : WARNING : Dying now

我们使用了三款标准库中的模块—— os 模块用以和操作系统交互, platform 模块用以获取平台——操作系统——的信息, logging 模块用来记录(Log)信息。

每周模块系列

标准库中还有许多模块值得探索,例如一些用以调试(Debugging)的模块, 处理命令行选项的模块,正则表达式(Regular Expressions)模块 等等等等。
进一步探索标准库的最好方法是阅读由 Doug Hellmann 撰写的优秀的 Python Module of the Week 系列(你还可以阅读它的实体书或是阅读 Python 官方文档)。

总结

我们已经探索了 Python 标准库中提供的诸多的模块的一些功能。在此强烈建议你浏览Python 标准库文档来了解所有可以使用的模块。
接下来,我们将介绍 Python 的其它各个方面,让我们的 Python 之旅更加完整。

传递元组

你可曾希望从一个函数中返回两个不同的值?你能做到的。只需要使用一个元组。

'''
在学习 DL 课程的过程中,jupyter notebook 形式的作业里,
吴恩达老师的团队,在里面每个大体的函数框架中,
对于在前向传播中,得到的一些值,cache 存储起来,以便反向传播的时候使用
经常存储的数据结构使用的就是 DIC 字典,Tuple 元组 ,list

'''

def get_error_details():
    return (2,'details')

errnum, errstr = get_error_details()
print(errnum)
print(errstr)
2
details

特殊方法

诸如 __init____del__ 等一些方法对于类来说有特殊意义。

特殊方法用来模拟内置类型的某些行为。举个例子,如果你希望为你的类使用 x[key] 索引操作(就像你在列表与元组中使用的那样),那么你所需要做的只不过是实现__getitem__() 方法,然后你的工作就完成了。如果你试图理解它,就想想 Python 就是对list 类这样做的!

  • __init__(self, ...)
    • 这一方法在新创建的对象被返回准备使用时被调用。
  • __del__(self)
    • 这一方法在对象被删除之前调用(它的使用时机不可预测,所以避免使用它)
  • __str__(self)
    • 当我们使用 print 函数时,或 str() 被使用时就会被调用。
  • __lt__(self, other)
    • 当小于运算符(<)被使用时被调用。类似地,使用其它所有运算符(+、> 等等)时都会有特殊方法被调用。
  • __getitem__(self, key)
    • 使用 x[key] 索引操作时会被调用。
  • __len__(self)
    • 当针对序列对象使用内置 len() 函数时会被调用

Lambda

lambda 语句可以创建一个新的函数对象。从本质上说, lambda 需要一个参数,后跟一个表达式作为函数体,这一表达式执行的值将作为这个新函数的返回值。

points = [{'x':2, 'y':3},
          {'x':4, 'y':1}]
# 按照每个字典中 y 值的大小来排序
points.sort(key=lambda i: i['y'])
print(points)
[{'x': 4, 'y': 1}, {'x': 2, 'y': 3}]

要注意到一个 list 的 sort 方法可以获得一个 key 参数,用以决定列表的排序方式(通常我们只知道升序与降序)。在我们的案例中,我们希望进行一次自定义排序,为此我们需要编写一个函数,但是又不是为函数编写一个独立的 def 块,只在这一个地方使用,因此我们使用 Lambda 表达式来创建一个新函数。

列表推导

列表推导(List Comprehension)用于从一份现有的列表中得到一份新列表。想象一下,现在你已经有了一份数字列表,你想得到一个相应的列表,其中的数字在大于 2 的情况下将乘以2。列表推导就是这类情况的理想选择。

listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
print(listtwo)
[6, 8]

在函数中接收元组与字典

有一种特殊方法,即分别使用 * 或 ** 作为元组或字典的前缀,来使它们作为一个参数为函数所接收。当函数需要一个可变数量的实参时,这将颇为有用。

def powersum(power, *args):
    '''Return the sum of each argument raised to the specified power.'''
    total = 0
    for i in args:
        total += pow(i, power)
    return total

print(powersum(2,3,4))    
print(powersum(3,1,3,2,2))
25
44

assert 语句

assert 语句用以断言(Assert)某事是真的。例如说你非常确定你正在使用的列表中至少包含一个元素,并想确认这一点,如果其不是真的,就抛出一个错误, assert 语句就是这种情况下的理想选择。当语句断言失败时,将会抛出 AssertionError 。

mylist = ['wow', 'opps']

assert len(mylist) >= 1

mylist.pop()

assert len(mylist) >= 1

mylist.pop()

assert len(mylist) >= 1
---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-33-f567f021077a> in <module>()
      9 mylist.pop()
     10 
---> 11 assert len(mylist) >= 1


AssertionError: 

装饰器(Decorators)

装饰器(Decorators)是应用包装函数的快捷方式。这有助于将某一功能与一些代码一遍又一遍地“包装”。举个例子,我为自己创建了一个 retry 装饰器,这样我可以将其运用到任何函数之中,如果在一次运行中抛出了任何错误,它就会尝试重新运行,直到最大次数 5 次,并且每次运行期间都会有一定的延迟。这对于你在对一台远程计算机进行网络调用的情况十分有用:

from time import sleep
from functools import wraps
import logging
logging.basicConfig()
log = logging.getLogger('retry')


def retry(f):
    @wraps(f)
    def wrapped_f(*args, **kwargs):
        MAX_ATTEMPTS = 5
        for attempt in range(1, MAX_ATTEMPTS + 1):
            try:
                return f(*args, **kwargs)
            except:
                log.exception("Attempt %s/%s failed : %s",
                             attempt,
                             MAX_ATTEMPTS,
                             (args, kwargs))
                sleep(10 * attempt)

        log.critical("All %s attempt failed : %s",
                    MAX_ATTEMPTS,
                    (args, kwargs))
    return wrapped_f

counter = 0

@retry
def save_to_database(arg):
    print("Write to a database or make a network call or etc.")
    print("This will be automatically retried if exception is thrown.")

    global counter
    counter += 1

    # 这将在第一次调用时抛出异常
    # 在第二次运行时将正常工作(也就是重试)
    if counter < 2:
        raise ValueError(arg)

if __name__ == '__main__'        :
    save_to_database('Some bad value')

Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.
Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.

未来还有很长的路要走。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值