地址合成脚本实战

主要的知识点

目的:通过编写一个命令行窗口工具,随机生成大量的地址Json数据,用于实际的地址数据测试

读写文件操作

Python内置了读写文件的函数,用法和C是兼容的。

  • 读文件,可以使用try…finally来实现
try:
    f = open('/path/to/file', 'r')
    print f.read()
finally:
    if f:
        f.close()

很麻烦,使用with来代替,会自动的条用close来关闭流

with open('/path/to/file', 'r') as f:
print f.read()

调用

  • f.read() 会一次性的读取文件的全部内容。保险起见,
  • f.read(size)指定缓存来控制内存的使用
  • f.readline()可以每次读取一行内容
  • readlines()一次读取所有内容并按行返回list

file-like Object

像open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object。除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()方法就行。StringIO就是在内存中创建的file-like Object,常用作临时缓冲。

  • 二进制文件
f = open('/Users/michael/test.jpg', 'rb')

在Python中默认的读取以ASCII编码格式来读取,在python中默认读入内存的数据就是ASCII编码格式,所有的内容都会转换为ASCII在内存中保留

  • 字符编码

读取非ASCII编码的文本文件,就必须以二进制模式打开,再解码

  • 打开文件自动转码,(下面代码的意思是编码格式为ASCII格式,如果非ASCII格式需要以rb格式打开)

    import codecs
    with codecs.open('/Users/michael/gbk.txt', 'r', 'gbk') as f:
       f.read() # u'\u6d4b\u8bd5'\

写文件

类似的操作都是,只是不同的选项记住

  • ‘w’中表示已覆盖的的方式写入
  • ‘a’表示追加的方式写入
  • ‘+’表示读写的方式,如w+
  • rb:以二进制读模式打开

编码格式检测

import chardet.universaldetector
# 编码检测
bytes = min(32, os.path.getsize(file_path))
raw = open(file_path, 'rb').read(bytes)
encoding_type = chardet.detect(raw)

返回的encoding_type就是读取的文件的格式

Python中的编码问题

代码面前的# -- coding: utf-8 -- 表明,Python 代码由 utf-8 编码。两个 Python 字符串类型间可以用 encode / decode 方法转换:

编码 encode
u.encode('utf-8') # 以 utf-8 的格式编码  ASCII ——> utf-8
解码 decode 
print s.decode('utf-8')   # 以utf-8的格式解码  utf-8 ——> ASCII

因为 Python 中认为 16 位的 unicode 才是字符的唯一内码,而大家常用的字符集如 gb2312,gb18030/gbk,utf-8,以及 ascii 都是字符的二进制(字节)编码形式。把字符从 unicode 转换成二进制编码,当然是要 encode。

  • 在进行同时包含 str 与 unicode 的运算时,Python 一律都把 str 转换成 unicode 再运算,建议是在代码里的中文字符串前写上 u

    u = u'关关雎鸠'
    

文件目录的操作

