返回顶部
首页 > 资讯 > 后端开发 > Python >#13 让代码变得Pythonic
  • 171
分享到

#13 让代码变得Pythonic

代码Pythonic 2023-01-30 23:01:21 171人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

前言 在学习python的过程中,肯定听说过这么一个词:Pythonic,它的意思是让你的代码很Python! 一、列表生成式 前面有一节专门讲解了Python的列表,其灵活的使用方法一定让你陶醉其中。当然,也也知道怎么初始化一个列表,比

前言

学习python的过程中,肯定听说过这么一个词:Pythonic,它的意思是让你的代码很Python!

一、列表生成式

前面有一节专门讲解了Python的列表,其灵活的使用方法一定让你陶醉其中。当然,也也知道怎么初始化一个列表,比如现在要生成 [0,1,2,3,4] 这样一个列表:

In [1]: list(range(5))
Out[1]: [0, 1, 2, 3, 4]

现在要将此列表的每个元素平方,要怎么办呢?

方法一:

In [9]: a
Out[9]: [0, 1, 2, 3, 4]

In [10]: b = []

In [11]: for i in a:
    ...:     b.append(i**2)
    ...:

In [12]: b
Out[12]: [0, 1, 4, 9, 16]

# 使用 for 循环遍历每一个元素,之后将结果保存在新的列表里

方法二:

In [13]: a
Out[13]: [0, 1, 2, 3, 4]

In [14]: for index,i in enumerate(a):
    ...:     a[index] **=2
    ...:

In [15]: a
Out[15]: [0, 1, 4, 9, 16]

# 使用内置函数 enumerate() 将可迭代对象返回其索引和相应的值,这种方法直接改变原有列表的元素

方法三:

In [15]: a
Out[15]: [0, 1, 4, 9, 16]

In [16]: func = lambda x:x**2

In [18]: a = map(func,a)

In [19]: a
Out[19]: <map at 0x21bbb7a30b8>

In [20]: for i in a:
    ...:     print(i)
    ...:
0
1
16
81
256

# 使用内置函数 map() 也可以实现,map(函数,可迭代对象),将可迭代对象的每一个元素传入函数并返回结果

方法四:使用更加Pythonic的方法:列表生成式

In [22]: a = [i for i in range(5)]

In [23]: a
Out[23]: [0, 1, 2, 3, 4]

# 可以看到生成一个列表就是如此简单
In [24]: a = [i**2 for i in range(5)]

In [25]: a
Out[25]: [0, 1, 4, 9, 16]

# 可以看到列表生成式很方便,很好用,这该死的无处安放的魅力啊
In [26]: a = [i for i in range(10) if i%2 == 0]

In [27]: a
Out[27]: [0, 2, 4, 6, 8]

# 列表生成式还可以加入 if 判断
In [28]: [p + q for p in range(3) for q in range(5)]
Out[28]: [0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6]

# 使用两层循环实现全排列
# 0+0 0+1 0+2 0+3 0+4 0+0 1+0 1+1 1+2 1+3 1+4 2+0 2+1 2+2 2+3 2+4

二、生成器

列表生成式很实用,但是有一个致命的缺点,就是不能创建大数据量的列表,数据量太大时会导致计算机内存不够用,同时,如果创建的大数据量列表被使用的元素很少的话,那么就会造成存储空间的大量浪费,那有没有一种方法,可以不提前生成列表,而是在使用列表的时候生成一个列表,换句话说就是:边循环边计算,这就是生成器—— generator。生成器在需要的时候才产生结果,不是立即产生结果,生成器效率高,节省CPU生成器只能遍历一次,是一个特殊的迭代器。

1.生成器表达式:类似于列表生成式,只不过将方括号 [] 改变为圆括号 () 

In [29]: l = [i for i in range(8)]

In [30]: l
Out[30]: [0, 1, 2, 3, 4, 5, 6, 7]

In [31]: g = (i for i in range(8))

In [32]: g
Out[32]: <generator object <genexpr> at 0x0000021BBBB16E08>

# 可以看到 l 是列表,而 g 是一个generator

如何获得生成器的元素呢?使用next()方法可以获取一个元素:

In [33]: next(g)
Out[33]: 0

