Python小白基础(3)


前言

提示:这里可以添加本文要记录的大概内容:

本文继续继Python小白基础(2)的后续章节部分,介绍了python后面的一些相关基础的知识,适合从零入门的小白看。比起之前,本文章节有些许难度提升,特别是嵌套、闭包和装饰器的相关内容。当然我可能会有些不严谨存在错误的地方望读者们谅解。


提示:以下是本篇文章正文内容,下面案例可供参考

一、作用域

1.命名空间

命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。

命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。


一般有三种命名空间:

  • 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
  • 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
  • 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)

在这里插入图片描述
命名空间查找顺序:
局部的命名空间 -> 全局命名空间 -> 内置命名空间。

命名空间的生命周期:

命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。

因此,我们无法从外部命名空间访问内部命名空间的对象。


作用域

作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。

Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。

变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python 的作用域一共有4种,分别是:

有四种作用域:

L(Local):最内层,包含局部变量,比如一个函数/方法内部。
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G(Global):当前脚本的最外层,比如当前模块的全局变量。
B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
规则顺序: L –> E –> G –> B。

在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
在这里插入图片描述

locals()
本地(本函数)定义的所以变量都会以字典的形式存在这里
globals()
在外部定义的所有变量都会以字典的形式存在在这里


c = 100
def funl():
    #声明要使用全部变量
    global c
    c += 2 # c=c+2
    print(c)
    pass



if __name__ == '__main__':
    funl()

102

列表,字典,集合不用声明全局,可以直接用的

li = [1,2,3]
dic = {"name":"tom","age":"19"}
def funl():
    #列表,字典,集合不用声明全局,可以直接用的
   li.append(99)
   print(li)
   print(dic)
   pass



if __name__ == '__main__':
    funl()

实例的结果为👇:

[1, 2, 3, 99]
{'name': 'tom', 'age': '19'}

2.嵌套

嵌套

#! /usr/bin/python
# -*- coding: UTF-8  -*-


def add_b():
    b=1
    def do_global():
        b=10
        def do_nonlocal():
            nonlocal b#b此时等于10
            b=b+20#b=30
            print(b)
        pass
    do_global()
    print(b)
    pass

if __name__ == '__main__':
    add_b()


结果如下:

1

函数的嵌套
这个不太懂略😄
在这里插入图片描述


函数名的玩法

#! /usr/bin/python
# -*- coding: UTF-8  -*-

def fun():
    print("i am a fun")
    pass

def main():
    f=fun()
    print(f)
    print(fun)

    f()
    pass


if __name__ == '__main__':
    main()

函数名里面是一个内存地址
有这个内存地址的人,加个括号就运行函数了(个人理解)

#! /usr/bin/python
# -*- coding: UTF-8  -*-

def f1():
    print("i am f1")

def f2():
    print("i am f2")

def main():
    li = [f1,f2]
    dic = {"hanshu1":f1,"hanshu2":f2}

    li[0]()
    dic["hanshu2"]()

    pass

if __name__ == '__main__':
    main()

显示内容如下👇:

i am f1
i am f2

不定长参数
在这里插入图片描述
不定长参数——能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名。基本语法如下:

def functionname([formal_args,] *var_args_tuple ):
“函数_文档字符串”
function_suite
return [expression]

加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。

#!/usr/bin/python3# -*- coding: UTF-8 -*-
可写函数说明def printinfo( arg1, *vartuple ):
"打印任何传入的参数"
print ("输出: ")
print (arg1)
print (vartuple)
调用printinfo 函数
printinfo( 70, 60, 50 )

以上实例输出结果:

输出:
70
(60, 50)

二、闭包

认识闭包
出于种种原因,我们有时候需要在函数外部得到函数内的局部变量。但是,由于Python中作用域的搜索顺序("链式作用域"结构(chain scope):子对象会一级一级地向上寻找所有父对象的变量),这一点通常是无法实现的。

所以我们需要用闭包来解决这个问题,当然闭包的学习也是比较难理解的


内函数和外函数
外函数的返回值是内函数的内存地址——个人理解这句话比较重要

#! /usr/bin/python
# -*- coding: UTF-8  -*-

