Skip to content

Latest commit

 

History

History
155 lines (106 loc) · 7.28 KB

File metadata and controls

155 lines (106 loc) · 7.28 KB

Python Tutorial 1 变量

索引

1.变量是什么
2.变量类型
3.拓展_数据的二进制表示

变量是什么

变量是计算机用来与一个内存地址相关联的标识符,可以通过该标识符来对内存中的数据进行操作:

var = "hello world!"
print(var)

# hello world!

安装完Python2.7后,你可以直接在控制台使用“python”命令进入解释器模式,输入以上代码,或是将代码直接存入一个后缀为“.py”的文件,假设是a.py的话,然后直接使用命令“python a.py”执行。

上面的代码通过定义一个字符串的变量var,然后通过print函数将其打印至控制台中。变量要先定义后才能使用,如果你想要定义一个整数来进行数值计算,原理也是一样的:

integer_1 = 12345
integer_2 = 54321
print(integer_1+integer_2)

# 66666
与C比较

如果你恰巧刚好学过C语言,你或许会发现一些比较明显不同,即python在定义变量的时候是不用加上变量类型的,假如在一份成百上千行的代码文件中,你看到一个名字为var的变量,而不是叫做var_str,那你就得好好看看这个变量存的到底是什么类型的数据,而在C这种强类型语言中,你只需看看该变量的定义就可以知道了:

char *var = "hello world!";
int integer_1 = 12345;
int integer_2 = 54321;

变量类型

python虽然不需要指定类型就能够定义变量,但并不是表示他就没有或是用不到变量类型,在这里我将日常使用的几种较为基本的类型列举下,整数int,浮点数(即小数)float,此外,还有一种字符串类型str(“string”的缩写)。我们可以通过内置的函数type()来验证下:

print()也是python的一个内置函数(Built-in Functions),由官方实现,可直接调用,而用户的普通函数则需要先进行定义,详见[函数](./00_Note.md)。

print(type(1))
print(type(1.0))
print(type("1.0"))
print(type("hello wolrd!"))

# <type 'int'>
# <type 'float'>
# <type 'str'>
# <type 'str'>

在大多数程序语言中,不单单python,整数相除的结果还是整数,也就是说,“5/2”的结果不是2.5而是2,要得到正确的结果需要将其中一个整数先转为浮点数才行,“5/2*1.0”这样也是不可以的,因为按计算的顺序与优先级来只会得到2.0,将5变成浮点数“1.0*5/2”或是借助括号“5/(2*1.0)”才能得到正确的结果。

同时,由于python变量不需要指定类型,所以它们可以很方便的指向其它不同类型的对象,操作更加灵活,也更加危险。

拓展_数据的二进制表示

在python中,所有的数据都是对象,每一个对象都有一个id,一个类型和一个值,例如,整数1这个对象,它的类型为int,值为1。

关于面向对象程序设计中的类与对象的概念这里暂不讨论,有兴趣的同学自行查阅资料。

id()

python保证在对象的存活期间(用不到的对象会被python的垃圾回收机制清空)该对象的id值是一个唯一的整数常量。我们可以通过内置函数id()来验证下:

print id(1)
# 140705070629576
print id(2)
# 140705070629552

id(1) == id(2)
# False, 1与2当然是两个不相等的对象咯。
id(1001) == id(1000+1)
# False, 由两个对象进行运算后生成的第三个对象与直接得到的对象不是同一个!!!
id(101) == id(100+1)
# True, 但是,python对一些小数值进行了缓存,不再对这些数值产生新的对象,而是直接引用现有的缓存!!!

# 知道整数也是对象这一回事就好了暂时;在python的官方实现中,函数id()所返回的值即对象的地址。

普通数据的类型比较

在这里我们借助struct模块来比较python的整数类型与C的几种整数类型,通过文档中的表格我们可以发现,C的所有整数类型都是可以转换成python的int类型,由于在日常使用中不需要关心python的整数类型(因为如果int的范围如果越界的话python会主动将其转为long的类型,python的int和long并不对应其它语言中的int和long类型),所以接下来主要了解C的整数类型,signed char, short, int, long分别占1,2,4,8个字节,所占空间越大,能表达的数据范围越大,因为每个字节含有8位,每位的数值有0,1两种情况,所以能表示的最大值为2^(8*字节数)/2-1(因为一半是正数一半是负数,正数部分还含有0这个值)。

# 1个字节所能表示的最大非负正整数
print 0b11111111  # 二进制
print 0xff        # 十六进制
print 255
# 255

# 导入模块
import struct
# 将该最大值存入一个字节的signed char中
print struct.pack('b', 0xff)  # error, 因为这里是signed char类型,包含负数部分,最大值只有256/2-1
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# struct.error: byte format requires -128 <= number <= 127

print struct.pack('B', 0xff) # 我们成功地将255以非负整数的形式存入一个字节,关于打印的结果,我们详见下一小结
# ?
print struct.pack('B', 48)
# 0

数值表示

回看上一小结的代码段,为何255这个值在某种形式下就能够存入一个字节,而在另一种形式下就不可以?为什么将48这个值存入一个字节中,打印该字节内容出来的是一个数值“0”?

正如注释里说的,signed char包含了负数的部分,1个字节所能表达的256个数值有一半被拿来表示负数,因此能表达的正数只能到127;而unsigned char所表示的无符号整数不含有负数,因此它能够表示0-255这个区间的所有整数,而且,它们在0-127的这个区间在内存中的二进制格式是一样的,至于0与1是怎样的组合才能表示这些数值,大家可以自行查阅原码与补码的内容。

第二个问题,打印出来的内容,其实只是一个字符,与数值0有所不同,这个字符的值便是48,有一个表专门映射了部分符号与数值之间的关系,即ascii码表,我们可以通过打印一个小写字母表来了解一下:

for i in range(26):
  print struct.pack('b', struct.unpack('b', 'a')[0] + i),  # 最后的逗号是为了避免换行;在ascii表中,26个小写字母是连续排列在一起的

# a b c d e f g h i j k l m n o p q r s t u v w x y z

同理,字符串实际上也只是一个数值序列而已,只不过计算机将其用以字符的形式解释出来:

for i in "hello world !":
  print ord(i),

# 104 101 108 108 111 32 119 111 114 108 100 32 33
# 因此我们可以看出空格就是对应32这个数值

此外,字符除了字母,符号,还有其它各种各有的语言符号,也有其对应的码表来映射,一个字节不够用就用两个,三个字节来表示一个字符(比如中文),常见的有GBK,Unicode等编码表。

end