In [34]: next(g)
Out[34]: 1

In [35]: next(g)
Out[35]: 2

In [36]: next(g)
Out[36]: 3

In [37]: next(g)
Out[37]: 4

In [38]: next(g)
Out[38]: 5

In [39]: next(g)
Out[39]: 6

In [40]: next(g)
Out[40]: 7

In [41]: next(g)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-41-e734f8aca5ac> in <module>
----> 1 next(g)

StopIteration:

# 可以看到当生成器没有元素可以取的时候,会抛出StopIteration异常

可以看到上面的代码总司不停的手动使用next()获取下一个元素,很烦~,在Python中其实不经常使用next(),而是用for循环的方法迭代生成器:

In [43]: g = (i for i in range(8))

In [45]: for p in g:
    ...:     print(p)
1
2
3
4
5
6
7

创建一个生成器以后,基本上不会使用next()方法,而是使用for循环,迭代完成以后不会抛出StopIteration异常。

2.生成器函数:将函数返回时的关键字return改为yield。函数将每次返回一个结果,之后挂起,再次调用时,继续从挂起的位置执行

In [46]: def print_num():
    ...:     '''
    ...:     print num to screen
    ...:     '''
    ...:     a = 'No.1'
    ...:     b = 'No.2'
    ...:     c = 'No.3'
    ...:     print(a)
    ...:     yield a
    ...:     print(b)
    ...:     yield b
    ...:     print(c)
    ...:     yield c

运行函数可以使用 next() ,当然也不常用,for循环才是generator的真爱:

In [46]: def print_num():
    ...:     '''
    ...:     print num to screen
    ...:     '''
    ...:     a = 'No.1'
    ...:     b = 'No.2'
    ...:     c = 'No.3'
    ...:     print(a)
    ...:     yield a
    ...:     print(b)
    ...:     yield b
    ...:     print(c)
    ...:     yield c
    ...:

In [52]: a = print_num()

In [53]: next(a)
No.1
Out[53]: 'No.1'

In [54]: next(a)
No.2
Out[54]: 'No.2'

In [55]: next(a)
No.3
Out[55]: 'No.3'

In [56]: next(a)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-56-15841f3f11d4> in <module>
----> 1 next(a)

StopIteration:
# 菲波那切数列
def Fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b   # 还记得这里的交换变量方法吗?
        n = n + 1
    return '到头了!!!!'

  In [61]: f = Fib(10)

  In [62]: for p in f:
  ...: print(p)
  1
  1
  2
  3
  5
  8
  13
  21
  34
  55

 

  # for循环才是generator的真爱

三、迭代器

在Python中,list、string、tuple、dict都是可以使用for循环进行遍历的,现在又多了一类generator。这些可以使用for循环的对象称为可迭代对象。迭代器是用来帮助我们记录每次迭代的位置,而可迭代对象使用内置函数iter()是可以转换为迭代器的:

In [63]: a = [1,2,3]      # 创建一个新列表

In [64]: print(a)         # 可以看到a是列表
[1, 2, 3]  

In [65]: i = iter(a)      # 将其变为迭代器

In [67]: print(i)         # 可以看到i为迭代器
<list_iterator object at 0x0000021BBCE00240>

获取迭代器中的元素可以使用内置函数next(),但不经常使用,经常使用的是for循环:

In [68]: i
Out[68]: <list_iterator at 0x21bbce00240>

In [70]: for p in i:
    ...:     print(p)
1
2
3

补充:对于列表、字符串、元组、字典等数据类型,在使用for循环时,在后台for语句对这些对象调用iter()函数,之后使用next()逐个访问每一个元素,直到遇到StopIteration异常,迭代结束。

在Python中,可以使用 isinstance() 判断一个对象是否为可迭代对象:

In [71]: from collections import Iterable   # 导入Iterable模块,之后会讲

In [72]: isinstance([],Iterable)
Out[72]: True

In [73]: isinstance((),Iterable)
Out[73]: True

In [74]: isinstance({},Iterable)
Out[74]: True

In [75]: isinstance('',Iterable)
Out[75]: True

四、装饰器

