ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python的一些高级特性

2021-07-28 14:00:28  阅读:172  来源: 互联网

标签:函数 Python add 特性 高级 say print def name


Python的一些高级特性

文章目录

高级特性

列表生成式

1.写列表生成式时,把要生成的元素x **2 放到前面,后面跟for循环,这是一般的用法。

>>> b = [x**2 for x in range(0,11)]
>>> b
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

2.列表生成式也可以输出某个目录下所有文件和文件夹的名称。

>>> b = [d for d in os.listdir(r'C:\Users\Administrator\Desktop\2005期基础班')]
>>> b
['.idea', '2005-林永好-考试.py', 'day02', 'day02_homework', 'day03', 'day03_homework', 'day04', 'day04_homework', 'day05',
 'day06', 'day07', 'day08', 'day09', 'day10', 'day11', 'day12', 'day13', 'day14', 'day15', 'day16', 'day17', 'day18']

3.列表生成式可以带有两个参数

>>> a = range(5)
>>> b = ['a', 'b', 'c', 'd', 'e']
>>> c = [str(x) + str(y) for x, y in zip(a, b)]
>>> c
['0a', '1b', '2c', '3d', '4e']

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

4.除此之外,还可以跟上if,这个if的作用就是过滤,而不是一个表达式,后面不能跟else

>>> b = [x**2 for x in range(11) if x % 2 == 0]
>>> b
[0, 4, 16, 36, 64, 100]

那如果还想添加上else,那就更改一下写法。此时的for前面的if....else是一个表达式,每一个x都要根据if..else算出一个结果,然后生成表达式。

>>> [x if x % 2 == 0 else -x for x in range(1, 11)]
[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]

此外还有其他几个更高级的用法

# 根据指定函数fn对lst分组
def bifurcate_by(lst, fn):
    return [
        [x for x in lst if fn(x)],
        [x for x in lst if not fn(x)]
    ]
print(bifurcate_by(['beep', 'boop', 'foo', 'bar'], lambda x: x[0] == 'b'))
# [['beep', 'boop', 'bar'], ['foo']]
# 将值分组
def bifurcate(lst, filter):
    return [
        [x for i, x in enumerate(lst) if filter[i] == True],
        [x for i, x in enumerate(lst) if filter[i] == False]
    ]
print(bifurcate(['beep', 'boop', 'foo', 'bar'], [True, True, False, True])) 
# [['beep', 'boop', 'bar'], ['foo']]

生成器

生成器可以实现在迭代的同时生成元素,

第一种创建生成器的方法:把列表生成的[] 换成 ()

>>> gene = (x * x for x in range(10))
>>> gene
<generator object <genexpr> at 0x0000015152CE1D68>
# 那如何调用呢? 第一种调用方式:next()
>>> next(gene)
0
>>> next(gene)
1
>>> next(gene)
4

我们也可以利用for循环来不断调用这个生成器(本质也是不断next()),因为gene既是一个生成器对象,也是一个可迭代对象。

>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)

第二种创建生成器的方法:定义一个以yield关键字标识返回值的函数

def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)

yield除了可以返回相应的值,还有一个重要的功能是,每当程序执行完该语句时,程序就会暂停执行,再次执行时,从上次返回的yield语句处继续执行

>>> o = odd() # 创建一个生成器对象
>>> next(o)   # 获取第一个返回值
step 1
1             
>>> next(o)   # 此时调用next(o)时,程序就会从print('step 2')继续执行
step 2
3 
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

迭代器

迭代器:支持迭代的容器类对象。
这些可以直接作用于for循环的对象统称为可迭代对象Iterable
可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections.abc import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
# list,dict,str,生成器,带yield的生成器函数 都是可迭代对象

可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator
可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
# 生成器其实也是迭代器
# 但是 list,dict,str 不是迭代器

listdictstrIterable变成Iterator可以使用iter()函数:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

函数式编程

闭包

闭包其实也就是一个函数,只是这个函数的返回结果是内层函数的引用,内部函数可以引用外部函数的参数和局部变量。

def sum(a):
    def add(b):
        return a +b
    return add
    
num2 = sum(2)
num3 = sum(3)
print(type(num2))
print(num3(3))
>>> <class 'function'>   # 其实就是返回一个函数的引用
>>> 6

它的用处是什么呢,以上面的例子来说,我们可以根据需要再计算出总和。
虽然我们通过num2 = sum(2) 其中a=2 num3 = sum(3) 其中a=3,但是b是个未知数,我们可以根据自己的需要来算出 任何b+2 或者b+3

当我们调用sum()时,每次调用都会返回一个新的函数,即使传入相同的参数,num4()num2()的结果互不影响

