Python基础-第四天

本篇内容:

1.装饰器

2.列表生成式与生成器

3.可迭代对象与迭代器

4.Python内建函数

一、装饰器

1.装饰器的介绍

装饰器本质是函数,它是为其它函数添加附加功能(装饰其它函数)。

装饰器遵循的原则有:

●不能修改被装饰函数的源代码;

●不能修改被装饰函数的调用方式;

●不能修改被装饰函数的运行结果;

2.装饰器的实现方式

①函数即变量

定义函数就相当于定义变量

>>> variable1 = "python"  # 定义一个变量variable1
>>> variable2 = variable1  # 将变量variable1的值赋给变量variable2
>>> print(variable2)  # 调用变量variable2
python

>>> def test():  # 定义一个test函数
        print("in the test")

>>> test1 = test
>>> test1()  # 调用test1函数,就相当调用test函数
in the test

上面通过def定义test函数,等同于test = 函数体

②高阶函数

●把函数名当作实参传给另外一个函数

>>> import time

>>> def bar():
        print("in the bar")
        time.sleep(1)

>>> def test1(func):
        start_time = time.time()
        func()  # run bar
        stop_time = time.time()
        print("the bar run time is %s second" % (stop_time - start_time))

>>> test1(bar)
in the bar
the bar run time is 1.0150017738342285 second

上面的例子,实现了在不修改bar函数源代码情况下,给bar函数加上了记录函数运行所耗时间的功能,但是修改了bar函数的调用方式。

●函数的返回值中包含函数名

>>> import time

>>> def bar():
        print("in the bar")
        time.sleep(1)

>>> def test2(func):
        start_time = time.time()
        func()  # run bar
        stop_time = time.time()
        print("the bar run time is %s second" % (stop_time - start_time))
        return func

>>> bar = test2(bar)
in the bar
the bar run time is 1.0002121925354004 second

>>> bar()
in the bar

上面的例子中,通过return返回bar函数的内存地址,实现了不修改bar函数的调用方式,但是好像bar()仅仅只是调用了bar函数,没有调用test2函数。

注意上面的bar = test2(bar),接下来例子中就能见证它的作用了。

③函数嵌套

>>> import time

>>> def timer(func):  # func = test1(将test1函数的内存地址传递进来)

        def decorator():
            start_time = time.time()
            result = func()  # func() = test1(),将test1函数运行结果赋给result
            stop_time = time.time()
            print("the test1 run time is %s second" % (stop_time - start_time))
            return result  # 返回test1函数运行结果

        return decorator
        
# @timer
>>> def test1():
        time.sleep(1)
        print("in the test1")
        return "from test1"

>>> test1 = timer(test1)

>>> test1()
in the test1
the test1 run time is 1.0140018463134766 second
from test1  # test1函数运行结果

上面的例子中,在没修改test1函数的源代码、test1函数的调用方式、test1函数的运行结果情况下,给test1函数加上了记录它自己运行耗时的功能。

到这步装饰器基本上就出来了,上面的例子中将test1 = timer(test1)去掉,在test1函数上面顶格写上@timer后,装饰器就真正的成了。其实@timer效果等同于test1 = timer(test1) = decorator。

上面是一个无参装饰器、被装饰函数也无参的例子,下面我们来说说装饰器加上参数的情况。

3.装饰器和被装饰函数有参数的情况

①无参装饰器,被装饰函数有参数

>>> import time

>>> def timer(func):

        def decorator(*args, **kwargs):
            start_time = time.time()
            result1 = func(*args, **kwargs)
            stop_time = time.time()
            print("the test1 run time is %s second" % (stop_time - start_time))
            return result1

        return decorator

>>> @timer
>>> def test1(name, age):
        time.sleep(1)
        print("my name is %s" % name)
        print("my age is %s" % age)
        return "from test1"

>>> print(test1("路人甲", 20))
my name is 路人甲
my age is 25
the test1 run time is 1.0000572204589844 second
from test1