装饰器是什么呢?来举个例子就明白了:有一个长发飘飘的漂亮女明星,被邀出演尼姑,肯定不会把头发剃光了吧,怎么办呢,聪明的你一定想到戴个头套就行。是的,在Python中,长发飘飘的女明星就是源代码,头套就是装饰器。转时期的本质就是在不改变函数原有代码并且不改变原有函数的调用方式的基础上给函数加上新的功能,听起来很迷人,用起来一样有趣,让你的代码一下子就提高档次了。

1.过程No.1

现在有一个 tell_name() 函数:

1 def tell_name():
2     print('I am MinuteSheep')

要求记录它的执行时间,对原有函数改写,这样来实现:

1 import time    # 引入time模块,这是一个时间模块,以后会讲到
2 def tell_name():
3     start_time = time.time()
4     print('I am MinuteSheep')
5     time.sleep(2)  # 为了体现执行时间,让程序等两秒
6     end_time = time.time()
7     print('执行时间为:',end_time - start_time)
8 
9 tell_name()

# 运行结果:

  I am MinuteSheep
  执行时间为: 2.001427173614502

2.过程No.2

现在又100个函数需要计算其执行时间,总不能改写100个函数的源代码吧,怎么办呢?还记的高阶函数吗,可以讲函数当作变量传给函数:

import time    # 引入time模块,这是一个时间模块,以后会讲到


def tell_name():
    print('I am MinuteSheep')
    time.sleep(2)  # 为了体现执行时间,让程序等两秒


def Time(func):  # 使用高阶函数
    start_time = time.time()
    func()
    end_time = time.time()
    print('执行时间为:', end_time - start_time)

Time(tell_name)   # 调用方式发生改变

# 运行结果:

  I am MinuteSheep
  执行时间为: 2.00026535987854

上面代码似乎实现了这个功能,也没有修改原函数的代码,但是却改变了它的调用方式,如果一个程序中有上百条调用,都要改的话还是很麻烦

3.过程No.3

import time    # 引入time模块,这是一个时间模块,以后会讲到


def tell_name():
    print('I am MinuteSheep')
    time.sleep(2)  # 为了体现执行时间,让程序等两秒


def Time(func):
    def wrapper():    # 使用函数的嵌套
        start_time = time.time()
        func()
        end_time = time.time()
        print('执行时间为:', end_time - start_time)
    return wrapper


tell_name = Time(tell_name)   # 相当于 tell_name = wrapper
tell_name()                            # 相当于执行 wrapper()

上面代码已经基本实现了这个功能,但是每次都要写两条调用语句才行,很烦

4.过程No.4

在Python中,为了克服上述问题,出现了一个叫做语法糖的语句,所以装饰器又叫做语法糖,在函数定义之前使用@语法糖可增加相应的功能

import time    # 引入time模块,这是一个时间模块,以后会讲到


def Time(func):
    def wrapper():    # 使用函数的嵌套
        start_time = time.time()
        func()
        end_time = time.time()
        print('执行时间为:', end_time - start_time)
    return wrapper


@Time   # 这就是装饰器,也叫语法糖
def tell_name():
    print('I am MinuteSheep')
    time.sleep(2)  # 为了体现执行时间,让程序等两秒


tell_name()  # 相当于执行 wrapper()

# 运行结果:

  I am MinuteSheep
  执行时间为: 2.000563621520996

上面代码实现了一个最简单的装饰器。

5.过程No.5

但是,又有新的问题出现了,如果被装饰函数有参数怎么办,这么办:

import time    # 引入time模块,这是一个时间模块,以后会讲到


def Time(func):
    def wrapper(name):    # 使用函数的嵌套
        start_time = time.time()
        func(name)
        end_time = time.time()
        print('执行时间为:', end_time - start_time)
    return wrapper


@Time
def tell_name(name):
    print('I am',name)
    time.sleep(2)  # 为了体现执行时间,让程序等两秒


tell_name('MS')  # 相当于执行 wrapper('MS')

# 运行结果:

  I am MS
  执行时间为: 2.0003795623779297

看起来不错

6.过程No.6

上面代码实现了装饰有一个参数函数的功能,但是,装饰器被应用与不同的函数,谁能知道这个函数有没有参数,有几个参数,为了实现通用性,这么办:

import time    # 引入time模块,这是一个时间模块,以后会讲到