#外函数
def outer(a):
    b = 10
    #内函数
    def inner():
        print(a+b)
    #外函数返回值是内函数的内存地址
    return inner

def main():
    a = outer(5)
    print(a)
    #加括号执行
    a()

if __name__ == '__main__':
    main()

结果如下:

<function outer.<locals>.inner at 0x0000024EB5BCD828>
15

判断内函数是否是闭包

#判断inner是否是闭包,如果是就返回cell…,不是则返回none,
print(inner.closure)

继续按照以上实例

#! /usr/bin/python
# -*- coding: UTF-8  -*-

#外函数
def outer(a):
    b = 10
    #内函数
    def inner():
        print(a+b)
    #判断inner是否是闭包,如果是就返回cell...,不是则返回none,
    print(inner.__closure__)
    #外函数返回值是内函数的内存地址
    return inner

def main():
    a = outer(5)
    print(a)
    #加括号执行
    a()

if __name__ == '__main__':
    main()

实例运行结果:

(<cell at 0x00000276B2F83588: int object at 0x00007FFCCCD67190>, <cell at 0x00000276B2F8C738: int object at 0x00007FFCCCD67230>)
<function outer.<locals>.inner at 0x00000276B327D828>
15

所以可以在外函数判定某一个内函数是不是闭包

一个闭包嵌着一个闭包

def wrapper():
    money = 1000
    def func():
        name = "tom"

        def inner():
            print(name,money)
        return inner

    return func

def main():
    f = wrapper()#此时f是func的内存地址
    i = f()#此时i是inner的内存地址
    i()


if __name__ == '__main__':
    main()

结果为:

tom 1000

闭包的传参

#! /usr/bin/python
# -*- coding: UTF-8  -*-


def func(a,b):
    def inner(x):
        return a*x+b

    return inner

def main():
    #此时f是inner的内存地址,并且此时inner里面的4*x+5,等待传输x
    f = func(4,5)
    print(f(2))


if __name__ == '__main__':
    main()

以上实例结果为:

13

三、装饰器

1.基本的装饰器用法

说白了就是闭包的玩法

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短

首先先回顾一下闭包相关的代码👇

import time

def fun1():
    time.sleep(3)
    print("i am fun1")

def timer(fun):
    def inner():
        #获取最初时间
        start = time.time()
        fun()
        #结束时间-开始时间
        print(time.time()-start)
    return inner


def main():
    a = timer(fun1)
    a()

if __name__ == '__main__':
    main()

实例结果为:

i am fun1
3.0139474868774414

装饰器,在运行装饰器装饰的函数的时候,会把目标函数放到装饰器函数里运行

把上面的实例里面加入装饰器

不带参数的装饰器

#! /usr/bin/python
# -*- coding: UTF-8  -*-

import time

def timer(fun):
    def inner():
        #获取最初时间
        start = time.time()
        fun()
        #结束时间-开始时间
        print(time.time()-start)
    return inner

#而装饰器,会在运行装饰器装饰的函数的时候,会把目标函数放到装饰器函数里运行
@timer
def fun1():
    time.sleep(3)
    print("i am fun1")


def main():
    fun1()

if __name__ == '__main__':
    main()


结果为↓:

i am fun1
3.0043251514434814

带参数的装饰器

#! /usr/bin/python
# -*- coding: UTF-8  -*-

import time

def timer(fun):
    def inner(a):#闭包函数需要携带参数
        #获取最初时间
        start = time.time()
        fun(a)#执行的时候也需要参数
        #结束时间-开始时间
        print(time.time()-start)
    return inner

#而装饰器,会在运行装饰器装饰的函数的时候,会把目标函数放到装饰器函数里运行
@timer
def fun1(a):
    time.sleep(a)
    print("i am fun1")
    print(a)


def main():
    fun1(5)

if __name__ == '__main__':
    main()

运行结果为:

i am fun1
5
5.014192819595337

包含多种参数的装饰器

#! /usr/bin/python
# -*- coding: UTF-8  -*-

import time

def timer(func):
    def inner(*args,**kwargs):
        func(args,kwargs)

    return inner