这里会遇到一个问题就在于当我们的路径中含有中文时,如果编码的格式没有处理好,会让我们无法判断正确的文件,可以使用unicode(path,”utf-8”),将路径编码为utf-8格式。常用到的操作文件、文件夹的模块有两个os模块shutil模块

  • os.getcwd() 得到当前工作目录,即当前Python脚本工作的目录路径
  • os.listdir() 返回指定目录下的所有文件和目录名
  • os.path.split() 返回一个路径的目录名和文件名

    eg os.path.split('/home/swaroop/byte/code/poem.txt')
    结果为 (‘/home/swaroop/byte/code’, ‘poem.txt’)`

  • os.path.splitext() 分离扩展名

  • os.path.dirname() 获取路径名
  • os.path.basename() 获取文件名
  • os.getenv() 与os.putenv() 读取和设置环境变量
  • os.linesep 给出当前平台使用的行终止符,Windows使用’\r\n’,Linux使用’\n’而Mac使用’\r’
  • os.name 指示你正在使用的平台,对于Windows,它是’nt’,而对于Linux/Unix用户,它是’posix’
  • os.rename(old, new)重命名
  • os.makedirs(r“c:\python\test”) 创建多级目录 os.mkdir(“test”)创建单个目录
  • os.stat(file)获取文件属性
  • os.chmod(file)修改文件权限和属性
  • os.exit()终止当前进程
  • os.path.getsize(filename)获取文件大小

用法用例

  • 创建空文件 os.mknod(“test.txt”)
  • 把文件裁成规定的大小 fp.truncate([size]),如果按行的话,直接丢到linux服务器,用wc命令
  • 将文件打操作标记移到offset的位置
  • 复制文件
    • shutil.copyfile(“oldfile”,”newfile”) #oldfile和newfile都只能是文件
    • shutil.copy(“oldfile”,”newfile”) #oldfile只能是文件夹,newfile可以是文件,也可以是目标目录
  • 复制文件夹 shutil.copytree(“olddir”,”newdir”) #olddir和newdir都只能是目录,且newdir必须不存在
  • 移动文件或者目录 shutil.move(“oldpos”,”newpos”)
  • 删除
    • os.remove(“file”) 删除文件
    • os.rmdir(“dir”) #只能删除空目录
    • shutil.rmtree(“dir”) #空目录、有内容的目录都可以删
    • os.chdir(“path”) #换路径

递归读取文件夹下的所有文件

def get_all_path(path, file_list, include_suffix_name=include_file_suffix_name, exclude_file_name=exclude_file_name):
#    path = path.replace("\\", "/")
if os.path.exists(path):
    for sub_path in os.listdir(path):
        m_path = os.path.join(path, sub_path)
        if os.path.isdir(m_path):
            get_all_path(m_path, file_list)
        else:
            # os.path.splitext(sub_path) 分割出文件与文件扩展名
            suffix_name = os.path.splitext(sub_path)[-1]
            file_name = os.path.splitext(sub_path)[0]
            if suffix_name in include_suffix_name and file_name not in exclude_file_name:
                file_list.append(m_path)
else:
    print('error! the input path is not dir')

时间和日期的操作

python中有一个库佳作datetime模块。datetime是模块,datetime模块还包含一个datetime类

  • 获取当前时间

    from datetime import datetime
    now = datetime.now() # 获取当前datetime
    
  • 按照指定日期和时间

    t = datetime(2015, 4, 19, 12, 20) # 用指定日期时间创建datetime
    
  • datetime转换为timestamp,浮点数

计算机中的时间是以相对于1970年1月1日 00:00:00 UTC+00:00时区的时刻来的

>>> from datetime import datetime
>>> dt = datetime(2015, 4, 19, 12, 20) # 用指定日期时间创建datetime
>>> dt.timestamp() # 把datetime转换为timestamp
1429417200.0
  • timestamp转换为datetime 可以使用 datetime.fromtimestamp(t)

  • str转换为datetime

    以从字符串中解析出一个标准的datetime对象

    >>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
    >>> print(cday)
    2015-06-01 18:19:59
  • datetime转换为str

主要的是其中的日期表示,%Y-%m-%d %H:%M:%S表示年、月、天、时、分、秒,如下可以看出

now.strftime('%a, %b %d %H:%M')  # Mon, May 05 16:28
  • datetime加减

导入timedelta这个类,可以将时间日期格式按照+、- 来操作

>>> from datetime import datetime, timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2015, 5, 18, 16, 57, 3, 540997)
>>> now + timedelta(hours=10)
datetime.datetime(2015, 5, 19, 2, 57, 3, 540997)
>>> now - timedelta(days=1)
datetime.datetime(2015, 5, 17, 16, 57, 3, 540997)
>>> now + timedelta(days=2, hours=12)
datetime.datetime(2015, 5, 21, 4, 57, 3, 540997)
  • 本地时间转换为UTC时间

一个datetime类型有一个时区属性tzinfo,但是默认为None,所以无法区分这个datetime到底是哪个时区

>>> from datetime import datetime, timedelta, timezone
>>> tz_utc_8 = timezone(timedelta(hours=8)) # 创建时区UTC+8:00
>>> now = datetime.now()
>>> now
datetime.datetime(2015, 5, 18, 17, 2, 10, 871012)
>>> dt = now.replace(tzinfo=tz_utc_8) # 强制设置为UTC+8:00
>>> dt
datetime.datetime(2015, 5, 18, 17, 2, 10, 871012, tzinfo=datetime.timezone(datetime.timedelta(0, 28800)))
  • 时区转换

先通过utcnow()拿到当前的UTC时间,再转换为任意时区的时间

# 拿到UTC时间,并强制设置时区为UTC+0:00:
>>> utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
>>> print(utc_dt)
2015-05-18 09:05:12.377316+00:00
# astimezone()将转换时区为北京时间:
>>> bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
>>> print(bj_dt)
2015-05-18 17:05:12.377316+08:00
# astimezone()将转换时区为东京时间:
>>> tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt)
2015-05-18 18:05:12.377316+09:00
# astimezone()将bj_dt转换时区为东京时间:
>>> tokyo_dt2 = bj_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt2)
2015-05-18 18:05:12.377316+09:00

迭代器和生成器

生成器 generator

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误

  • 第一种方法很简单,只要把一个列表生成式的[]改成()eg >> g = (x*x for x in range(1,10))
  • 包含yield关键词,一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。

调用next(g)就可以每次之生成指定想要的数据。也可以用使用for来迭代。比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

可迭代对象和迭代器

迭代器一定是可迭代对象,

map和 reduce函数

这两个函数非常的好用,对于两个等长度类型的列表A和B,

  • map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回

    >>> def f(x):
    ... return x * x
    ...
    >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    >>> list(r)
    [1, 4, 9, 16, 25, 36, 49, 64, 81]

    当然 f可以使用lambda表达式来表示, f = lambda x, x*x

  • reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算

    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
    

命令行解析

从网上来看,有两种方法在看来比较优,一种是基于argparse解析器,一种是docopt。其中argparse是基于标准的python库的,而docpoct虽然很强大,但是需要额外的安装一些内容。

使用 argparse

主要的步骤有三个,1. 生成一个argparse解析对象 2. 增加参数 3.解析参数

创建一个解析器

使用用法就是 parser = argparse.ArgumentParser(description='Process some integers.'),其中ArgumentParser对象中就保存了命令行解析成python数据类型的所有信息。下面为官方的帮助文档

Definition : ArgumentParser(...)

Type : Function of argparse module

Object for parsing command line strings into Python objects.

Keyword Arguments:
prog – The name of the program (default: sys.argv[0])  程序的名字(默认:sys.argv[0],在帮助信息中都可以使用%(prog)s格式符得到程序的名字
usage – A usage message (default: auto-generated from arguments) 用法,可自动从参数中生成
description – A description of what the program does 
epilog – Text following the argument descriptions
parents – Parsers whose arguments should be copied into this one
formatter_class – HelpFormatter class for printing help messages
prefix_chars – Characters that prefix optional arguments 可选参数的前缀字符集(默认:‘-‘)
fromfile_prefix_chars – Characters that prefix files containing 
additional arguments 额外的参数应该读取的文件的前缀字符集(默认:None)
argument_default – The default value for all arguments
conflict_handler – String indicating how to handle conflicts
add_help – Add a -h/-help option 给解析器添加-h/–help 选项(默认:True)
allow_abbrev – Allow long options to be abbreviated unambiguously
增加参数
ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
定义应该如何解析一个命令行参数。下面每个参数有它们自己详细的描述,简单地讲它们是:

name or flags - 选项字符串的名字或者列表,例如foo 或者-f, --foo。
action - 在命令行遇到该参数时采取的基本动作类型。
nargs - 应该读取的命令行参数数目。
const - 某些action和nargs选项要求的常数值。
default - 如果命令行中没有出现该参数时的默认值。
type - 命令行参数应该被转换成的类型。
choices - 参数可允许的值的一个容器。
required - 该命令行选项是否可以省略(只针对可选参数)。
help - 参数的简短描述。
metavar - 参数在帮助信息中的名字。
dest - 给parse_args()返回的对象要添加的属性名称。
解析参数

默认情况下,参数字符串取自于sys.argv,并创建一个空的Namespace对象用于保存属性。

格式化编码

  • 字符串对象的 str.rjust() 方法的作用是将字符串靠右,并默认在左边填充空格,类似的方法还有 str.ljust()str.center()

  • str.format()比较常用,使用{}占位符,可选项':'和格式标识符可以跟着 field name,这样可以进行更好的格式化

    python
    print('We are the {} who say "{}!"'.format('knights', 'Ni'))
    # 使用了关键字参数
    print('{0} and {1}'.format('Kobe', 'James'))
    print('The {thing} is {adj}.'.format(thing='flower', adj='beautiful'))
    # 指定宽度格式化
    print('The value of PI is {0:.3f}.'.format(math.pi))

  • % 操作符也可以实现字符串格式化。它将左边的参数作为类似 sprintf() 式的格式化字符串,而将右边的代入 print('The value of PI is %10.3f.' %math.pi)

随机数

print("随机生成一个0到99之间的数字:",random.randint(0,99))
print("随机生成一个1到100之间的偶数:",random.randrange(0,101,2))
print("实现一个0到1之间的浮点数:",random.random())
a,b=0,5
print("随机生成(a,b)之间的浮点数:",random.uniform(a,b))
print("随机字符:在指定的范围内随机取样一个:",random.choice(range(1,3)))
print("随机选取字符串:在指定范围内随机你随机取样多个:",random.choices(['one','two','three','four']))
print("多个字符串中选取特定的字符:",random.sample('abcdefghijk',3))

参考:
廖雪峰Python教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值