def Time(func):
    def wrapper(*args, **kwargs):    # 通过非固定参数实现各种参数的通用装饰器
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print('执行时间为:', end_time - start_time)
    return wrapper


@Time
def tell_name(name):
    print('I am', name)
    time.sleep(2)  # 为了体现执行时间,让程序等两秒


@Time
def add(a, b):
    c = a + b
    print(c)


tell_name('MS')  
add(5, 6)

# 运行结果:

  I am MS
  执行时间为: 2.00108003616333
  11
  执行时间为: 0.0004711151123046875

7.过程No.7

上面的过程中装饰器没有参数,其实装饰器时可以带参数的:

import time    # 引入time模块,这是一个时间模块,以后会讲到


def Time(num):   # 使用两层嵌套实现带参数的装饰器
    def decorator(func):
        def wrapper(*args, **kwargs):
            if num == 1:
                start_time = time.time()
                func(*args, **kwargs)
                end_time = time.time()
                print('执行时间为:', end_time - start_time)
            elif num == 0:
                func(*args, **kwargs)
                print('不需要计算时间')
        return wrapper
    return decorator


@Time(num=1)
def tell_name(name):
    print('I am', name)
    time.sleep(2)  # 为了体现执行时间,让程序等两秒


@Time(num=0)
def add(a, b):
    c = a + b
    print(c)


tell_name('MS')
add(5, 6)

# 运行结果:

  I am MS
  执行时间为: 2.0000314712524414
  11
  不需要计算时间

8.过程No.8

一个函数可以使用多个装饰器,装饰器运行顺序从里到外:

@a
@b 
@c  
def func():
    pass

# 先运行c,再运行b,最后运行a

以上就是装饰器99%的功能,还有一种叫做类装饰器,等记录完Python面向对象的知识后再补充,拜拜~

--结束END--

本文标题: #13 让代码变得Pythonic

