Python3.x 变量、变量作用域

一、变量

1、概念理解

  • 变量是会变的量。它是一个装数据的容器,里面的数据是可以变的,因此叫变量

2、变量定义

  • 在 Python 中,每个变量 在使用前都必须赋值,变量 赋值以后 该变量 才会被创建
  • 等号(=)用来给变量赋值
    • = 左边是一个变量名
    • = 右边是存储在变量中的值
变量名 =#变量定义之后,后续就可以直接使用了

3、变量的类型

在内存中创建一个变量,会包括:

  1. 变量的名称
  2. 变量保存的数据
  3. 变量存储数据的类型
  4. 变量的地址(标示)

案例 1:定义变量

# 定义 tmooc 账号变量
tmooc_account = "1234567@qq.com"     #一句话类型

# 定义 tmooc 密码变量
tmooc_password = 123456             #整数类型

# 在程序中,如果要输出变量的内容,需要使用 print 函数
print(tmooc_account)
print(tmooc_password)

练习 1:买包子

  • 可以用 其他变量的计算结果 来定义变量
  • 变量定义之后,后续就可以直接使用了

需求

  • 包子的价格是 1.5 元/个
  • 买了 10 个 包子
  • 计算付款金额
# 定义包子价格变量
price = 1.5
# 定义购买数量
number = 10
# 计算金额
money = price * number
print(money)

练习 2:买包子进阶

  • 今天老板高兴,总价打 9 折
  • 请重新计算购买金额
# 定义包子价格变量
price = 1.5
# 定义购买数量
number = 10
# 计算金额
money = price * number
# 总价打 98 折
money = money * 0.9
print(money)

提问

  • 上述代码中,一共定义有几个变量?
    • 三个:pricenumbermoney
  • money = money * 0.9 是在定义新的变量还是在使用变量?
    • 直接使用之前已经定义的变量
    • 变量名 只有在 第一次出现 才是 定义变量
    • 变量名 再次出现,不是定义变量,而是直接使用之前定义过的变量
  • 在程序开发中,可以修改之前定义变量中保存的值吗?
    • 可以
    • 变量中存储的值,就是可以

二、变量作用域

1. 全局变量

  • 标识符的作用域是定义为其声明在程序里的可应用范围,也就是变量的可见性
  • 在一个模块中最高级别的变量有全局作用域
  • 全局变量的一个特征是除非被删除掉,否则他们会存活到脚本运行结束,且对于所有的函数,他们的值都是可以被访问的

全局变量的使用

>>> x = 10			# 定义全局变量x
>>> def func1():		# 定义函数func1(),函数内部可以直接使用变量x
...     print(x)
... 
>>> func1()		#调用函数func1(),结果为10

2. 局部变量

  • 局部变量只是暂时的存在,仅仅只依赖于定义他们的函数现阶段是否处于活动
  • 当一个函数调用出现时,其局部变量就进入声明它们的作用域。在那一刻,一个新的局部变量名为那个对象创建了
  • 一旦函数完成,框架被释放,变量将会离开作用域

局部变量只在函数内部起作用

>>> def func2():		#定义函数func2(), 其中的变量a为局部变量,只在函数内部有效
...     a = 10
...     print(a)
... 
>>> def func3():		#定义函数func2(), 其中的变量a为局部变量,只在函数内部有效
...     a = 'hello'
...     print(a)
... 
>>> func2()			#调用函数func2(),结果为10
>>> func3()			#调用函数func3(), 结果为hello
>>> a		#查看a的值,没有被定义,函数内部的a为局部变量,只在该函数内部有效

如果局部变量与全局变量有相同的名称,那么函数运行时,局部变量的名称将会把全局变量的名称遮盖住

>>> x = 100		# 定义全局变量x
>>> def func5():		# 声明函数func5(), 函数内有局部变量x=200
...     x = 200
...     print(x)
... 
>>> func5()		# 局部变量
200
>>> x			# 查看x【全局变量】,没有发生变化
100

3. global 语句

  • 因为全局变量的名字能被局部变量给遮盖掉
  • 为了明确地引用一个已命名的全局变量,必须使用 global 语句
>>> x = 100		#定义全局变量x
>>> def func6():		#定义函数func6()
...     global x      #引用全局变量x
...     x = 200       #为全局变量x赋值为200
...     print(x)      #打印变量x的值
... 