被装饰的test1函数加上参数后,为什么是传给了decorator函数了?那是因为:

test1("路人甲", 20) = timer(test1)("路人甲", 20) = decorator("路人甲", 20)。

为什么这里要写*args, **kwargs了?因为这样写即能接收位置参数,也能接收关键参数,并且参数数量没有限制,程序一下变的很活了。

②有参装饰器,被装饰函数参数不固定

>>> import time

>>> def timer(timeout):

        def wrapper(func):

            def decorator(*args, **kwargs):
                start_time = time.time()
                result1 = func(*args, **kwargs)
                stop_time = time.time()
                print("the test1 run time is %s second" % (stop_time - start_time))
                print(timeout)
                return result1
            

            return decorator

        return wrapper

>>> @timer(10)
>>> def test1(name):
        time.sleep(1)
        print("my name is %s" % name)
        return "from test1"

>>> print(test1("路人甲"))
my name is 路人甲
the test1 run time is 1.012411117553711 second
10
from test1

当装饰器也带上参数后,就需要在装饰器函数中再加上一层函数嵌套。为什么还需要再加上一层了,我们来推导下:test1("路人甲") = timer(10)(test1)("路人甲") = wrapper(test1)("路人甲") = decorator("路人甲")

③总结

●函数中通过return返回的是函数名(函数的内存地址),在函数名后面加上小括号后就是调用该函数了;

●调用函数时,如果小括号中写有值,代表给被调用函数传参;

4.多个装饰器共存的情况

>>> def dec2(func):  # func = wra1
        def wra2():
            print("wra2开始")
            res2 = func()
            print("wra2结束")
            return res2
        return wra2

>>> def dec1(func):  # func = test
        def wra1():
            print("wra1开始")
            res1 = func()
            print("wra1结束")
            return res1
        return wra1

>>> @dec2
>>> @dec1
>>> def test():
        print("test开始")
        print("test结束")
        return 1

>>> print(test())
wra2开始
wra1开始
test开始
test结束
wra1结束
wra2结束
1

先不管@dec2,只看@dec1,它的意思是:test = dec1(test) = wra1

再来看加上@dec2后的情况,可以推导成:test = dec2(dec1(test)) = dec2(wra1) = wra2

有没有看明白?其实给dec2函数传的参数是wra1函数的内存地址,给dec1函数传的参数是test函数的内存地址。

总结一下就是,装饰顺序从被装饰函数开始由内向外,调用函数时的执行顺序由外向内,装饰顺序和执行顺序相反。

多个装饰器共存情况下的传参问题就不说了,看懂上面第3节内容后,细想下就明白了。

二、列表生成式与生成器

1.列表生成式

现有一个需求要生成一个列表,列表中的十个元素是0到9每个数乘以2的积,可以这么做:

list1 = []

for number in range(10):
    list1.append(number*2)

print(list1)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

但是,有没有觉得上面方法的代码太多,其实还可以这样做:

list2 = [i * 2 for i in range(10)]

print(list2)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

意思是将每次循环得到的值乘以2,计算出的积就是列表的元素,一条代码就搞定了,这就是列表生成式。

2.生成器

动过列表生成式可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

如果列表元素可以按照某种算法推算出来,那可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。

在Python中,这种一边循环一边计算的机制,称为生成器(generator)。注意,生成器只有在被调用时才会生成相应的数据。

生成器不支持通过切片方式获取值,唯一方法只能一个一个的取。

①将列表生成式变成生成器(generator)

将列表生成式最外层的[]换成()后,列表生成式就变成了生成器。

generator1 = (i * 2 for i in range(10))

print(generator1)
<generator object <genexpr> at 0x0000000000B1EF10>

print(generator1.__next__())  # 通过__next__()函数一个一个的取值
0

print(generator1.__next__())  # 每次调用只会生成当前值
2

for i in generator1:  # 推荐方法通过for循环取值
    print(i)
4
6
8
10
12
14
16
18

②使用yield把函数变成生成器(generator)

