当前位置: 移动技术网 > IT编程>脚本编程>Python > Python进阶一:Python列表生成式的高效使用和Python对象间相等性比较

Python进阶一:Python列表生成式的高效使用和Python对象间相等性比较

2020年07月20日  | 移动技术网IT编程  | 我要评论

1. 写在前面

今天整理列表生成式的常用使用场景, 列表生成式是生成python列表的一种高效的方式,并且优雅简洁,可以尝试多多使用。 首先整理11种列表生成式的使用场景(有难有易吧), 然后是Python对象间的对比简单梳理(is, in, ==)。今天是python进阶的第一篇, python进阶开始就更关注python的更多细节层面, 当然依然是从使用的角度出发, 理论部分不做过多整理。

大纲如下:

  • Python列表生成式的高效使用案例
  • Python对象相等性的比较

Ok, let’s go!

2. Python列表生成式高效使用

下面是11种列表生成式的使用方式:

  1. 数据再运算
    使用列表生成式的方式实现数据再运算, 即生成新的列表

    # 元素平方(当然不只是这一种操作)
    a = range(0, 11)
    b = [x**2 for x in a]
    b   # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    
    # 数值型元素列表转成字符串
    c = [str(i) for i in a]
    c   ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
    
  2. 一串随机数

    # 生成10个0到1的随机浮点数, 保留小数点后两位
    from random import random
    a = [round(random(), 2) for _ in range(10)]
    a
    
    # 生成10个0到10的满足均匀分布的浮点数
    from random import uniform
    b = [round(uniform(0, 10), 2) for _ in range(10)]
    b
    
  3. if和嵌套for

    # 对一个列表里面的数据筛选, 只计算[0, 11)中偶数的平方
    a = [x**2 for x in range(12) if x%2==0]
    a  #  [0, 4, 16, 36, 64, 100]
    
    # 列表生成式中嵌套for
    a = [i*j for i in range(10) for j in range(1, i+1)]
    a
    
  4. zip和列表

    a = range(5)
    b = ['a', 'b', 'c', 'd', 'e']
    c = [str(y) + str(x) for x, y in zip(a, b)]
    c  # ['a0', 'b1', 'c2', 'd3', 'e4']
    
  5. 打印键值对

    a = {'a': 1, 'b': 2, 'c': 3}
    b = [k + '=' + str(v) for k, v in a.items()]
    b  ['a=1', 'b=2', 'c=3']
    
  6. 文件列表

    import os
    a = [d for d in os.listdir('E:/Jupyter Notebook/Python全栈')]
    
  7. 保留唯一值
    这个当然有比较快的方式,就是利用set

    def filter_non_unique(lst):
        return [item for item in lst if lst.count(item)==1]
    
    filter_non_unique([1, 2, 2, 1, 3])
    
  8. 筛选分组

    def bifurcate(lst, filte):
        return [[x for i, x in enumerate(lst) if filte[i]==True],
                [x for i, x in enumerate(lst) if filte[i]==False]
               ]
    
    bifurcate(['beep', 'boop', 'foo', 'bar'], [True, True, False, True])   # [['beep', 'boop', 'bar'], ['foo']]
    
  9. 函数分组
    通过函数的方式对列表中的元素分组, 这个还是很常用的。

    def bifurcate_by(lst, fn):
        return [[x for x in lst if fn(x)], [x for x in lst if not fn(x)]]
    # 筛选出以u开头的元素
    bifurcate_by(['python3', 'up', 'users', 'people'], lambda x: x[0]=='u')  # [['up', 'users'], ['python3', 'people']]
    
  10. 两个列表的差集
    筛选出在列表1中出现的元素, 而不在列表2中出现。

    def difference(a, b):
        _a, _b = set(a), set(b)
        return [item for item in _a if item not in _b]
    
    difference([1, 1, 2, 3, 3], [1, 2, 4])
    
  11. 函数差集

    # 列表a, b中元素经过fn映射后, 返回在a不在b中的元素
    def difference_by(a, b, fn):
        _b = set(map(fn, b))
        return [item for item in a if fn(item) not in _b]
    
    from math import floor
    difference_by([2.1, 1.2], [2.3, 3.4], floor)   # 1.2
    difference_by([{'x': 2}, {'x':1}], [{'x': 1}], lambda v:v['x'])   # [{'x': 2}]
    