本文链接: https://lsjlt.com/news/181026.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • #13 让代码变得Pythonic
    前言 在学习Python的过程中,肯定听说过这么一个词:Pythonic,它的意思是让你的代码很Python! 一、列表生成式 前面有一节专门讲解了Python的列表,其灵活的使用方法一定让你陶醉其中。当然,也也知道怎么初始化一个列表,比...
    99+
    2023-01-30
    代码 Pythonic
  • 如何使得Python代码更Pythonic
    本文小编为大家详细介绍“如何使得Python代码更Pythonic”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何使得Python代码更Pythonic”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1.合并嵌...
    99+
    2023-07-06
  • 如何让python代码更Pythonic
    今天就跟大家聊聊有关如何让python代码更Pythonic,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。这篇文章,主要介绍几个简单技巧,让你在写Python代码,更Pythonic...
    99+
    2023-06-17
  • 八个重构技巧使得Python代码更Pythonic
    1.合并嵌套的if语句我们从简单的开始。不要像这样嵌套 if 语句,只需将它们合并为一个即可。if a: if b: pass # -> refactor if a and b: pas2.使用 any 而不是循环这里我们要检查列表中是否...
    99+
    2023-05-14
    Python 重构 Pythonic
  • Python代码显得Pythonic(区别于其他语言的写法)
    目录一、字符串二、运算三、赋值四、变量命名五、提升代码可读性(一)避免用分号;在一行内些多条语句(二)避免用\符号来换行(三)if-else三元表达式一、字符串 对于字符串连接,相比...
    99+
    2024-04-02
  • 三种方案 | 抛弃for循环,让Python代码更pythonic !
    为什么要挑战自己在代码里不写 for loop?因为这样可以迫使你去学习使用比较高级、比较地道的语法或 library。文中以 python 为例子,讲了不少大家其实在别人的代码里都见过、但自己很少用的语法。自从我开始探索 Python 中...
    99+
    2023-05-14
    Python Pythonic for
  • JavaScript 代理模式:让你的代码变得灵活而优雅
    ...
    99+
    2024-04-02
  • 钉钉低代码开发让开发变得更简单
    随着数字化转型的加速,企业对开发技术的需求日益增强。然而,传统的开发方式往往需要专业的技术背景和长时间的学习成本,使得很多企业无法快速满足业务需求。在这种情况下,钉钉低代码开发应运而生,它以简单的界面和强大的功能,帮助企业和个人快速实现应用...
    99+
    2023-12-17
    代码 简单 钉钉低
  • AMD的模块化魔法:让JavaScript代码变得整洁
    模块化是现代JavaScript开发中至关重要的概念,它允许将代码组织成可重用、可维护的模块。AMD(Asynchronous Module Definition)是一种模块化规范,它定义了在异步环境中加载和定义模块的方法。 AMD的优势...
    99+
    2024-02-18
    AMD JavaScript 模块化
  • 零代码平台推荐让开发变得更加简单
    在当今的数字化时代,企业对于技术的需求日益增长。然而,对于许多人来说,编程知识的缺乏成为了一道难以逾越的鸿沟。这时,零代码平台的出现为我们提供了一种新的解决方案,让非专业人士也能轻松创建和管理应用程序。本文将为您推荐几款优秀的零代码平台,并...
    99+
    2023-11-20
    变得更加 代码 简单
  • 零代码的小程序平台让编程变得更简单
    随着数字化时代的到来,各种技术应用不断涌现。特别是在移动互联网和物联网的大背景下,用户对于个性化服务和便捷应用的需求也日益增长。零代码的小程序平台,作为新兴的技术趋势,以其简单易用、无需编码的特性,正在逐渐改变传统编程的面貌。 一、什么是零...
    99+
    2023-11-23
    代码 简单 程序
  • 十个惊艳的Pythonic单行代码
    目录1.交换两个变量2.多变量赋值3. 对列表的每个第二个元素求和4.删除多个元素5. 将文件读入行数组6. 将字符串写入文件7. 列表创建8.列表映射9. 创建集合10.回文检查自...
    99+
    2022-12-08
    Pythonic单行代码 Pythonic 代码
  • Pythonic风格代码的好处有哪些
    本篇内容主要讲解“Pythonic风格代码的好处有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Pythonic风格代码的好处有哪些”吧!在Java里这样的:for index&n...
    99+
    2023-06-15
  • 让管理变得更简单(3)
    一、     管理是什么——澄清对管理的一些误解   尽管管理已经成为一个前所未有热门的流行词,但是时至今日管理仍然是一门经常被误读的学科。有些人认为管理就是一种忍受,在一个组织中运用各种方式或条文来对成员进行约束,由此来使组织顺利运行;有...
    99+
    2023-01-31
    简单
  • VSCode使React Vue代码调试变得更爽
    目录引言用 VSCode 调试 React 代码用 VSCode 调试 Vue 代码总结引言 作为前端开发,基本每天都要调试 Vue/React 代码,不知道大家都是怎么调试的,但我...
    99+
    2024-04-02
  • 怎么使Java代码性能变得更高
    本篇内容介绍了“怎么使Java代码性能变得更高”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!01 如何让代码性能更高?1.1.需要 Map ...
    99+
    2023-06-16
  • PyPy 如何让Python代码运行得和C一样快
    目录1. 引言2. 举个栗子3. 刨根问底3.1 提前编译3.2 语言可解释性3.3 即时编译4. 总结1. 引言 作为一名算法工程师,如何快速实现一个想法并验证它是否有效对日常工作...
    99+
    2024-04-02
  • html代码让照片变模糊的方法
    小编给大家分享一下html代码让照片变模糊的方法,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!在html中可以使用filter属性和blur()函数来让照片变模糊,只需要给img照片添加“filter: blur(px);...
    99+
    2023-06-06
  • Python中怎么理解PyPy能让代码运行得更快
    这篇文章主要介绍“Python中怎么理解PyPy能让代码运行得更快”,在日常操作中,相信很多人在Python中怎么理解PyPy能让代码运行得更快问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python中怎么...
    99+
    2023-06-16
  • PyPy 是怎么让Python代码运行得和C一样快
    这篇文章的内容主要围绕PyPy 是怎么让Python代码运行得和C一样快进行讲述,文章内容清晰易懂,条理清晰,非常适合新手学习,值得大家去阅读。感兴趣的朋友可以跟随小编一起阅读吧。希望大家通过这篇文章有所收获!1. 引言作为一名算...
    99+
    2023-06-26
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作