• Python拾遗(2)


    包括Python中的常用数据类型。

    int

    64位平台上,int类型是64位整数:

    • 从堆上按需申请名为PyIntBlcok的缓存区域存储整数对象
    • 使用固定数组缓存[-5, 257]之间的小数字,只需计算下标就能获得指针
    • PyIntBlock内存不会返还给操作系统,直至进程结束
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    a = 15
    b = 15
    a is b
    True
    a = 1000
    b = 1000
    >>> a is b
    False
    >>> a = 257
    >>> b = 257
    >>> a is b
    False

    根据第三点,如果使用range创建巨大的数字列表,这就需要很大内存空间。但是换成xrange,每次迭代之后数字对象被回收,其占用内存空间出来并被复用,内存就不会暴涨。(仅指python2)。
    当超出int限制时,会自动转换成为long

    float

    python2中,/默认返回整数,而python3中默认返回浮点数。如果需要准确控制运算精度,有效位数和round的结果,使用Decimal代替。(但是建议往Decimal传入字符串型的浮点数 – 为什么你需要少看垃圾博客以及如何在Python里精确地四舍五入

    1
    2
    3
    4
    5
    >>> from decimal import Decimal, ROUND_UP, ROUND_DOWN
    >>> float('0.1') * 3 == float('0.3')
    False
    >>> Decimal('0.1') * 3 == Decimal('0.3')
    True

    string

    不太熟的方法

    • splitlines(): 按行分割
    • find(): 查找
    • lstrip()/rstrip()/strip(): 剔除前后空格
    • replace():替换字符
    • expandtabs():将tab替换成空格
    • ljust()/rjust()/center()/zfill():填充

      字符编码

      在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,转换为UTF-8编码。
      py3

      包括bytesstr。字节的实例包含8个原生比特值,字符串实例是由Unicode字符组成

    py2

    包括strunicode。字符串代表原生的8比特,而unicodeUnicode字符组成。

    因此代码中,最核心的部分应该使用Unicode字符类型,即py3中使用strpy2中使用unicode。这两种字符类型没有相关联的二进制编码(原生的8个比特值),因此如果要将Unicode转换为二进制数据,应该使用encode方法。而反过来,如果要二进制编码转化为Unicode字符,必须使用decode方法。
    py3中的写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def (bytes_or_str):
    if isinstance(bytes_or_str, bytes):
    value = bytes_or_str.decode('utf-8')
    else:
    value = bytes_or_str
    return value

    def to_bytes(bytes_or_str):
    if isinstance(bytes_or_str, str):
    value = bytes_or_str.encode('utf-8')
    else:
    value = bytes_or_str
    return value

    py2中的写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def to_unicode(unicode_or_str):
    if isinstance(unicode_or_str, str):
    value = unicode_or_str.decode('utf-8')
    else:
    value = unicode_or_str
    return value

    def (unicode_or_str):
    if isinstance(unicode_or_str, unicode):
    value = unicode_or_str.encode('utf-8')
    else:
    value = unicode_or_str
    return value

    需要注意的是两大陷阱:

    • py2中,当一个str类型仅仅包含7个比特的ASCII码字符的时候,unicodestr实例看起来是一致的。因此可以采用:

      • +运算符合并strunicode
      • 可以使用等价或者不等价运算符来比较strunicode实例
      • 可以使用unicode来替换像%s这种字符串中的格式化占位符

        然而在py3中,bytesstr的实例是不可能等价的。

    • py3中,涉及到文件的处理操作,例如采用内置的open函数,会默认以utf8编码,而在py2中默认采用二进制的形式编码。举个例子,在py3的情况下,会报错:

      1
      2
      3
      4
      5
      def open('/tmp/random.bin','w') as f:
      f.write(os.urandom(10))

      >>>
      TypeError: must be str,not bytes

    这是因为py3中对于open函数新增了名为encoding的参数,并且此参数默认值为utf-8。因此,其对文件的源的期望是包含了unicode字符串的str实例,而不是包含了二进制的bytes文件。因此,可以采用py2py3中都通用的方法:

    1
    2
    with open('/tmp/random.bin','wb') as f:
    f.write(os.urandom(10))

    画重点

    • py3中,bytes是包含8个比特位的序列,str是包含unicode的字符串,它们不能同时出现在操作符>或者+中。
    • py2中,str是包含8个比特位的序列,而unicode是包含unicode的字符串,二者可以同时出现在只包含7个比特的ASCII码的运算中。
    • 使用工具函数来确保程序输入的数据是程序预期的类型,例如上面的to_str之类的函数。
    • 总是使用wbrb模式来处理文件。

    string.ascii_letters/digits

    使用string类的ascii_letters或者digits可以获得大小写字符,以及数字,避免自己写循环生成:

    1
    2
    3
    4
    5
    6
    7
    >>> import string
    >>> string.ascii_letters
    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    >>> type(string.ascii_letters)
    <class 'str'>
    >>> string.digits
    '0123456789'

    池化

    使用intern()可以把运行期动态生成的字符串池化:

    1
    2
    3
    4
    5
    >>> s = "".join(['a', 'b', 'c'])
    >>> s is "abc"
    False
    >>> intern(s) is "abc"
    True

    dict

    • popitem()

      随机返回并删除字典中的一对键值

    • setdefault(key, default=None)

      如果字典中包含有给定键,则返回键对应的值,否则返回为该键设置的值。

    • fromkeys(it, [initial])

      返回以可迭代对象it里的元素为键值的字典,如果有initial参数,就把它作为这些键对应的值,默认是None

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      In [104]: info = {}.fromkeys(['name', 'blog'])

      In [105]: info
      Out[105]: {'blog': None, 'name': None}

      In [106]: info = {}.fromkeys(['name', 'blog'], ['angel', 'jay'])

      In [107]: info
      Out[107]: {'blog': ['angel', 'jay'], 'name': ['angel', 'jay']}

      In [110]: info = {}.fromkeys(['name', 'blog', 'test'], 'angel')

      In [111]: info
      Out[111]: {'blog': 'angel', 'name': 'angel', 'test': 'angel'}
    • update

      使用指定键值对更新字典

    可以采用key=value的形式:

    1
    2
    3
    4
    In [112]: info.update(blog='jay')

    In [113]: info
    Out[113]: {'blog': 'jay', 'name': 'angel', 'test': 'angel'}

    也可以采用{key:value}的形式:

    1
    2
    3
    4
    In [114]: info.update({'test':'album'})

    In [115]: info
    Out[115]: {'blog': 'jay', 'name': 'angel', 'test': 'album'}

    也可以使用tuple的形式:

    1
    2
    3
    4
    In [119]: info.update((('name', 'unkown'),('test', 'secret')))

    In [120]: info
    Out[120]: {'blog': 'jay', 'name': 'unkown', 'test': 'secret'}

    对于大字典,调用keys()values()items()会同样构造巨大的列表,因此可以使用迭代器(iterkeys()itervalues()iteritems())减少内存开销。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> d = {"a":1, "b":2}
    >>> d.iterkeys()
    <dictionary-keyiterator object at 0x7fde6e70b368>
    >>> d.itervalues()
    <dictionary-valueiterator object at 0x7fde6e70b3c0>
    >>> d.iteritems()
    <dictionary-itemiterator object at 0x7fde6e70b368>
    >>> for k, v in d.iteritems():
    ... print k, v
    ...
    a 1
    b 2

    视图

    判断两个字典间的差异,除了使用Counter,也可以使用视图。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    >>> d1 = dict(a=1, b=2)
    >>> d2 = dict(b=2, c=3)
    >>> d1 & d2
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for &: 'dict' and 'dict'
    >>> v1 = d1.viewitems()
    >>> v2 = d2.viewitems()
    >>> v1 & v2
    set([('b', 2)])
    >>> v1 | v2
    set([('a', 1), ('b', 2), ('c', 3)])
    >>> v1 - v2
    set([('a', 1)])
    >>> v1 ^ v2
    set([('a', 1), ('c', 3)])

    视图会和字典同步变更:大专栏  Python拾遗(2)r/>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> d = {"a": 1}
    >>> v = d.viewitems()
    >>> v
    dict_items([('a', 1)])
    >>> d["b"] = 2
    >>> v
    dict_items([('a', 1), ('b', 2)])
    >>> del d["a"]
    >>> v
    dict_items([('b', 2)])

    collections.defaultdict

    在实例化一个defaultdict的时候,需要给构造方法提供一个可调用对象或者无参数函数,这个可调用对象会在__getitem__(例如dd是个defaultdict,当dd[k]时会调用此方法)碰到找不到的键的时候被调用,让__getitem__返回某种默认值。如果在创建defaultdict的时候没有指定可调用对象,查询不存在的键会触发KeyError(这是由于__missing__方法的缘故)。
    使用一个类型初始化,当访问键值不存在时,默认值为该类型实例。

    1
    2
    3
    4
    5
    6
    >>> dd = defaultdict(list)
    >>> dd['foo']
    []
    >>> cc = defaultdict(dict)
    >>> cc['foo']
    {}

    也可以使用不带参数的可调用函数进行初始化,当键值没有指定的时候,可以采用该函数进行初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> import collections
    >>> def default_factory():
    ... return 'default value'
    ...
    >>> d = collections.defaultdict(default_factory, foo='bar')
    >>> print('d:', d)
    d: defaultdict(<function default_factory at 0x7f2c39c04378>, {'foo': 'bar'})
    >>> print(d['foo'])
    bar
    >>> print(d['bar'])
    default value

    1
    2
    3
    4
    5
    6
    >>> def zero():
    ... return 0
    ...
    >>> ff = defaultdict(zero)
    >>> ff['foo']
    0

    简化为:

    1
    2
    3
    >>> ee = defaultdict(lambda : 0)
    >>> ee['foo']
    0

    OrderedDict

    字典是哈希表,默认迭代是无序的,如果需要元素按照添加顺序输出结果,可以使用OrderedDict

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    >>> from collections import OrderedDict
    >>> od = OrderedDict()
    >>> od["a"] = 1
    >>> od["c"] = 3
    >>> od["b"] = 2
    >>> for k, v in od.items(): print k, v
    ...
    a 1
    c 3
    b 2
    >>> od.popitem()
    ('b', 2)
    >>> od.popitem()
    ('c', 3)
    >>> od.popitem()
    ('a', 1)

    因为字典是有序的,因此当使用popitem时,不再是随机弹出

    set

    set方法的pop也是随机弹出的。集合和字典的主键都必须是可哈希类型对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> a = frozenset('abc')
    >>> a
    frozenset(['a', 'c', 'b'])
    >>> a.add('d')
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: 'frozenset' object has no attribute 'add'
    >>> b = set('abc')
    >>> b.add('d')
    >>> b
    set(['a', 'c', 'b', 'd'])

    如果需要将自定义类型放入集合中,需要保证hashequal的结果都相同才行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    class User(object):

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

    def __hash__(self):
    return hash(self.name)

    def __eq__(self, other):
    cls = type(self)
    if not other or not isinstance(other, cls):
    return False
    return self.name == other.name


    s = set()
    s.add(User('tom'))
    s.add(User('tom'))
    print s

    list

    对于频繁增删元素的大型列表,应该考虑使用链表或者迭代器创建列表对象的方法(itertools)。某些时候,可以考虑用数组(array)代替列表,但是它只能放指定的数据类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    >>> import array
    >>> a = array.array("l", range(10)) # 创建一个long类型的数组
    >>> a
    array('l', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    >>> a.tolist() #转化为list
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> a = array.array("c")
    >>> a.fromstring("abc")
    >>> a
    array('c', 'abc')
    >>> a.fromlist(list("def"))
    >>> a
    array('c', 'abcdef')
    >>> a.extend(array.array("c", "xyz"))
    >>> a
    array('c', 'abcdefxyz')

    向有序列表插入元素

    1
    2
    3
    4
    5
    >>> l = ["a", "d", "c", "e"]
    >>> l.sort()
    >>> bisect.insort(l, "b")
    >>> l
    ['a', 'b', 'c', 'd', 'e']

    Tuple

    在对tuple进行比较的时候,Python会优先比较元组中下标为0的元素,然后依次递增。有个很神奇的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> values = [1,5,3,9,7,4,2,8,6]
    >>> group = [7, 9]
    >>> def sort_priority(values, group):
    ... def helper(x):
    ... if x in group:
    ... return (0, x)
    ... return (1, x)
    ... values.sort(key=helper)
    ...
    >>> sort_priority(values, group)
    >>> print(values)
    [7, 9, 1, 2, 3, 4, 5, 6, 8]

    namedtuple

    需要两个参数,一个是类名,另一个是类的各个字段的名字。后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。

    继承自tuple的子类,创建的对象拥有可以访问的属性,但是仍然是只读的。

    1
    2
    3
    4
    5
    >>> from collections import namedtuple
    >>> TPoint = namedtuple('TPoint', ['x', 'y'])
    >>> p = TPoint(x=10, y=10)
    >>> p.x, p.y
    (10, 10)

    也可以使用TPoint = namedtuple('TPoint', 'x y')这种格式

    • 将数据变为namedtuple类:

      1
      2
      3
      4
      5
      6
      7
      >>> TPoint = namedtuple('TPoint', ['x', 'y'])
      >>> t = [11 , 22]
      >>> p = TPoint._make(t)
      >>> p
      TPoint(x=11, y=22)
      >>> p.x
      11
    • 如果要进行更新,需要调用方法_replace

      1
      2
      3
      4
      5
      6
      7
      8
      >>> p
      TPoint(x=10, y=10)
      >>> p.y = 33
      Traceback (most recent call last):
      File "<input>", line 1, in <module>
      AttributeError: can't set attribute
      >>> p._replace(y=33)
      TPoint(x=10, y=33)
    • 将字典数据转换成namedtuple

      1
      2
      3
      4
      >>> p = {'x': 44, 'y': 55}
      >>> p = TPoint(**p)
      >>> p
      TPoint(x=44, y=55)
  • 相关阅读:
    事件对象阻止默认行为
    事件对象的属性和方法
    [MySQL] 中 Schema和Database的区别
    MyBatis-session-SqlSession
    Setting the Java Class Path
    MySQL Connector/J
    Backup and Recovery Types
    The MySQL Server
    Server SQL Modes
    MySQL Server and Server-Startup Programs
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12361279.html
Copyright © 2020-2023  润新知