num4 = sum(2)
print(num2 == num4)
>>> False
  • 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()  # f1,f2,f3 是fs的三个元素
>>> f1()
9
>>> f2()
9
>>> f3()
9
# 为什么结果都是一样的, 当你调用f1()时,此时所引用的变量i是3,因此会返回9
# 同理,f2和f3都是
# 如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,
# 无论该循环变量后续如何更改,已绑定到函数参数的值不变
def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

匿名函数

关键字lambda表示匿名函数,冒号前面的x表示函数参数。

匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

>>> f = lambda x: x * x
# def f(x):
#     return x*x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25

匿名函数也是一个函数对象,要调用匿名函数,要赋于一个变量

匿名函数也可以作为函数的返回值

装饰器

import time
def after_add(func):
    def add_thing():
        print('----装饰前------')
        func()
        print('----装饰后------')
    return add_thing

def add_1():
    print((time.strftime('%H:%M:%S',time.localtime(time.time()))))
    
add_2 = after_add(add_1)  # add_2 其实就是个函数对象
add_2()

----装饰前------
16:15:25
----装饰后------

利用我们前面所将的闭包知识,after_add其实就是形成了一个闭包,而要讲的装饰器其实就是add_2 = after_add(add_1)

那我们为什么要使用装饰器呢?如果你想要 调用add_1前后打印----装饰前----------装饰后------,而且又不希望修改add_1函数的定义呢?
因此引出装饰器的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

借助Python的@语法

import time
def after_add(func):
    print("22")
    def add_thing():
        print('----装饰前------')
        func()
        print('----装饰后------')
    return add_thing

@after_add   add_1 = after_add(add_1)
def add_1():
    print((time.strftime('%H:%M:%S',time.localtime(time.time()))))

if __name__== '__main__':
    add_1()

    
22    
----装饰前------
16:15:25
----装饰后------   

记住两个原则:
1、装饰器在函数调用之前被增强
2、相同的函数只被增强一次

@after_add放在add_1的定义处,相当于执行语句

add_1 = after_add(add_1)

原来的add_1()函数仍然存在,只是同名的add_1变量指向了新的函数,于是调用add_1()将执行新函数,也就是在add_thing()里面的func()函数。换句话说就是下面的例子。

add_2 = after_add(add_1)  # add_2 其实就是个函数对象
add_2()

带参数的函数装饰器

def say_thing(func):
    def say_say(name):   # 目标函数的参数供自己使用
        print("Hello")
        func(name)
    return say_say

@say_thing
def say_name(name):
    print(name)
    
print(say_name.__name__)    
say_name('Li Ming')

首先say_name()经过增强了, @say_thing 其实相当于执行 say_name= say_thing(say_name)

打印say_name.__name__时显示的是say_say,当我们执行say_name("Li Ming")时,相当于进入say_say(name),其中name=='Li Ming'

然后打印Helllo,接着执行func(name) 其中name=='Li Ming',
而这一句就会进入say_name(name) 其中name=='Li Ming'
说白了 say_name('Li Ming') 相当于执行语句

say_thing(say_name)('Li Ming')

首先执行say_thing(say_name),返回的是say_say函数,在调用返回的函数,参数是'Li Ming'

如果有多个装饰器,它是从内往外增强的。

偏函数

Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)

int()函数可以把字符串转换为整数(默认是按照十进制转换),同时也可以传入base参数,做N进制的转换

>>> int('12',base=8)
10    # 字符串`12`经过8进制转换,转成整数10=1*(8^1)+2*(8^0)
>>> int('10',base=8)
8

那如果要转换大量的二进制字符串,除了可以自己定义函数,还可以利用functools.partial

functools.partial就是帮助我们创建一个偏函数的,可以直接使用下面的代码创建一个新的函数int2

>>> import functools
>>> int2 = functools.partial(int, base=2)  # 把base参数重新设定为默认值2
>>> int2('1000000')
64
>>> int2('1010101')
85

它的作用就是把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

最后,创建偏函数时,实际上可以接收函数对象、*args**kw这3个参数

当传入:

int2 = functools.partial(int, base=2)
实际上固定了int函数的关键字参数base

也就是说

int2('10010')
相当于

kw = { 'base': 2 }
int('10010', **kw)

当传入:

max2 = functools.partial(max, 10)  # 实际上会把10作为*args的一部分自动加到左边
max2(5,6,7)

相当于

args = (10, 5, 6, 7)
max(*args)

参考资料:


python语法糖

廖雪峰的官方网站

[zhenguo]

标签:函数,Python,add,特性,高级,say,print,def,name
来源: https://blog.csdn.net/qq_41907769/article/details/119177596

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有