3. Python对象间的相等性比较

python中, 对象相等性比较相关关键字包括is, in, 比较运算符有==

  • is判断两个对象的标识号是否相等

    a = [1, 2, 3]
    id(a)  #2646376974856
    
    b = [1, 2, 3]
    id(b)  # 2646141534088
    
    a is b   # False
    a == b # True
    

    对于序列型、字典型、集合型对象,一个对象实例指向另一个对象实例,is 比较才返回真值。

    a, b = {'a': [1, 2, 3]}, {'id': 'book id', 'price': 'book price'}
    a = b
    a is b  # True
    

    对于值类型而言,不同的编译器可能会做不同的优化。从性能角度考虑,它们会缓存一些值类型的对象实例。所以,使用 is 比较时,返回的结果看起来会有些不太符合预期。注意观察下面两种情况,同样的整数值,使用 is 得到不同结果。

    a = 123
    b = 123
    a is b     # True
    
    c = 123456
    d = 123456
    c is d   # False
    

    Python 解释器,对位于区间 [-5,256] 内的小整数,会进行缓存,不在该范围内的不会缓存,所以才出现上面的现象。

    # Python中None对象是一个单例类的实例, 具有唯一的标识号
    id(None)  # 1542233392
    
  • in用于成员检测
    如果元素i是s的成员, 则i in s 为True, 否则返回False。

    # 对于字符串类型,i in s 为 True,意味着 i 是 s 的子串,也就是 s.find(i) 返回大于 - 的值
    'ab' in 'abc'  # True
    

    内置的序列类型, 字典类型和集合类型, 都支持in操作。 对于字典类型, in操作判断i是否是字典的键

    [1, 2] in [[1, 2], 'str']
    'apple' in {'orange': 1.6, 'banana': 2.3, 'apple': 5.2}  # True
    

    对于自定义类型, 判断是否位于序列类型中, 需要重写序列类型的魔方方法contains。 比如下面的例子, 自定义一个Student类, 然后再定义一个继承于list的Students类, 根据Student类的name属性, 判断某Student是否在Students列表中。

    class Student():
        def __init__(self, name):
            self._name = name
        
        @property
        def name(self):
            return self._name
        
        @name.setter
        def name(self, val):
            self._name = val
    
    class Students(list):
        def __contains__(self, stu):
            for s in self:
                if s.name == stu.name:
                    return True
            return False
    

    下面进行测试:

    s1 = Student('xiaoming')
    s2 = Student('xiaohong')
    
    a = Students()
    a.extend([s1, s2])
    
    s3 = Student('xiaohong')
    s3 in a    # True
    
  • ==用于判断值或者内容是否相等, 默认是基于两个对象的标识号比较。
    对于数值型, 字符串, 列表, 字典, 集合, 默认只要元素值相等, ==比较结果是True。

    str1 = 'alg-channel'
    str2 = 'alg-channel'
     
    str1 == str2 # True
    

    对于自定义类型, 当所有属性取值完全相同的两个实例, 判断==时, 返回false。

    但是, 大部分场景下, 我们希望两个对象是相等的, 这样不用重复添加到列表中, 比如,判断用户是否已经登入时,只要用户所有属性与登入列表中某个用户完全一致时,就认为已经登入。这时候需要重写方法eq.

    class Student():
        def __init__(self, name, age):
            self._name = name
            self._age = age
        
        @property     # 装饰器, 把方法装饰成属性
        def name(self):
            return self._name
        
        @name.setter
        def name(self, val):
            self._name = val
        
        @property
        def age(self):
            return self._age
        @age.setter
        def age(self, val):
            self._age = val
        
        def __eq__(self, val):
            print(self.__dict__)
            return self.__dict__ == val.__dict__
    

    下面尝试加入几个对象, 然后如果是相等的两个对象, 看看输出什么结果:

    a = []
    xiaoming = Student('xiaoming', 29)
    if xiaoming not in a:
        a.append(xiaoming)
    
    xiaohong = Student('xiaohong', 30)
    if xiaohong not in a:
        a.append(xiaohong)
    
    xiaoming2 = Student('xiaoming', 29)
    if xiaoming2 == xiaoming:   # 会发现这个是相等的
        print('equal')         
    

本文地址:https://blog.csdn.net/wuzhongqiang/article/details/107423473

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网