如果一个函数中包含yield关键字,那么它就不再是函数,而是一个生成器(generator)。

def fib(max):  # 斐波那契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到
    n, a, b = 0, 0, 1

    while n < max:
        yield b  # 使用yield把函数变成生成器
        a, b = b, a + b
        n += 1

    return ‘done‘

f = fib(8)

print(f)
<generator object fib at 0x000000000067EF10>

print(f.__next__())
1

print(f.__next__())
1

print("==做点别的事==")
==做点别的事==

print(f.__next__())
2

for number in f:  # 推荐方法通过for循环取值
    print(number)
3
5
8
13
21

a, b = b, a + b意思是:

a, b = 1, 2

t = (b, a + b)

a = t[0]

b = t[1]

③StopIteration错误

创建了一个生成器(generator)后,如果通过for循环来迭代它,不管循环多少次,都不会有StopIteration的错误,所以就不需要关心StopIteration的错误。

如果调用__next__()函数,当调用次数超过生成器(generator)总共可调用次数后,会有StopIteration的错误提示。

如果想要拿到生成器函数中的返回值,必须捕获StopIteration错误,因为返回值包含在StopIteration的value中。

def fib(max):  # 斐波那契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到
    n, a, b = 0, 0, 1

    while n < max:
        yield b  # 使用yield把函数变成生成器
        a, b = b, a + b
        n += 1

    return "---done---"  # return后面写的是错误信息,即返回值。返回值包含在StopIteration的value中;

f = fib(6)  # 把fib函数变成生成器

while True:
    try:  # 当调用次数小于生成器总共可调用次数,执行try部分
        x = f.__next__()  # 执行生成器,当执行到yield语句处返回b的值
        print("斐波那契数列值: ", x)

    except StopIteration as e:  # 把异常对象命名为e,可以随便命名。当调用次数超过生成器总共可调用次数后,执行except部分的代码
        print("生成器return的值: ", e.value)  # 返回值包含在StopIteration的value中
        break
斐波那契数列值:  1
斐波那契数列值:  1
斐波那契数列值:  2
斐波那契数列值:  3
斐波那契数列值:  5
斐波那契数列值:  8
生成器return的值:  ---done---

三、可迭代对象与迭代器

1.可迭代对象(Iterable)

可以直接作用于for循环的数据结构有以下几种:

●一类是集合数据类型,如list、tuple、dict、set、str、bytes等;

●一类是生成器(generator),包括生成器和带yield的生成器函数。

这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)。

判断一个对象是否是可迭代对象(Iterable):

isinstance():可以判断一个对象是否是可迭代对象(Iterable);

from collections import Iterable

print(isinstance([], Iterable))
True

print(isinstance((), Iterable))
True

print(isinstance({}, Iterable))
True

print(isinstance("abcd", Iterable))
True

print(isinstance("abcd", Iterable))
True

print(isinstance(10, Iterable))
False

2.迭代器(Iterator)

可以被__next__()函数调用并不断返回下一个值的对象称为迭代器(Iterator)。

判断一个对象是否是迭代器(Iterator)对象:

isinstance():可以判断一个对象是否是迭代器(Iterator)对象;

from collections import Iterator

print(isinstance((x for x in range(10)), Iterator))
True

print(isinstance([], Iterator))
False

print(isinstance({}, Iterator))
False

print(isinstance(10, Iterator))
False

3.把list、dict、str等,由可迭代对象(Iterable)变成迭代器(Iterator)

生成器都是迭代器(Iterator)对象,但list、dict、str虽然是可迭代对象(Iterable),却不是迭代器(Iterator)。

把list、dict、str等,由可迭代对象(Iterable)变成迭代器(Iterator)可以使用iter()函数。

from collections import Iterable, Iterator

variable1 = [1, 2, 3]

print(isinstance(variable1, Iterable))  # 判断variable1是不是可迭代对象(Iterable)
True

print(isinstance(variable1, Iterator))  # 判断variable1是不是迭代器(Iterator)
False

