zoukankan      html  css  js  c++  java
  • Python基础之变量进阶

    变量的引用

    • 变量和数据都是保存在内存中的;
    • 在python中函数的参数传递以及返回值都是靠引用传递的。

    函数引用的概念

    在python中

    • 变量和数据时分开存储的;
    • 数据保存在内存中的一个位置;
    • 变量保存着数据在内存中的地址;
    • 变量中记录数据的地址,就叫做引用;
    • 使用id()函数可以查看变量中保存数据所在的内存地址。

    注意:如果变量已经被定义,当给一个变量赋值的时候,本质上是自改了数据的引用;即变量不再对之前的数据引用;变量改为对新赋值的数据引用。

    a = 1
    
    id(a)
    140721952793280
    
    id(1)
    140721952793280
    
    b = a
    id(b)
    140721952793280
    
    a = 2
    id(a)
    140721952793312
    id(b)
    140721952793280
    
    b = a
    id(b)
    140721952793312
    b = 2
    id(b)
    140721952793312
    

    函数引用理解

    我们可以把变量的名字理解为便签纸,而变量名和数据就相当于把便签纸贴在数据上;
    当我们a = b时,就是把a,b两张标签纸贴在了同一个数据上,而如果我们把a重新赋值,就是把a的便签纸撕下来贴在另一个数据上,但b的便签纸位置不变;

    函数传参与引用的关系

    函数参数的传递,实际传送的是对应实参变量的引用,而不是实参保存的数据

    def test(num):
        print("在函数内部%d对应的内存地址是%s" % (num, id(num)))
    
    
    a = 10
    
    print("a 变量保存数据的内存地址是 %s" % id(a))
    
    test(a)
    
    # a 变量保存数据的内存地址是 140722085962720
    # 在函数内部10对应的内存地址是140722085962720
    

    函数返回值与引用

    函数的返回值同样也是返回变量的引用,而不是真实的数据;
    数据地址本质上就是一个数字;

    def test(num):
    
        result = "test_password"
    
        print("函数内返回值result的内存地址是 %s" % id(result))
    
        return result
    
    
    a = 10
    r = test(a)
    print("返回的 %s 的内存地址是 %s" % (r, id(r)))
    # 函数内返回值result的内存地址是 2333111002800
    # 返回的 test_password 的内存地址是 2333111002800
    

    可变类型和不可变类型

    修改可变类型 是修改数据的内容,而不会修改变量引用的地址;修改可变类型,要用对象.方法()进行修改;
    重新赋值会修改变量引用的地址;

    不可变类型,内存中的数据不允许被修改:

    • 数字类型;
    • 元组;
    • 字符串;

    可变类型,内存中的数据可以被修改:

    • 列表;
    • 字典;

    可变类型修改和重赋值对引用的影响

    可变类型比如列表,字典,对它们进行数据修改时,不会对引用的内存地址造成影响;
    只有当我们对变量进行重新赋值之后,才会影响引用;

    下面举例仅举列表的例子,字典一样,就不赘述了。

    # 列表数据修改和重赋值对引用的影响
    	a = [1,2,3]
    	id(a)
    	1956997579272
    
    	a.append(4)
    	a
    	[1, 2, 3, 4]
    	id(a)
    	1956997579272
    	a.remove(2)
    	a
    	[1, 3, 4]
    	id(a)
    	1956997579272
    	a.clear()
    	a
    	[]
    	id(a)
    	1956997579272
    
    	a = ['a','s','d']
    	id(a)
    	1956997945160
    

    字典的key只能使用不可变类型
    注意:可变类型的数据变化,是通过方法来是实现的;

    哈希算法

    d = {}
    d["name"] = "zhangsan"
    d
    {'name': 'zhangsan'}
    d[1] = "整数"
    d
    {'name': 'zhangsan', 1: '整数'}
    d[(1,)] = "元组"
    d
    {'name': 'zhangsan', 1: '整数', (1,): '元组'}
    
    d[[1,2,3]] = "列表"
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    TypeError: unhashable type: 'list'
    
    d[{"age":18}] = "字典"
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    TypeError: unhashable type: 'dict'
    
    • Python中内置一个名字叫做hash(o)的函数,它接收一个不可变类型的数据作为参数,返回结果是一个整数;
    • 哈希是一种算法,其作用是提取数据的特征码(指纹);相同的数据得到相同的结果,不同的数据得到不同的结果;
    • 在python中,设置字典的键值对时,会首先对key进行hash,以决定如何在内存中保存字典的数据,以方便后续的字典的增删改查;
    • 字典 键值对的key必须是不可变类型数据;键值对的value可以是任意类型的数据;

    哈希算法,只能哈希不可变类型;
    因为字典的key要使用哈希,所以,字典的key只能是不可变类型;

    hash(1)
    1
    
    hash("hello")
    2061306992742373012
    hash("hello python")
    9189581639312291988
    
    hash((1,2))
    3713081631934410656
    
    hash([1,2])
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    TypeError: unhashable type: 'list'
    
    hash({"age":18})
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    TypeError: unhashable type: 'dict'
    

    局部变量和全局变量

    局部变量,就是在函数内部定义的变量,仅供函数内部使用;
    全局变量,就是在函数外部定义的变量,所有函数内部都可以使用这个变量。

    在其他语言中,大多都不推荐使用全局变量,因为可变范围太大,不可控情况多;

    局部变量

    局部变量介绍

    • 局部变量是在函数内部定义的变量,只能在函数内部使用;
    • 函数执行完成后,函数内部的局部变量,会被系统回收;
    • 不同的函数,可以定义相同的名字的局部变量,彼此之间不会产生影响;

    局部变量的作用:在函数内部使用,临时保存函数内部需要使用的数据;

    局部变量只能在定义的函数内部使用,不能被函数外部或函数外部函数使用

    def demo1():
        num = 10
        print("demo1内部的局部变量num的值为%d" % num)
    
    # 因为num是num1的局部变量,而demo1外面也没有定义num变量,所以本句运行后会报错,注释掉
    # print(num)  # NameError: name 'num' is not defined
    
    
    def demo2():
        # 同样的,demo2重吗既没有num的变量,外部也没有定义全局的num变量,运行会报错,注释掉
        # print(num)  # NameError: name 'num' is not defined
        pass
    
    
    demo1()  # demo1内部的局部变量num的值为10
    demo2()
    

    局部变量的生命周期

    当局部变量被执行时创建;当函数执行完后局部变量被系统回收,生命结束;
    局部变量在生命周期内可以用来临时存储信息。
    用断点可以验证局部变量的生命周期。

    不同函数内的同名局部变量

    不同函数间可以定义相同名的局部变量,彼此之间互不关联,这就像1班有一个小明,2班也有一个小明,但他们并不是同一个人;

    def demo1():
        num = 10
        print("demo1内部的局部变量num的值为%d" % num)  # demo1内部的局部变量num的值为10
    
    
    def demo2():
        num = 100
        print("demo2的num:", num)  # demo2的num: 100
    
    
    demo1()  
    demo2()
    

    全局变量

    全局变量的使用

    在所有函数外部定义的变量,就叫做全局变量;
    可以给全局所有代码调用,包括全局变量的平行级和下级函数内部;

    num = 10
    def demo1():
        print("demo1的num", num)
    def demo2():
        print("demo2的num", num)
    
    demo1()
    demo2()
    print(num)
    
    # demo1的num 10
    # demo2的num 10
    # 10
    

    函数内部不能直接修改全局变量的值

    在函数内部,可以直接通过全局变量的引用获取对用的数据;
    但是,在python中,函数内部不能直接修改全局变量的值,如果用全局变量名在函数内部重新赋值,本质上只是创建一个同名局部变量而已

    num = 10
    
    
    def demo1():
        # 这个语句 并不是修改全局变量的值,而是创建一个同名局部变量
        num = 90
        print("demo1的num", num)
    
    
    def demo2():
        print("demo2的num", num)
    
    
    demo1()
    demo2()
    print(num)
    
    # demo1的num 90
    # demo2的num 10
    # 10
    

    变量查找顺序
    注意:函数执行时,需要处理变量时 会:

    1. 先从函数内部找指定名称的局部变量,如果有,直接使用;
    2. 函数内部没找到变量,就去函数外部找指定名称的全局变量,如果有,直接使用;
    3. 还没找到,就报错;

    用global在函数内修改全局变量

    如果希望在函数内部修改全局变量的值,使用global声明一下变量即可;
    global关键字会告诉解释器后面声明的变量是一个全局变量,这样,再使用赋值语句时,就不会创建局部变量了。

    num = 10
    
    
    def demo1():
        # 告诉解释器,这个就是全局变量,不用再创建同名局部变量了
        global num
        num = 90
        print("demo1的num", num)
    
    
    def demo2():
        print("demo2的num", num)
    
    
    demo1()
    demo2()
    print(num)
    
    # demo1的num 90
    # demo2的num 90
    # 90
    

    全局变量定义的位置

    • 在函数中要使用的变量必须在函数被调用前就被定义好,否则会报错;
    • 一般讲所有的全局变量都放在其他函数的上方,这样可以确保每个函数都能正确的使用全局变量。

    代码结构顺序:

    1. shebang
    2. import 模块
    3. 全局变量
    4. 函数定义
    5. 执行代码

    全局变量命名的建议:全局变量建议在变量名前g_变量名 或者gl_变量名

  • 相关阅读:
    HTML+JSP的登录界面数据库链接
    链式前向星模板
    【洛谷【模板】最小生成树】
    【洛谷P1090 合并果子】
    Dijkstra【迪杰斯特拉算法】
    Bellman-Ford&&SPFA
    【一本通1248:Dungeon Master&&洛谷UVA532 Dungeon Master】
    【一本通1329:【例8.2】细胞&&洛谷P1451 求细胞数量】
    Floyed-Warshall【弗洛伊德算法】
    广搜
  • 原文地址:https://www.cnblogs.com/yifchan/p/python-1-10.html
Copyright © 2011-2022 走看看