欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-27 13:03:57
1. 写在前面今天整理列表生成式的常用使用场景, 列表生成式是生成python列表的一种高效的方式,并且优雅简洁,可以尝试多多使用。 首先整理11种列表生成式的使用场景(有难有易吧), 然后是Python对象间的对比简单梳理(is, in, ==)。今天是python进阶的第一篇, python进阶开始就更关注python的更多细节层面, 当然依然是从使用的角度出发, 理论部分不做过多整理。2. Python列表生成式高效使用下面是11种列表生成式的使用方式:数据再运算使用列表生成式的方式实现...

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