我的编程空间,编程开发者的网络收藏夹
学习永远不晚

#13 让代码变得Pythonic

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

#13 让代码变得Pythonic

前言

在学习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面向对象的知识后再补充,拜拜~

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

#13 让代码变得Pythonic

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

#13 让代码变得Pythonic

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

如何让python代码更Pythonic

今天就跟大家聊聊有关如何让python代码更Pythonic,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。这篇文章,主要介绍几个简单技巧,让你在写Python代码,更Pythonic
2023-06-17

如何使得Python代码更Pythonic

本文小编为大家详细介绍“如何使得Python代码更Pythonic”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何使得Python代码更Pythonic”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1.合并嵌
2023-07-06

钉钉低代码开发让开发变得更简单

随着数字化转型的加速,企业对开发技术的需求日益增强。然而,传统的开发方式往往需要专业的技术背景和长时间的学习成本,使得很多企业无法快速满足业务需求。在这种情况下,钉钉低代码开发应运而生,它以简单的界面和强大的功能,帮助企业和个人快速实现应用开发。正文:钉钉低代码开发是一种基于“拖拉拽”方式的软件开发方式,不需要写
钉钉低代码开发让开发变得更简单
2023-12-17

AMD的模块化魔法:让JavaScript代码变得整洁

AMD的模块化魅力:让JavaScript代码更加整洁
AMD的模块化魔法:让JavaScript代码变得整洁
2024-02-18

零代码平台推荐让开发变得更加简单

在当今的数字化时代,企业对于技术的需求日益增长。然而,对于许多人来说,编程知识的缺乏成为了一道难以逾越的鸿沟。这时,零代码平台的出现为我们提供了一种新的解决方案,让非专业人士也能轻松创建和管理应用程序。本文将为您推荐几款优秀的零代码平台,并对它们进行详细说明。一、FigmaFigma是一款以设计为中心的云协作平台
零代码平台推荐让开发变得更加简单
2023-11-20

零代码的小程序平台让编程变得更简单

随着数字化时代的到来,各种技术应用不断涌现。特别是在移动互联网和物联网的大背景下,用户对于个性化服务和便捷应用的需求也日益增长。零代码的小程序平台,作为新兴的技术趋势,以其简单易用、无需编码的特性,正在逐渐改变传统编程的面貌。一、什么是零代码小程序平台零代码小程序平台是一种基于图形化界面的编程工具,用户无需具备专
零代码的小程序平台让编程变得更简单
2023-11-23

怎么使Java代码性能变得更高

本篇内容介绍了“怎么使Java代码性能变得更高”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!01 如何让代码性能更高?1.1.需要 Map
2023-06-16

html代码让照片变模糊的方法

小编给大家分享一下html代码让照片变模糊的方法,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!在html中可以使用filter属性和blur()函数来让照片变模糊,只需要给img照片添加“filter: blur(px);
2023-06-06

PyPy 是怎么让Python代码运行得和C一样快

这篇文章的内容主要围绕PyPy 是怎么让Python代码运行得和C一样快进行讲述,文章内容清晰易懂,条理清晰,非常适合新手学习,值得大家去阅读。感兴趣的朋友可以跟随小编一起阅读吧。希望大家通过这篇文章有所收获!1. 引言作为一名算法工程师,
2023-06-26

Python中怎么理解PyPy能让代码运行得更快

这篇文章主要介绍“Python中怎么理解PyPy能让代码运行得更快”,在日常操作中,相信很多人在Python中怎么理解PyPy能让代码运行得更快问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python中怎么
2023-06-16

如何使用​链式方法使 PHP 代码变得美观

链式方法是一种编程技术,允许您在单行代码中对对象调用多个方法。这可以使您的代码更易于阅读、维护和表达。要在 PHP 中使用链式方法,您只需从每个要链接的方法中返回当前对象即可。例如,以下代码显示了链式方法的一个简单示例:class User
2023-10-25

Python Lambda表达式性能优化指南:让代码跑得更快

:Python Lambda表达式是一种简短且高效的方式来创建匿名函数,它在许多情况下都能带来性能优势。本文将介绍几种优化Python Lambda表达式性能的技巧,帮助您编写更快的代码。
Python Lambda表达式性能优化指南:让代码跑得更快
2024-02-23

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录