@timer
def fun1(*args,**kwargs):
    print(args,kwargs)
    pass



def main():
    fun1('a','b',1,2,3,name="tom",age="19")


if __name__ == '__main__':
    main()

(('a', 'b', 1, 2, 3), {'name': 'tom', 'age': '19'}) {}

补充:与装饰器无关的内容↓

打印函数中的注释内容
打印函数名
在这里插入图片描述


2.多种装饰器

装饰器传参

在这里插入图片描述
在这里插入图片描述


四、迭代器

迭代首先要想什么东西可以遍历呢

迭代是Python最强大的功能之一,是访问集合元素的一种方式。

迭代器是一个可以记住遍历的位置的对象。

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

迭代器有两个基本的方法:iter() 和 next()。

字符串,列表、元组、集合或者字典都可用于迭代器。


创建一个迭代器

把一个类作为一个迭代器使用需要在类中实现两个方法 iter() 与 next() 。

如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python 的构造函数为 init(), 它会在对象初始化的时候执行。

iter() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。

next() 方法(Python 2 里是 next())会返回下一个迭代器对象。

创建一个返回数字的迭代器,初始值为 1,逐步递增 1

例子

#! /usr/bin/python
# -*- coding: UTF-8  -*-

def main():
    li = [1,2,3,4,5,]
    li_iter = li.__iter__() #开始使用迭代器迭代
    item1 = li_iter.__next__()#迭代一个
    print(item1)
    item2 = li_iter.__next__()
    print(item2)
    item3 = li_iter.__next__()
    print(item2)



if __name__ == '__main__':
    main()

运行结果如下:

1
2
2

自动迭代

#! /usr/bin/python
# -*- coding: UTF-8  -*-

def main():
    li = [1,2,3,4,5,]
    li_iter = li.__iter__() #开始使用迭代器迭代

    while True:
        try:#捕获异常,如果try里面的东西出现异常,就直接执行excepte内的内容
            item = li_iter.__next__()
            print(item)
        except:
            print("迭代结束, break")
            break



if __name__ == '__main__':
    main()


运行为:

1
2
3
4
5
迭代结束, break

五、生成器

一个函数执行到一半的时候就想取出数据,那么就可以用到生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

调用一个生成器函数,返回的是一个迭代器对象。

#! /usr/bin/python
# -*- coding: UTF-8  -*-

def gen_fun():
    a = 1
    print("将a赋值")
    yield a #yield为中断函数,return a,等待下一个next才会继续执行
    b = 2
    print("将b赋值")
    yield b
    pass

def main():
    g1 = gen_fun()
    print(next(g1))


if __name__ == '__main__':
    main()

实例的结果如下:

将a赋值
1
#! /usr/bin/python
# -*- coding: UTF-8  -*-
import time


def gen_fun():
    a = 1
    print("将a赋值")
    yield a #yield为中断函数,return a,等待下一个next才会继续执行
    b = 2
    print("将b赋值")
    yield b
    pass

def main():
    g1 = gen_fun()
    print(next(g1))
    time.sleep(2)
    print(next(g1))


if __name__ == '__main__':
    main()


将a赋值
1
将b赋值
2

自动生成

#! /usr/bin/python
# -*- coding: UTF-8  -*-
import time

def produce():
    for i in range(100):
        yield "生产了%s个包子"%i
        pass



def main():
    p = produce()
    num = 0
    for i in p:#此时的p.__next__()就是i
        print(i)#相当于调用了yield
        num += 1
        if num==12:
            break




if __name__ == '__main__':
    main()

实例结果如下:

生产了0个包子
生产了1个包子
生产了2个包子
生产了3个包子
生产了4个包子
生产了5个包子
生产了6个包子
生产了7个包子
生产了8个包子
生产了9个包子
生产了10个包子
生产了11个包子

或者也可以方法二这样:
直接使用p.__next__()

#! /usr/bin/python
# -*- coding: UTF-8  -*-
import time

def produce():
    for i in range(100):
        yield "生产了%s个包子"%i
        pass


def main():
    p = produce()
    num = 0
    for i in range(12):
        print(p.__next__())#相当于调用了yield


if __name__ == '__main__':
    main()

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值