zoukankan      html  css  js  c++  java
  • 跟哥一起学python(3)- 理解“变量”

    我们把前面的程序稍微改一下,来了解python中的变量。 

    # file: ./4/4_1.py
    # 定义变量
    hello_str = "hello, world!"
    # 字符串打印
    print(hello_str)

     建议通过视频来学习本节内容: 查看本节视频


    这段代码实现的功能也是在终端打印出“hello,world!”这一字符串。与我们最开始那个程序不同的是,它定义了一个变量“hello_str”用于存储这个字符串,然后再调用print函数输出。

    本节我们来学习什么是变量? 变量,顾名思义就是可以变化的一个数据,与其对应的不能改变的数据,叫做“常量”。

    变量和常量,是所有编程语言的一个基本概念。

    Python里面没有专门定义常量的语法,通常用变量来替代,所以我们不专门介绍常量。

     抽象了看,所有的程序,无论大小,其本质都是在操作一系列的数据按照我们预设的逻辑去运算。这些数据在运算过程中,会被临时存储在内存中,我们可以认为变量就是对这些存储空间的一个命名。我们可以在代码中通过使用变量,来达到操作对应数据的目的,而不需要感知这个数据具体是怎么被计算机存储的。

     我们通过pycharm来调试该段代码,看看变量是如何存储数据的:

    我们通过id(hello_str)来获取变量hello_str的地址,这个地址是我们看来很奇怪的一串值。其实这个值是一个内存地址,它指向的是一段内存空间的起始位置。“hello,world!”这一串字符就存储在这段内存空间中。 变量的存储空间是堆(heap)和栈(stack)。堆栈是有很大区别的,在C语言里面你需要非常清晰的搞清楚它们,但是python封装得更好,不需要太去深究它们。如果感兴趣,你可以参考下图,或者百度。

     

      


    总结一下,变量是用来临时存储数据的,它本质上指向的是一段存储空间的起始地址。 Python里面,对于变量的命名有一些约束,如下:

    • 变量的第一个字符必须是字母表中字母或下划线 _ 。
    • 变量的其他的部分由字母、数字和下划线组成。
    • 标识符对大小写敏感。
    • 变量不能采用python的保留字命名。

    我们可以在windows命令行中采用下面的方法查询保留字: 

    理论上,python3可以支持采用中文字符命名变量。


     下面我们通过一个有意思的例子来进一步深入理解python的变量。

     1  # file: ./4/4_2.py
     2 
     3 score1 = 10score2 = 50
     4 
     5 # score1 score2的地址
     6 print('id(score1): %x, id(score2): %x, ' % (id(score1), id(score2)))
     7 score2 = score2 - score1
     8 
     9 # 字符串打印
    10 print('score2: ', score2)
    11 
    12 # score1 score2的地址
    13 print('id(score1): %x, id(score2): %x, ' % (id(score1), id(score2)))
    14 score3 = 40
    15 print('id(score3): %x' % (id(score3)))  

    这个例子的输出如下:

    id(score1): 7ffc5331d7c0, id(score2): 7ffc5331dcc0,

    score2:  40

    id(score1): 7ffc5331d7c0, id(score2): 7ffc5331db80,

    id(score3): 7ffc5331db80

     

    我们可以看到,在score2的值变为40之后,它指向了一个新的地址7ffc5331db80。而我们定义了一个新变量score3,给它赋值40,它居然也和score2指向了同一块地址空间。写惯了C语言的程序员对此会感到费解,但python就是这样的。

    当我们给score1赋值为10时,python会先给10创建一个对象并分配一个存储空间,然后再将score1指向这个对象。

    当score2做减法后,python也会先给40分配一个对象空间,然后将score2指向这个新的对象,所以我们看到score2的地址变了。

    当我们给score3赋值为40时,由于40对应的对象存在,所以直接将score3指向了这个对象。所以我们看到score2和score3的地址相同。

    如下图所示:

     

    那么原来那个值为50的对象怎么处理呢?如果是C语言,需要程序员主动去将其释放,否则就会内存泄露。幸运的是,python为我们提供了自动垃圾回收机制(GC),当它发现这个对象没有被引用后会自动将其释放。关于垃圾回收机制,这是一个很大的话题,我们现在没必要去深究它,有兴趣的同学可以百度。

    我们再来看一个有意思的例子:

      

     1 # file: ./4/4_3.py
     2 
     3  
     4 
     5 score1 = 10
     6 
     7 score2 = score1
     8 score1 = 20
     9 
    10 print('score1: ', score1)
    11 print('score2: ', score2)
    12 
    13  

    它的输出是:

    score1:  20

    score2:  10

    没有编程经验的同学会对此感到疑惑,不是score2=score1吗,为什么score1改变了,score2却没有改变?我们同样可以把变量的地址打印出来,就很好理解了。

     

    # file: ./4/4_3.py
    
    
    score1 = 10
    print('id(score1): %x' % (id(score1)))
    
    score2 = score1
    print('id(score2): %x' % (id(score2)))
    
    score1 = 20
    print('id(score1): %x, id(score2): %x, ' % (id(score1), id(score2)))
    
    print('score1: ', score1)
    print('score2: ', score2)
    
     

    它的输出是:

    id(score1): 7ffc5331d7c0

    id(score2): 7ffc5331d7c0

    id(score1): 7ffc5331d900, id(score2): 7ffc5331d7c0,

    score1: 20

    score2: 10

    我们可以看到,在score2 = score1后,score2的确指向了score1的地址。但是我们改变score1的值为20后,score1指向了另外一块地址空间,而score2并没有跟着改变,所以score2依然是10。

    如下图所示:

     

    我们最后再看一个例子,这个例子里面我们给变量赋了一个列表数据结构的值,关于数据结构,我们下一节会详细介绍,大家不用太关注。我们看看对于列表结构,它的变量是否也如同上面两个例子那样。

     

     1 # file: ./4/4_4.py
     2 
     3 
     4 # 列表
     5 num_list1 = [10, 20, 30, 40]
     6 num_list2 = [10, 20, 30, 40]
     7 
     8 print('id(num_list1): %x, id(num_list2): %x' % (id(num_list1), id(num_list2)))
     9 
    10 num_list1[0] = 50
    11 print('num_list1: ', num_list1)
    12 
    13 print('id(num_list1): %x, id(num_list2): %x' % (id(num_list1), id(num_list2)))

    它的输出是:

    id(num_list1): 292bd87df00, id(num_list2): 292bd9ba880

    num_list1:  [50, 20, 30, 40]

    id(num_list1): 292bd87df00, id(num_list2): 292bd9ba880

    可以看出,在初始赋值时,虽然num_list1和num_list2的值是相同的,但是它们指向的地址空间并不相同。我们修改了num_list1的值之后,num_list1也并没有重新指向一个新的地址。所以,列表数据类型和我们上面两个例子中的变量处理是不一样的。Python会给列表对应的变量分配独立的地址空间,即便值相同,也不会多个变量复用。

     

    对于不同数据类型的变量,python的处理方式是不一样的。也许你现在会觉得有点乱,没关系,下节我们学习了python的数据类型之后,你就能理解python的解释器为什么要这样区别处理了。

    另外,从这些例子我们也能理解变量给我们带来的好处了,试想如果没有变量的话,程序员几乎没法写代码,因为你想要的那个数据一会儿存在A地址,一会儿又存在了B地址。但是有了变量的话,程序员只需要对这个变量进行操作即可,不需要关心它具体指向哪儿。

    好了,下节我们学习python的数据类型。

     

  • 相关阅读:
    matplotlib 进阶之origin and extent in imshow
    Momentum and NAG
    matplotlib 进阶之Tight Layout guide
    matplotlib 进阶之Constrained Layout Guide
    matplotlib 进阶之Customizing Figure Layouts Using GridSpec and Other Functions
    matplotlb 进阶之Styling with cycler
    matplotlib 进阶之Legend guide
    Django Admin Cookbook-10如何启用对计算字段的过滤
    Django Admin Cookbook-9如何启用对计算字段的排序
    Django Admin Cookbook-8如何在Django admin中优化查询
  • 原文地址:https://www.cnblogs.com/tiger-python/p/12831588.html
Copyright © 2011-2022 走看看