variable2 = iter(variable1)

print(isinstance(variable2, Iterator))  # 判断variable2是不是迭代器(Iterator)
True

print(variable2.__next__())
1

print(variable2.__next__())
2

四、Python内建函数

abs(x):返回数字的绝对值;

print(abs(-1))
1

print(abs(2))
2

print(abs(-1.2))
1.2

all(iterable):如果可迭代对象(iterable)的所有元素都为true,或者可迭代对象(iterable)为空,则返回True。

print(all([0, 1]))
False

print(all([-1, 1]))
True

print(all([1.1]))
True

print(all({}))
True

any(iterable):如果可迭代对象(iterable)有为true的元素,则返回True。如果可迭代对象(iterable)为空,则返回False。

print(any({}))
False

print(any([0, 1]))
True

print(any([0]))
False

print(any([1, 2, "abcd"]))
True

bin(x):将整数转换为二进制;

print(bin(1))
0b1

print(bin(2))
0b10

print(bin(3))
0b11

print(bin(255))
0b11111111

hex(x):将整数转换为以“0x”为前缀的小写十六进制字符串;

print(hex(10))
0xa

print(hex(15))
0xf

print(hex(255))
0xff

oct(x):将整数转换为以“0o”为前缀的小写八进制字符串;

print(oct(5))
0o5

print(oct(8))
0o10

print(oct(9))
0o11

print(oct(15))
0o17

print(oct(16))
0o20

bool([x]):返回一个布尔值,即True或False。如果x为false或省略不写,则返回False,否则返回True。空列表、空元组、空字典等都返回False,只要有元素存在都返回True。对于数字类型来说,非零的数都为真,浮点数为真,负数也为真。

print(bool(0))
False

print(bool(-1))
True

print(bool(1.1))
True

print(bool([]))
False

print(bool([0]))
True

print(bool(["abcd"]))
True

callable(object):如果对象参数可调用,则返回True,否则返回False。

def function():
    pass

print(callable(function))
True

print(callable([]))
False

exec(object):对象必须是字符串或代码对象。如果它是一个字符串,则将该字符串解析为一组Python语句,然后执行该语句(除非发生语法错误)。如果它是一个代码对象,它只是被执行。

code = """
def function(number):
    print("第%s次传递值" % number)

for i in range(1, 3, 1):
    function(i)
"""
exec(code)
第1次传递值
第2次传递值

eval(expression):将字符串str当成有效的表达式来求值并返回计算结果,参数只能是字符串。

x = "1+2+3"
print(eval(x))
6

variable1 = """{"name": "zhonglu"}"""
print(type(variable1))
<class ‘str‘>

variable1 = eval(variable1)
print(type(variable1))
<class ‘dict‘>

variable2 = """[1, 2]"""
print(type(variable2))
<class ‘str‘>

variable2 = eval(variable2)
print(type(variable2))
<class ‘list‘>

dir([object]):如果没有写具体的对象,返回当前整个文件作用域中的名称列表。使用参数时,返回该对象的有效属性列表。

enumerate(iterable, start=0):iterable必须是一个序列,一个迭代器,或者其他支持迭代的对象。__next__()方法返回的迭代器的 enumerate()返回一个元组,其中包含一个count(start,默认从零开始)和一个从迭代获得的值。

variable = ["a", "b", "c"]

for index, element in enumerate(variable):
    print(index, element)
0 a
1 b
2 c

print(list(enumerate(variable)))
[(0, ‘a‘), (1, ‘b‘), (2, ‘c‘)]

print(list(enumerate(variable, start=1)))
[(1, ‘a‘), (2, ‘b‘), (3, ‘c‘)]

globals():返回一个字典,字典中包含整个程序中所有的变量,变量名是key,变量的内容是value。

locals():返回一个字典,字典中包含所有本地(局部)的变量,变量名是key,变量的内容是value。可以判断文件中是否存在某一变量。

hash(object):返回对象的哈希值。哈希值是整数。

print(hash(1))
1