>>> func6()		#调用函数func6()
>>> x

4. 查找变量或函数的顺序

  • 首先在函数的内部去查找
  • 函数内部没有,然后去全局去查找,看是否定义
  • 全局也没有,最后会去内建函数中查找
# 验证python查找变量或函数的顺序,定义函数func7(),统计字符'abcd'的长度
>>> def func7():
...     print(len('abcd'))
... 
>>> func7()		#调用函数,结果为4,正确
>>> len			#全局查看是否有len,没有,不存在
# 先在函数func7()内部查找方法len(),再在全局查找,最后在内建中查找len()

5. 生成器

Python 使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处。

Python有两种不同的方式提供生成器:

  • 生成器函数:

    • 常规函数定义,但是,使用 yield 语句而不是 return 语句返回结果
    • yield 语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
  • 生成器表达式:

    • 类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
    >>> from random import randint
    >>> nums = [randint(1, 100) for i in range(10)]		#产生10个1~99的随机数
    >>> nums
    >>> nums2 = (randint(1, 100) for i in range(10))		#() 会产生一个随机数的生成器对象
    >>> nums2		#为一个对象,不占用空间,使用时才会产生数据
    >>> for i in nums2:		#使用for循环遍历nums2中的元素,成功
    ...     print(i)
    ... 
    
    >>> ['192.168.1.%s' %i for i in range(1, 255)]		#使用列表解析产生一个254个元素的大列表,占据比较大的内存空间
    >>> ips = ('192.168.1.%s' %i for i in range(1, 255))		#() 会产生一个IP地址的生成器对象【包含254个IP地址】
    >>> ips			#为一个对象,不占用空间,使用时才会产生数据
    >>> for ip in ips:			#使用for循环可以遍历出ips中的所有元素,成功
    ...     print(ip)
    
    
    • Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
    >>> sum((x ** 2 for x in range(4))
    # 而不用多此一举的先构造一个列表:
    >>> sum([x ** 2 for x in range(4)]) 
    
    • 生成器的好处在于延迟操作,需要的时候再使用,所以会节省空间
    sum([i for i in range(100000000)])
    sum((i for i in range(100000000)))
    
  • 注意事项

    • 生成器的唯一注意事项就是:生成器只能遍历一次
    • 我们直接来看例子,假设文件中保存了每个省份的人口总数,现在,需要求每个省份的人口占全国总人口的比例。显然,我们需要先求出全国的总人口,然后在遍历每个省份的人口,用每个省的人口数除以总人口数,就得到了每个省份的人口占全国人口的比例。
    • 自定义生成器函数的过程
      • 在函数内部,有很多 yield 返回中间结果;
      • 程序向函数取值时,当函数执行到第1个yield时,会暂停函数运行并返回中间结果;
      • 当主程序再次调用函数时,函数会从上次暂停的位置继续运行,当遇到第2个yield,会再次暂停运行函数并返回数据;
      • 重复以上操作,一直到函数内部的yield全部执行完成为止

练习 :文件生成器

需求:通过生成器完成以下功能

  • 使用函数实现生成器
  • 函数接受一个文件对象作为参数
  • 生成器函数每次返回文件的 10 行数据
#定义生成器函数gen_block(),功能:每次取10行记录
def gen_block(fobj):
    lines = []           		#每次存储10行记录
    counter = 0          		#计数器,用于每次从文件中取10行记录
  
    for line in fobj:         	#从文件对象中,一行一行读取记录
        lines.append(line)    	#将读取的行记录,存储在列表lines中
        counter += 1          #统计读取了几行记录
        if counter == 10:     	#当读取10行记录时,执行代码块
            yield  lines      #暂停运行函数,给函数返回列表lines
            lines = []        	#再次读取时,继续运行函数,清空lines
            counter = 0       #再次读取时,counter复位到0,重新计数
      
    if lines:            		#当lines不为空时,返回剩余的行记录【不足10行】
        yield lines

if __name__ == '__main__':
    fname = '/etc/passwd'         	#读取数据的文件
    fobj = open(fname)            	#打开文件,默认只读数据
   
    for block in gen_block(fobj): 		#调用生成器函数,每次打印10行记录
        print(block)              	#打印每次读取的记录
        print('*' * 50)           	#打印50个*, 区分每次读取的记录
    fobj.close()                  	#打开文件,就需要关闭文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值