美文网首页
python学习日记-2016.7.26

python学习日记-2016.7.26

作者: 这是朕的江山 | 来源:发表于2016-07-26 15:19 被阅读163次

    1.datetime

    datetime是Python处理日期和时间的标准库。它的用法如下:
    a.获取当前时间

    >>> from datetime import datetime
    >>> now = datetime.now() # 获取当前datetime
    >>> print(now)
    

    b.获取指定时间和日期

    >>> from datetime import datetime
    >>> dt = datetime(2015, 4, 19, 12, 20) # 用指定日期时间创建datetime
    >>> print(dt)
    

    c.datetime转换为timestamp
    在计算机中,时间实际上是用数字表示的。我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time,记为0
    (1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestamp。timestamp的值与时区毫无关系,因为timestamp一旦确定,其UTC时间就确定了,转换到任意时区的时间也是完全确定的,这就是为什么计算机存储的当前时间是以timestamp表示的,因为全球各地的计算机在任意时刻的timestamp都是完全相同的(假定时间已校准)。

    >>> from datetime import datetime
    >>> dt = datetime(2015, 4, 19, 12, 20) # 用指定日期时间创建datetime
    >>> dt.timestamp()
    

    d.timestamp转换为datetime

    >>> from datetime import datetime
    >>> t = 1429417200.0
    >>> print(datetime.fromtimestamp(t))
    >>> print(datetime.utcfromtimestamp(t)) # UTC时间
    

    e.str转换为datetime

    >>> from datetime import datetime
    >>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
    >>> print(cday)
    

    f.datetime转换为str

    >>> from datetime import datetime
    >>> now = datetime.now()
    >>> print(now.strftime('%a, %b %d %H:%M'))
    Mon, May 05 16:28
    

    g.时区转换

    # 拿到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
    

    2namedtuple

    namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。

    这样一来,我们用namedtuple可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。

    >>> from collections import namedtuple
    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> p = Point(1, 2)
    >>> p.x1
    >>> p.y2
    

    3.deque

    使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。

    deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

    >>> from collections import deque
    >>> q = deque(['a', 'b', 'c'])
    >>> q.append('x')
    >>> q.appendleft('y')
    >>> q
    deque(['y', 'a', 'b', 'c', 'x'])
    

    4.defaultdict

    使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:

    >>> from collections import defaultdict
    >>> dd = defaultdict(lambda: 'N/A')
    >>> dd['key1'] = 'abc'
    >>> dd['key1'] # key1存在
    'abc'
    >>> dd['key2'] # key2不存在,返回默认值
    'N/A'
    

    注意默认值是调用函数返回的,而函数在创建defaultdict对象时传入。
    除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。

    5.OrderedDict

    使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。如果要保持Key的顺序,可以用OrderedDict:

    >>> from collections import OrderedDict
    >>> d = dict([('a', 1), ('b', 2), ('c', 3)])
    >>> d # dict的Key是无序的
    {'a': 1, 'c': 3, 'b': 2}
    >>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
    >>> od # OrderedDict的Key是有序的
    OrderedDict([('a', 1), ('b', 2), ('c', 3)])
    

    6.Counter

    Counter是一个简单的计数器,例如,统计字符出现的个数:

    >>> from collections import Counter
    >>> c = Counter()
    >>> for ch in 'programming':
    ...  c[ch] = c[ch] + 1...
    >>> c
    Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
    

    Counter实际上也是dict的一个子类,上面的结果可以看出,字符'g'、'm'、'r'各出现了两次,其他字符各出现了一次。

    7.base64

    Base64是一种用64个字符来表示任意二进制数据的方法。

    用记事本打开exe、jpg、pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进制数据,就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。
    Base64编码会把3字节的二进制数据编码为4字节的文本数据,长度增加33%,好处是编码后的文本数据可以在邮件正文、网页等直接显示。

    如果要编码的二进制数据不是3的倍数,最后会剩下1个或2个字节怎么办?Base64用\x00字节在末尾补足后,再在编码的末尾加上1个或2个=号,表示补了多少字节,解码的时候,会自动去掉。

    Python内置的base64可以直接进行base64的编解码:

    >>> import base64
    >>> base64.b64encode(b'binary\x00string')
    b'YmluYXJ5AHN0cmluZw=='
    >>> base64.b64decode(b'YmluYXJ5AHN0cmluZw==')
    b'binary\x00string'
    

    由于标准的Base64编码后可能出现字符+和/,在URL中就不能直接作为参数,所以又有一种"url safe"的base64编码,其实就是把字符+和/分别变成-和_:

    >>> base64.b64encode(b'i\xb7\x1d\xfb\xef\xff')
    b'abcd++//'
    >>> base64.urlsafe_b64encode(b'i\xb7\x1d\xfb\xef\xff')
    b'abcd--__'
    >>> base64.urlsafe_b64decode('abcd--__')
    b'i\xb7\x1d\xfb\xef\xff'
    

    8.struct

    Python提供了一个struct模块来解决bytes和其他二进制数据类型的转换。
    struct的pack函数把任意数据类型变成bytes:

    >>> import struct
    >>> struct.pack('>I', 10240099)
    b'\x00\x9c@c'
    

    pack的第一个参数是处理指令,'>I'的意思是:
    >表示字节顺序是big-endian,也就是网络序,I表示4字节无符号整数。后面的参数个数要和处理指令一致。
    unpack把bytes变成相应的数据类型:

    >>> struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')
    (4042322160, 32896)
    

    根据>IH的说明,后面的bytes依次变为I:4字节无符号整数和H:2字节无符号整数。

    9.hashlib

    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。

    什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

    import hashlib
    md5 = hashlib.md5()
    md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
    print(md5.hexdigest())
    

    MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。
    另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:

    import hashlib
    sha1 = hashlib.sha1()
    sha1.update('how to use sha1 in '.encode('utf-8'))
    sha1.update('python hashlib?'.encode('utf-8'))
    print(sha1.hexdigest())
    

    SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。
    比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法不仅越慢,而且摘要长度更长。

    10.itertools

    Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数
    a.count函数

    >>> import itertools
    >>> natuals = itertools.count(1)
    >>> for n in natuals:
    ...  print(n)
    ...
       1
       2
       3
    ...
    

    b.cycle函数

    >>> import itertools
    >>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一种
    >>> for c in cs:...  print(c)
    ...
    'A'
    'B'
    'C'
    'A'
    'B'
    'C'
    ...
    

    c.repeat函数

    >> ns = itertools.repeat('A', 3)
    >>> for n in ns:
    ...  print(n)
    ...
    A
    A
    A
    

    无限序列虽然可以无限迭代下去,但是通常我们会通过takewhile()等函数根据条件判断来截取出一个有限的序列:

    >>> natuals = itertools.count(1)
    >>> ns = itertools.takewhile(lambda x: x <= 10, natuals)
    >>> list(ns)
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    itertools提供的几个迭代器操作函数更加有用:
    d.chain()函数
    chain()可以把一组迭代对象串联起来,形成一个更大的迭代器:

    >>> for c in itertools.chain('ABC', 'XYZ')
    ...  print(c)
    # 迭代效果:
    'A' 'B' 'C' 'X' 'Y' 'Z'
    

    e.groupby()函数
    groupby()把迭代器中相邻的重复元素挑出来放在一起:

    >>> for key, group in itertools.groupby('AAABBBCCAAA'):
    ...  print(key, list(group))
    ...A ['A', 'A', 'A']
    B ['B', 'B', 'B']
    C ['C', 'C']
    A ['A', 'A', 'A']
    

    实际上挑选规则是通过函数完成的,只要作用于函数的两个元素返回的值相等,这两个元素就被认为是在一组的,而函数返回值作为组的key。如果我们要忽略大小写分组,就可以让元素'A'和'a'都返回相同的key:

    >>> for key, group in itertools.groupby('AaaBBbcCAAa', lambda c: c.upper()):
    ...  print(key, list(group))
    ...
    A ['A', 'a', 'a']
    B ['B', 'B', 'b']
    C ['c', 'C']
    A ['A', 'A', 'a']
    

    11.xml

    DOM vs SAX
    操作XML有两种方法:DOM和SAX。DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点。SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件。
    正常情况下,优先考虑SAX,因为DOM实在太占内存。
    在Python中使用SAX解析XML非常简洁,通常我们关心的事件是start_element,end_element和char_data,准备好这3个函数,然后就可以解析xml了。
    举个例子,当SAX解析器读到一个节点时:
    <a href="/">python</a>
    会产生3个事件:
    1.start_element事件,在读取<a href="/">时;

    2.char_data事件,在读取python时;

    3.end_element事件,在读取</a>时。

    from xml.parsers.expat import ParserCreate
    class DefaultSaxHandler(object): 
      def start_element(self, name, attrs): 
        print('sax:start_element: %s, attrs: %s' % (name, str(attrs))) 
    
      def end_element(self, name): 
        print('sax:end_element: %s' % name) 
      
      def char_data(self, text): 
        print('sax:char_data: %s' % text)
    
    xml = r'''<?xml version="1.0"?>
    <ol> 
      <li><a href="/python">Python</a></li>
      <li><a href="/ruby">Ruby</a></li>
    </ol>'''
    
    handler = DefaultSaxHandler()
    parser = ParserCreate()
    parser.StartElementHandler = handler.start_element
    parser.EndElementHandler = handler.end_element
    parser.CharacterDataHandler = handler.char_data
    parser.Parse(xml)
    

    12.HTMLParser

    Python提供了HTMLParser来非常方便地解析HTML,只需简单几行代码:

    from html.parser import HTMLParser
    from html.entities import name2codepoint
    class MyHTMLParser(HTMLParser): 
      def handle_starttag(self, tag, attrs): 
        print('<%s>' % tag) 
      def handle_endtag(self, tag): 
        print('</%s>' % tag) 
      def handle_startendtag(self, tag, attrs): 
        print('<%s/>' % tag) 
      def handle_data(self, data): 
        print(data) 
      def handle_comment(self, data): 
        print('<!--', data, '-->') 
      def handle_entityref(self, name): 
        print('&%s;' % name) 
      def handle_charref(self, name): 
        print('&#%s;' % name)
    
    parser = MyHTMLParser()
    parser.feed('''<html>
    <head></head>
    <body>
    <!-- test html parser --> 
    <p>Some <a href=\"#\">html</a> HTML&nbsp;tutorial...<br>END</p>
    </body>
    </html>''')
    

    feed()方法可以多次调用,也就是不一定一次把整个HTML字符串都塞进去,可以一部分一部分塞进去。特殊字符有两种,一种是英文表示的 ,一种是数字表示的Ӓ,这两种字符都可以通过Parser解析出来。

    13.urllib

    urllib提供了一系列用于操作URL的功能。
    a.Get方法
    urllib的request模块可以非常方便地抓取URL内容,也就是发送一个GET请求到指定的页面,然后返回HTTP的响应:
    例如,对豆瓣的一个URLhttps://api.douban.com/v2/book/2129650
    进行抓取,并返回响应:

    from urllib import request
    with request.urlopen('https://api.douban.com/v2/book/2129650') as f: 
      data = f.read() 
      print('Status:', f.status, f.reason) 
      for k, v in f.getheaders(): 
        print('%s: %s' % (k, v)) 
      print('Data:', data.decode('utf-8'))
    

    可以看到HTTP响应的头和JSON数据:

    Status: 200 OK
    Server: nginx
    Date: Tue, 26 May 2015 10:02:27 GMT
    Content-Type: application/json; charset=utf-8
    Content-Length: 2049
    Connection: close
    Expires: Sun, 1 Jan 2006 01:00:00 GMT
    Pragma: no-cache
    Cache-Control: must-revalidate, no-cache, private
    X-DAE-Node: pidl1
    Data: {"rating":{"max":10,"numRaters":16,"average":"7.4","min":0},"subtitle":"","author":["廖雪峰编著"],"pubdate":"2007-6","tags":[{"count":20,"name":"spring","title":"spring"}...}
    

    如果我们要想模拟浏览器发送GET请求,就需要使用Request对象,通过往Request对象添加HTTP头,我们就可以把请求伪装成浏览器。例如,模拟iPhone 6去请求豆瓣首页:

    from urllib import request
    req = request.Request('http://www.douban.com/')
    req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
    with request.urlopen(req) as f:
       print('Status:', f.status, f.reason) 
       for k, v in f.getheaders(): 
        print('%s: %s' % (k, v)) 
      print('Data:', f.read().decode('utf-8'))
    

    这样豆瓣会返回适合iPhone的移动版网页:

    ... <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"> 
    <meta name="format-detection" content="telephone=no">
     <link rel="apple-touch-icon" sizes="57x57" href="http://img4.douban.com/pics/cardkit/launcher/57.png" />...
    

    b.Post方法
    如果要以POST发送一个请求,只需要把参数data以bytes形式传入。
    我们模拟一个微博登录,先读取登录的邮箱和口令,然后按照weibo.cn的登录页的格式以username=xxx&password=xxx的编码传入:

    from urllib import request, parse
    print('Login to weibo.cn...')
    email = input('Email: ')
    passwd = input('Password: ')
    login_data = parse.urlencode([ ('username', email), ('password', passwd), ('entry', 'mweibo'), ('client_id', ''), ('savestate', '1'), ('ec', ''), ('pagerefer', 'https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F')])
    req = request.Request('https://passport.weibo.cn/sso/login')
    req.add_header('Origin', 'https://passport.weibo.cn')
    req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
    req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')
    with request.urlopen(req, data=login_data.encode('utf-8')) as f: 
      print('Status:', f.status, f.reason) 
      for k, v in f.getheaders(): 
        print('%s: %s' % (k, v)) 
      print('Data:', f.read().decode('utf-8'))
    

    如果登录成功,我们获得的响应如下:

    Status: 200 OK
    Server: nginx/1.2.0
    ...
    Set-Cookie: SSOLoginState=1432620126; path=/; domain=weibo.cn
    ...
    Data: {"retcode":20000000,"msg":"","data":{...,"uid":"1658384301"}}
    

    如果登录失败,我们获得的响应如下:

    ...
    Data: {"retcode":50011015,"msg":"\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef","data":{"username":"example@python.org","errline":536}}
    

    14.PIL

    参考:
    PIL--廖雪峰的官方教程

    相关文章

      网友评论

          本文标题:python学习日记-2016.7.26

          本文链接:https://www.haomeiwen.com/subject/edjnjttx.html