print(hash(1.0))
1

print(hash("abcd"))
-6905759380937986042

print(hash("a"))
-4127621861757105051

print(hash("好的"))
4063688330910289507

help([object]):调用内置的帮助系统。

id(object):返回对象的内存地址。

input([prompt]):该函数从输入读取一行,将其转换为字符串(剥离尾随的换行符),并返回。

int(x=0):返回一个由数字构造的整型对象。如果没有给出参数,则返回0。对于浮点数,将截断小数点后面的部分,取整。

len(s):返回一个对象的长度(项目数)。参数可以是序列(如字符串,字节,元组,列表或范围)或集合(如字典,集合或冻结集合)。

list1 = [1, 2, 3, "a", "b"]
print(len(list1))
5

max(iterable):返回一个可迭代对象中最大的项;

variable1 = [1, 2, 3, 5, 4]
print(max(variable1))
5

min(iterable):返回一个可迭代对象中最小的项;

reversed(seq):返回一个反向迭代器。

variable1 = [1, 2, 3]

variable2 = reversed(variable1)

print(variable2)
<list_reverseiterator object at 0x00000000006CA5F8>

print(variable2.__next__())
3

print(variable2.__next__())
2

print(variable2.__next__())
1

round(number[, ndigits]):四舍五入保留小数点后指定的位数。如果省略了ndigits,或者没有,它将去掉小数位,返回整数位。

print(round(1.235, 2))
1.24

print(round(12.235))
12

sorted(iterable):从可迭代对象(Iterable)中返回一个新的排序列表。

variable = {-5: "i", 2: "a", 6: "e", 4: "c", 8: "g"}

print(variable)
{8: ‘g‘, 2: ‘a‘, -5: ‘i‘, 4: ‘c‘, 6: ‘e‘}

print(variable.items())
dict_items([(8, ‘g‘), (2, ‘a‘), (-5, ‘i‘), (4, ‘c‘), (6, ‘e‘)])

print(sorted(variable.items()))  # 根据key来排序
[(-5, ‘i‘), (2, ‘a‘), (4, ‘c‘), (6, ‘e‘), (8, ‘g‘)]

print(sorted(variable.items(), key=lambda x: x[1]))  # 根据value来排序
[(2, ‘a‘), (4, ‘c‘), (6, ‘e‘), (8, ‘g‘), (-5, ‘i‘)]

sum(iterable):从左到右依次迭代,返回他们的总和。可迭代对象(Iterable)的项目通常是数字,起始值不允许为字符串。

variable = [1, 2, 3]

print(sum(variable))
6

type(object):返回对象的数据类型;

zip(*iterables):创建一个迭代器,从每个迭代器中聚合元素,返回一个元组的迭代器。当最短输入的可迭代对象(Iterable)耗尽时,迭代器就停了止。

variable1 = [1, 2, 3]
variable2 = ["a", "b", "c"]
print(zip(variable1, variable2))
<zip object at 0x0000000000D5D408>

for i in zip(variable1, variable2):
    print(i)
(1, ‘a‘)
(2, ‘b‘)
(3, ‘c‘)

variable3 = [5, 6, 7, 8, 9]
variable4 = ["e", "f", "g"]
print(zip(variable3, variable4))
<zip object at 0x0000000000D5D408>

for j in zip(variable3, variable4):
    print(j)  # 默认是以最短的为准
(5, ‘e‘)
(6, ‘f‘)
(7, ‘g‘)
时间: 2024-10-20 17:34:28

Python基础-第四天的相关文章

Python 基础语法(四)

Python 基础语法(四) --------------------------------------------接 Python 基础语法(三)-------------------------------------------- 十.Python标准库 Python标准库是随Pthon附带安装的,包含了大量极其有用的模块. 1. sys模块 sys模块包含系统对应的功能 sys.argv ---包含命令行参数,第一个参数是py的文件名 sys.platform ---返回平台类型 sy

Python基础知识(四)

