一. 进制以及源码、反码和补码
1. 进制
计算机世界中只有二进制,所以计算机中存储和运算的所有数据都要转为二进制。包括数字、字符、图片、声音、视频等。常见的进制:
(1)二进制:0、1,满2进1。
(2)八进制:0-7,满8进1。
(3)十进制:0-9,满10进1。
(4)十六进制:0 - 9及A-F,满16进1。十六进制中,除了 0 到 9 十个数字外,还引入了字母,以便表示超过9的值。字母A、B、C、D、E、F分别对应十进制的10、11、12、13、14、15。
| 二进制 | 八进制 | 十进制 | 十六进制 |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 |
| 10 | 2 | 2 | 2 |
| 11 | 3 | 3 | 3 |
| 100 | 4 | 4 | 4 |
| 101 | 5 | 5 | 5 |
| 110 | 6 | 6 | 6 |
| 111 | 7 | 7 | 7 |
| 1000 | 10 | 8 | 8 |
| 1001 | 11 | 9 | 9 |
| 1010 | 12 | 10 | A |
| 1011 | 13 | 11 | B |
| 1100 | 14 | 12 | C |
| 1101 | 15 | 13 | D |
| 1110 | 16 | 14 | E |
| 1111 | 17 | 15 | F |
| 10000 | 20 | 16 | 10 |
| 10001 | 21 | 17 | 11 |
2. 不同进制表示整数
(1)二进制:以0b或0B开头表示。
(2)八进制:以0o开头表示
(3)十进制:正常数字表示。
(4)十六进制:以0x或0X开头表示,此处的A-F不区分大小写。
# 十进制
dec = 10
# 二进制 以0b开头
binary_number = 0b1010
# 八进制 以0o开头
octal_number = 0o12
# 十六进制 以0x开头
hex_number = 0xA
print(dec)
print(binary_number)
print(octal_number)
print(hex_number)
print("~~~~~~~~~~~~~~~~")
print("十进制数为:", dec)
print("转换为二进制为:", bin(dec))
print("转换为八进制为:", oct(dec))
print("转换为十六进制为:", hex(dec))
输出:
10
10
10
10
~~~~~~~~~~~~~~~~
十进制数为: 10
转换为二进制为: 0b1010
转换为八进制为: 0o12
转换为十六进制为: 0xa
3. 二进制转换成十进制
(1)规则:从最低位开始,将每个位上的数提取出来,乘以2的(位数-1)次方,然后求和。
(2)案例:请将二进制 1011 转成十进制的数。
4. 十进制转换成二进制
(1)规则:将该数不断除以2,直到商为0为止,然后将每步得到的余数倒过来,就是对应的二进制。
(2)案例:请将 56 转成二进制。
5. 十六进制转换成十进制
(1)规则:从最低位开始,将每个位上的数提取出来,乘以16的(位数-1)次方,然后求和。
(2)案例:请将0x34A转成十进制的数。
如果是8进制转换为10进制,就乘以8的(位数-1)次方,然后求和
6. 十进制转换成十六进制
(1)规则:将该数不断除以16,直到商为0为止,然后将每步得到的余数倒过来,就是对应的十六进制。
(2)案例:请将356转成十六进制。
如果将十进制转换为八进制,将该数不断除以8,直到商为 0 为止,然后将每步得到的余数倒过来。
7. 二进制转换成十六进制
(1)规则:低位开始,将二进制数每四位一组,转成对应的十六进制数即可。
因为2的4次方等于16 ,所以将二进制数从右向左每 4 位分成一组。如果二进制数的位数不是 4 的倍数,则在最左边补零,使其成为 4 的倍数
(2)案例:请将1001011转成十六进制。
如果二进制转换为八进制,3位分一组
8. 十六进制转换成二进制
(1)规则:将十六进制数每1位,转成对应的4位的一个二进制数即可。
(2)案例:请将0x23B转成二进制。
如果八进制转换为二进制,1位八进制转成3位二进制数
9. 原码、反码、补码
计算机底层存储数据时使用的是二进制数字,但是计算机在存储一个数字时并不是直接存储该数字对应的二进制数字,而是存储该数字对应二进制数字的补码。先了解概念
1)机器数
一个数在计算机的存储形式是二进制数,我们称这些二进制数为机器数。机器数可以是有符号的,用机器数的最高位存放符号位,0表示正数,1表示负数。
2)真值
因为机器数带有符号位,所以机器数的形式值不等于其真实表示的值(真值),以机器数10000001为例,其真正表示的值(首位为符号位)为-1,而形式值(首位就是代表1)为129;因此将带符号的机器数的真正表示的值称为机器数的真值。
3)原码
原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值。
- 正数的原码:就是它对应的二进制数。
- 负数的原码:它的绝对值对应的二进制数,且最左边位变为1。
- 0的原码:仍然是0。
十进制的正负1,用8位二进制的原码表示如下:
+1 原码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ]
4)反码
- 正数的反码:和原码相同。
- 负数的反码:在其原码的基础上,符号位不变,其余各位取反。
- 0的反码:仍然是0。
十进制的正负1,用8位二进制的反码表示如下:
+1 原码:[ 0000 0001 ] 反码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ] 反码:[ 1111 1110 ]
需要注意的是,反码通常是用来由原码求补码或者由补码求原码的过渡码。
5)补码
- 正数的补码:和原码、反码相同。
- 负数的补码:反码的基础上加1。
- 0的补码:仍然是0。
十进制的正负1,用8位二进制的补码表示如下:
+1 原码:[ 0000 0001 ] 反码:[ 0000 0001 ] 补码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ] 反码:[ 1111 1110 ] 补码:[ 1111 1111 ]
6)总结
(1)正数的原码、反码、补码都一样,三码合一。
(2)负数的反码:它的原码符号位不变,其它位取反(0 -> 1,1 -> 0);负数的补码:它的反码+1。
(3)0的反码,补码都是0。
二. 运算符
1. 算数运算符
| 运算符 | 说明 | 实例 |
|---|---|---|
| + | 加 | a + b |
| - | 减、或取负 | a - b、-a |
| * | 乘 | a * b |
| / | 除 | a / b |
| // | 整除,除后向下取整 | a // b |
| % | 模,返回除法的余数 | a % b |
| ** | 幂 | a ** b |
# -------------算术运算符---------------
a = 20
b = 10
c = a + b
print(a , "+" , b , "的结果为" , c)
c = a - b
print(a , "-" , b , "的结果为" , c)
c = a * b
print(a , "*" , b , "的结果为" , c)
c = a / b #注意:结果为浮点类型
print(a , "/" , b , "的结果为" , c)
c = a % b
print(a , "%" , b , "的结果为" , c)
a = 2
b = 3
c = a ** b
print(a , "的" , b , "次方结果为" , c)
a = 10
b = 3
c = a // b
print(a , "//" , b , "的结果为" , c)
print("-" * 30) # 输出30次-
输出结果:
20 + 10 的结果为 30
20 - 10 的结果为 10
20 * 10 的结果为 200
20 / 10 的结果为 2.0
20 % 10 的结果为 0
2 的 3 次方结果为 8
10 // 3 的结果为 3
2. 赋值运算符
| 运算符 | 说明 | 实例 |
|---|---|---|
| = | 赋值 | a = 1 |
| += | 加法赋值 | a += 2,等同于a = a + 2 |
| -= | 减法赋值 | a -= 2,等同于a = a - 2 |
| *= | 乘法赋值 | a *= 2,等同于a = a * 2 |
| /= | 除法赋值 | a /= 2,等同于a = a / 2 |
| //= | 整除赋值 | a //= 2,等同于a = a // 2 |
| %= | 模赋值 | a %= 2,等同于a = a % 2 |
| **= | 幂赋值 | a **= 2,等同于a = a ** 2 |
| := | 海象运算符,在表达式中同时进行赋值和返回赋值的值。Python3.8 版本新增 | num1 = 20 print((num2 := 3**2) > num1)print(num2) |
# -------------赋值运算符---------------
num3 = 30
num4 = 40
num5 = num3 + num4
print(num5)
num3 += 50 # num3 = num3 + 50
print(num3)
输出结果:
70
80
3. 比较运算符
| 运算符 | 说明 | 实例 |
|---|---|---|
| == | 相等,比较两者的值 | a == b |
| != | 不相等 | a != b |
| > | 大于 | a > b |
| < | 小于 | a < b |
| >= | 大于等于 | a >= b |
| <= | 小于等于 | a <= b |
# -------------比较运算符---------------
num1 = 10
num2 = 20
print(num1 == num2) # False
print(num1 != num2) # True
print(num1 > num2) # Flase
print(num1 < num2) # True
print(num1 >= num2) # False
print(num1 <= num2) # True
num3 = 'abc'
# 注意:不同的数据类型之间不能进行大小的比较
print(num1 > num3)
# 如果是字符串比较大小,是从最左边开始逐个比较字符串中相应位置的字符的ASCII码
print('5' > '6') # False
print('15' > '6') # False
4. 逻辑运算符
| 运算符 | 说明 |
|---|---|
| and | 与,x and y,若x为False返回x的值,否则返回y的值 |
| or | 或,x or y,若x为True返回x的值,否则返回y的值 |
| not | 非,not x,若x为True返回False,若x为False返回True |
# -------------逻辑运算符---------------
b1 = False
b2 = True
print(b1 and b2) # False
print(b1 or b2) # True
print(not(b1)) # True
print(5 and 8) # 8 非0表示True,0表示False
print(0 and 8) # 0
print(5 or 8) # 5
print(0 or 8) # 8
print(not(5)) # False
5. 位运算符
| 运算符 | 说明 | 实例 |
|---|---|---|
| & | 按位与 | a & b |
| | | 按位或 | a | b |
| ^ | 按位异或 | a ^ b |
| ~ | 按位取反 | ~ a |
| << | 按位左移 | a << 1 |
| >> | 按位右移 | a >> 1 |
1)原码反码补码
一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号,正数为0,负数为1。
| ** | 正数7 | 负数-7 |
|---|---|---|
| 原码 | 符号位加上真值的绝对值00000111 | 符号位加上真值的绝对值10000111 |
| 反码 | 等于原码00000111 | 原码符号位不变,其余位取反 11111000 |
| 补码 | 等于原码00000111 | 反码的基础上+1 11111001 |
位运算时,以补码形式进行计算。
2)正数的与、或、异或、非运算
测试代码:
num1 = 17
num2 = 13
print(f"正数与运算: {num1} & {num2}")
print(f"{num1:3} : {num1:08b}")
print(f"{num2:3} : {num2:08b}")
print(f"{num1 & num2:3} : {num1 & num2:08b}")
print()
print(f"正数或运算: {num1} | {num2}")
print(f"{num1:3} : {num1:08b}")
print(f"{num2:3} : {num2:08b}")
print(f"{num1 | num2:3} : {num1 | num2:08b}")
print()
print(f"正数异或运算: {num1} ^ {num2}")
print(f"{num1:3} : {num1:08b}")
print(f"{num2:3} : {num2:08b}")
print(f"{num1 ^ num2:3} : {num1 ^ num2:08b}")
print()
print(f"非运算: ~{num1}")
print(f"{num1:3}原码 : {num1:08b}")
print(f"{num1:3}取反 : {(1 << 8) - 1 ^ num1:08b},得到结果的补码")
print(f"{~num1:3}原码 : {~num1:08b},计算出结果的原码")
3)有负数的与、或运算
测试代码:
num1 = 17
num2 = 13
num3 = -12
print(f"有负数的与运算: {num3} & {num1}")
print(f"{num3:3}原码 : {num3:08b}")
print(f"{num3:3}反码 : {(1 << 8) - 1 + num3:08b}")
print(f"{num3:3}补码 : {(1 << 8) + num3:08b}")
print(f"{num1:3}补码 : {num1:08b}")
print(f"{num1 & num3:3}补码 : {num1 & num3:08b},得到结果")
print()
print(f"有负数的或运算: {num3} | {num1}")
print(f"{num3:3}原码 : {num3:08b}")
print(f"{num3:3}反码 : {(1 << 8) - 1 + num3:08b}")
print(f"{num3:3}补码 : {(1 << 8) + num3:08b}")
print(f"{num1:3}补码 : {num1:08b}")
print(f"{num1 | num3:3}补码 : {(1 << 8) + (num1 | num3):08b},得到结果的补码")
print(f"{num1 | num3}原码 : {num1 | num3:08b},计算出结果的原码")
4)按位左移、右移运算
测试代码:
num1 = 17
num2 = -12
offset = 1
print(f"左移运算: {num1} << {offset}")
print(f"{num1:3} : {num1:08b}")
print(f"{num1 << offset:3} : {num1 << offset:08b}")
print()
offset = 2
print(f"左移运算: {num2} << {offset}")
print(f"{num2:3}原码\t\t: {num2:08b}")
print(f"{num2:3}反码\t\t: {(1 << 8) - 1 + num2:08b}")
print(f"{num2:3}补码\t\t: {(1 << 8) + num2:08b}")
print(f"{num2:3}补码<<{offset}\t: {(((1 << 8) + num2) << 2) & 0xff:08b},得到结果的补码")
print(f"{num2 << offset:3}\t\t\t: {num2 << offset:08b},计算出原码")
print()
offset = 3
print(f"右移运算: {num1} >> {offset}")
print(f"{num1:3} : {num1:08b}")
print(f"{num1 >> offset:3} : {num1 >> offset:08b}")
print()
offset = 3
print(f"右移运算: {num2} >> {offset}")
print(f"{num2:3}原码\t\t: {num2:08b}")
print(f"{num2:3}反码\t\t: {(1 << 8) - 1 + num2:08b}")
print(f"{num2:3}补码\t\t: {(1 << 8) + num2:08b}")
print(f"{num2:3}补码>>{offset}\t: {(((1 << 8) + num2) >> offset) | (0xff >> 5 << 5):08b},得到结果的补码")
print(f"{num2 >> offset:3}\t\t\t: {num2 >> offset:08b},计算出原码")
6. 成员运算符
| 运算符 | 说明 | 实例 |
|---|---|---|
| in | 在指定的序列中找到值返回 True,否则返回 False | a in ['a', 'b', 'c'] |
| not in | 在指定的序列中没有找到值返回 True,否则返回 False | a not in ['a', 'b', 'c'] |
# -------------成员运算符---------------
num6 = 1
num7 = 20
test_list = [1,2,3,4,5]
print(test_list)
print(num6 in test_list) # True 判断1是不是列表中的的成员
print(num7 not in test_list) # True
7. 身份运算符
| 运算符 | 说明 | 实例 |
|---|---|---|
| is | 判断两个标识符是不是引用自相同对象 | a is b,类似id(a) == id(b)。如果引用的是同一个对象则返回True,否则返回False |
| not is | 判断两个标识符是不是引用自不同对象 | a is not b,类似id(a) != id(b)。如果引用的不是同一个对象则返回True,否则返回False |
# -------------身份运算符---------------
m = 20
n = 20
q = 30
print(m is n) # True 判断m和n在内存中是否指向同一个地址
print(n is q) # False
print(n is not q) # True
# id() 用于获取对象在内存中的地址
print(id(m) == id(n)) # True
print("-" * 30)
# -------------is和==的区别---------------
a = [1,2,3]
b = a
print(b is a) # True
print(b == a) # True
b = a[:]
print(b)
print(b is a) # False
print(b == a) # True
8. 运算符优先级
三. Python编码规范
随着你编写的程序越来越长,有必要了解一些代码格式设置约定。为确保所有人编写的代码的结构都大致一致, Python 程序员都遵循一些格式设置约定。
PEP8(Python Enhancement Proposal ,PEP)是最古老的PEP之一,它向 Python 程序员提供了代码格式设置指南。 python.org/dev/peps/pe…
下面的列出一些基本的规范:
1. 缩进
在 Python中,代码块的结束不像其他一些编程语言(如 C、Java 等)使用大括号 {} 来明确界定,而是通过缩进来表示。PEP 8建议每级缩进都使用四个空格,这既可提高可读性,又留下了足够的多级缩进空间。在文本处理文档中,大家常常使用制表符而不是空格来缩进。对于文本处理文档来说,这样做的效果很好,但混合使用制表符和空格会让 Python 解释器感到迷惑。每款文本编辑器都提供了一种设置,可将输入的制表符转换为指定数量的空格。你在编写代码时应该使用制表符键,但一定要对编辑器进行设置,使其在文档中插入空格而不是制表符。
在程序中混合使用制表符和空格可能导致极难解决的问题。如果你混合使用了制表符和空格,可将文件中所有的制表符转换为空格,大多数编辑器都提供了这样的功能。
2. 行长
很多 Python 程序员都建议每行不超过 80 字符。最初制定这样的指南时,在大多数计算机中,终端窗口每行只能容纳 79 字符;当前,计算机屏幕每行可容纳的字符数多得多,为何还要使用 79 字符的标准行长呢?这里有别的原因。专业程序员通常会在同一个屏幕上打开多个文件,使用标准行长可以让他们在屏幕上并排打开两三个文件时能同时看到各个文件的完整行。 PEP 8 还建议注释的行长都不超过 72 字符,因为有些工具为大型项目自动生成文档时,会在每行注释开头添加格式化字符。
PEP8中有关行长的指南并非不可逾越的红线,有些小组将最大行长设置为 99 字符。在学习期间,你不用过多地考虑代码的行长,但别忘了,协作编写程序时,大家几乎都遵守PEP 8 指南。在大多数编辑器中,都可设置一个视觉标志,通常是一条竖线,让你知道不能越过的界线在什么地方。
3. 空行
要将程序的不同部分分开,可使用空行。你应该使用空行来组织程序文件,但也不能滥用。例如,如果你有 5 行创建列表的代码,还有 3 行处理该列表的代码,那么用一个空行将这两部分隔开是合适的。然而,你不应使用三四个空行将它们隔开。
空行不会影响代码的运行,但会影响代码的可读性。 Python 解释器根据水平缩进情况来解读代码,但不关心垂直间距。
4. 同一行显示多条语句
Python可以在某些时候同一行中可以使用多条语句,语句之间使用分号(;)分割,但并不是所有情况都可以,所以不推荐这种写法。以下是一个简单的实例:
import sys;print(sys.path) #没有问题
'''
import sys
for i in sys.path:
print(i) #没有问题
'''
import sys;for i in sys.path:;print(i) # 报错
5. 分号
建议不要在行尾加分号,也不要使用分号将多条命令放在同一行。
6. 源文件编码
Python源码请使用 UTF-8 编码(Python2 中可以使用 ASCII 编码)。
文件采用 ASCII(Python2) 或者 UTF-8(Python 3)
7. 不以空格结束一行代码
在任何地方都不要以空格结束本行代码, 因为行末的空格不可见, 这可能会闹出问题: 比如反斜杠(连字符) 如果后面接空白字符就不再能够当连字符使用。 很多编辑器不允许以空格作为行结束符。