Python基础知识(四) 一丶列表 定义格式: 是一个容器,由 [ ]表示,元素与元素之间用逗号隔开. 如:name=["张三","李四"] 作用: 存储任意类型的数据 (32位机器能存5亿多,64为机器存储更多) 特点: 可变 (增,删,改,查) 默认从左到右 ,从0开始 . 有序(索引,切片,步长) 操作: 增 , 删 , 改 ,查 ,索引,切片,步长 ?? #列表的两种定义方式 name=["香蕉","西瓜",&quo

Python基础入门 (四)

一.迭代器&生成器 1.迭代器仅仅是一容器对象,它实现了迭代器协议.它有两个基本方法: 1)next 方法 返回容器的下一个元素 2)_iter_方法 返回迭代器自身.迭代器可以使用内建的iter方法创建 ts = iter(['asd','sds','qweq']) #创建iter方法 print(ts.__next__()) #使用_next_方法返回下一个元素 print(ts.__next__()) print(ts.__next__()) #运行结果 asd sds qweq#需要注意

python 基础第四篇

今日大纲: 1. list(增删改查) 列表可以装大量的数据. 不限制数据类型. 表示方式:[] 方括号中的每一项用逗号隔开列表和字符串一样.也有索引和切片常用的功能: 增: append() 删:remove() 改: 索引修改 查: for循环 常用方法: len() count() sort() 排序 2. list的嵌套降维操作3. tuple 元组不可变的列表. 只读列表. 有索引和切片.不可变的是它内部子元素. 如果子元素是列表. 列表中的元素是可以变的.4. range()数数有一

Python基础第四篇—模块

一.模块 模块,是用一堆代码实现了某个功能的代码集合,模块分为三种:自定义模块(自己定义).内置模块(python自带).开源模块 导入模块 (1).导入一个py文件,解释器解释该py文件 (2).导入一个包,解释器解释该包下的 __init__.py 文件 #模块导入 import module from module.xx import xx from module.xx.xx import * from module.xx.xx import xx as rename #自己给模块定义一个

python 基础(四) 正则,递归 生成器

字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在.比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以复用. 正则表达式是一种用来匹配字符串的强有力的武器.它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的. 下面这张图展示了使用正则表达式匹配的流程 1.Python支持的正则表达式元字符和语法 语法 说明 表

python基础第四天

什么是运算符? 本章节主要说明Python的运算符.举个简单的例子 4 +5 = 9 . 例子中,4 和 5 被称为操作数,"+" 称为运算符. Python语言支持以下类型的运算符: 算术运算符 比较(关系)运算符 赋值运算符 逻辑运算符 位运算符 成员运算符 身份运算符 运算符优先级 接下来让我们一个个来学习Python的运算符. Python算术运算符 以下假设变量: a=10,b=20: 运算符 描述 实例 + 加 - 两个对象相加 a + b 输出结果 30 - 减 - 得到

Python自学之路——Python基础(四)内置函数

对上表一些比较重要常用的内置函数做一个整理 chr()与ord()     chr()是将ASCII中十进制编号转换成相应的字符,而ord()刚好相反 c = chr(49) o = ord('1') print(c) print(o) 输出结果: 1 49 知道了chr()的基本用法,可以利用它来生成一个字母验证码,因为验证码都是随机生成的,所以这里要涉及到random模块.在ASCII中,大写字母的十进制编号是从65到90. 小写字母是97到122 1 import random 2 li

python 全栈 python基础 (四)运算 copy

字符串的格式化 在字符串中插入 %s ,作为占位符,后边儿再定义插入变量. 算术运算 % 取模   判断奇偶数 / 除法   有小于号 // 取整除  返回整数部分 逻辑运算 and or not 'str'.isdigit() 是判断一个字符串能否转换成数字 布尔运算 以下几种情况为假! []空列表 {}空字典 ()空元组,空集合 ''空字符串 0 位运算 == 二进制运算 列表的copy   浅copy与深copy的关系  用在内存占位的 id 理解! 字典 中的 fromkeys() 从序