01 Python基础入门:从变量到异常处理

  • 1. 变量、运算符与数据类型
  • 运算符
  • 数据类型与转换
  • print()函数
  • 2. 位运算
  • 原码、反码和补码
  • 按位运算
  • 使用位运算进行快速计算
  • 使用位运算实现整数集合
  • 从集合中插入、删除、判断某元素是否在集合中
  • 集合之间的操作
  • Python中二进制码输出的特殊点


1. 变量、运算符与数据类型

表示注释:

  • # 作用于整行
  • ''' ''' 或者 """ """ 表示区间注释

运算符

比较运算符:

  • != 表示不等于

逻辑运算符:

  • and
  • or
  • not

位运算符

操作符

名称

示例

~

按位取反

~4

&

按位与

4 & 5

`

`

按位或

^

按位异或

4 ^ 5

<<

左移

4 << 2

>>

右移

4 >> 2

三元运算符

例子

x, y = 4, 5
small = x if x < y else y
print(small)  # 4

其他运算符

操作符

名称

示例

in

存在

'A' in ['A', 'B', 'C']

not in

不存在

'h' not in ['A', 'B', 'C']

is


"hello" is "hello"

is not

不是

"hello" is not "hello"

💡__注意__

  • is, is not 对比的是两个变量的内存地址
  • ==, != 对比的是两个变量的值
  • 比较的两个变量,指向的都是地址不可变的类型(str等),那么isis not==!= 是完全等价的。
  • 对比的两个变量,指向的是地址可变的类型(list,dict,tuple等),则两者是有区别的。

例子

【例子】比较的两个变量均指向可变类型。

a = ["hello"]
b = ["hello"]
print(a is b, a == b)  # False Tru
print(a is not b, a != b)  # True False

数据类型与转换

类型

名称

示例

int

整型 <class 'int'>

-876, 10

float

浮点型<class 'float'>

3.149, 11.11

bool

布尔型<class 'bool'>

True, False

获取类型信息:用type(object)

类型转换

  • 转换为整型 int(x, base=10)
  • 转换为字符串 str(object='')
  • 转换为浮点型 float(x)

保留浮点型小数点后n位

import decimal
from decimal import Decimal 
decimal.getcontext().prec = 4
c = Decimal(1) / Decimal(3)
print(c)

bool作用在基本类型的变量

  • 只要X不是整型0、浮点型0.0,那么bool(X)就是True,其余就是False。

bool作用在容器类型变量

  • 只要X不是空变量,bool(X)就是True,其余就是False。

print()函数

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

关键字参数:sep、end、file、flush

sep作用: 实现分隔符,比如多个参数输出时想要输出中间的分割字符。

shoplist = ['apple', 'mango', 'carrot', 'banana']
print("This is printed with 'sep='&''.")
for item in shoplist:
    print(item, 'another string', sep='&')
# 输出结果
This is printed with 'sep='&''.

apple&another string

mango&another string

carrot&another string

banana&another string

💡 此时 end参数默认是\n,即输出后换行。

end作用: 默认是换行符\n,用于输出结束时的字符。

shoplist = ['apple', 'mango', 'carrot', 'banana']
print("This is printed with 'end='&''.")
for item in shoplist:
    print(item, end='&')
print('hello world')
# 输出结果
This is printed with 'end='&''.

apple&mango&carrot&banana&hello world

2. 位运算

原码、反码和补码

二进制有三种表现形式。计算机内部使用补码来表示。

原码:有一位符号位。

反码:正数的反码就是其原码,负数的反码是符号位不变,其余位取反。

补码:正数的补码就是其原码,负数的补码是反码+1。

符号位:最高位是符号位,0表示正数,1表示负数。

按位运算

按位异或操作 ^

1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

只有两个对应位不同时才为1。

按位左移 <<

num << inum的二进制表示向左移动i位所得的值。

00 00 10 11 -> 11
11 << 3
---
01 01 10 00 -> 88

按位右移 >>

num >> inum的二进制表示向右移动i位所得的值。

00 00 10 11 -> 11
11 >> 2
---
00 00 00 10 -> 2

使用位运算进行快速计算

通过 <<>> 快速计算2的倍数问题。

n << 1 -> 计算 n*2
n >> 1 -> 计算 n/2,负奇数的运算不可用
n << m -> 计算 n*(2^m),即乘以 2 的 m 次方
n >> m -> 计算 n/(2^m),即除以 2 的 m 次方
1 << n -> 2^n

通过 ^ 快速交换两个整数。 通过 ^ 快速交换两个整数。

a ^= b
b ^= a
a ^= b

通过 a & (-a) 快速获取a的最后为 1 位置的整数。

#例子1
00 00 01 01 -> 5
&
11 11 10 11 -> -5
---
00 00 00 01 -> 1

#例子2
00 00 11 10 -> 14
&
11 11 00 10 -> -14
---
00 00 00 10 -> 2

使用位运算实现整数集合

一个数的二进制表示可以看作是一个集合(0表示不在此集合中,1表示在此集合中)。以集合 {1,3,4,8}为例,可以表示成 01 00 01 10 10

整数

9

8

7

6

5

4

3

2

1

0

二进制位

0

1

0

0

0

1

1

0

1

0

从表格中我们可以直观地看到,哪个整数在集合中,那么该数字对应的二进制位的值就是1,反之哪个整数不在该集合中,则二进制位的值取0。

从集合中插入、删除、判断某元素是否在集合中

以上述例子继续讨论,当我们想在原集合中 插入 一个2,那么代码实现是:

a = 0b0100011010
b = a | (1<<2) #把2插入到集合中
print(bin(b)) #0b100011110

插入数字2就是将二进制对应序号为2的位置的值置为1,表示该集合中有一个值为2的整数。

接下来,假设我们把上述集合中的元素4从集合中 删除 ,可以用代码实现:

c = b & ~(1<<4) #把4从集合中删除
print(bin(c)) #0b0100001110

假定集合b{1,2,3,4,8},判断3,5是否在集合中,可以用代码实现:

b & (1<<3) #8 (非零属于)
b & (1<<5) #0 (零不属于)

集合之间的操作

根据位数的多少来定义一个全集,比如说是16位表示一个集合 {0,1,2,...,14,15},那么其补集、任意两元素大小在0-15之间的集合的交集、并集、差集都可以用位运算的方式进行计算。以集合 a{1,5,6,8}b{1,2,5,6,8}为例。

a的补集

a = 0b0101100010
a_com = bin(~a & 0xffff)
print(a_com)
#0b1111111010011101

a的补集对应为{0,2,3,4,7,9,10,11,12,13,14,15}

a和b的交集

a = 0b0101100010
a_b = a & b #a交b
print(bin(a_b))
 # 0b101100010

交集对应的集合{1,5,6,8}

a与b的并集

a = 0b0101100010
ab = a | b #a并b
print(bin(ab)) 
# 0b101100110

对应的集合是{1,2,5,6,8}

b与a的差集

a = 0b0101100010
b_a = b & (~a) #a差b
print(bin(b_a))
 # 0b100

💡 以上二进制码输出均为补码输出

Python中二进制码输出的特殊点

首先我们来看C#语言中输出负数的例子。

class Program
{
    static void Main(string[] args)
    {
        string s1 = Convert.ToString(-3, 2);
        Console.WriteLine(s1); 
        // 11111111111111111111111111111101
        
        string s2 = Convert.ToString(-3, 16);
        Console.WriteLine(s2); 
        // fffffffd
    }
}

我们发现对于数字-3的二进制码,是以补码的形式输出。

那么在python中,结果是不一样的。

print(bin(3))  # 0b11
print(bin(-3))  # -0b11

并不是以补码的形式输出,而是在原码的二进制表示前加上负号, 巨坑 ,因此若要以补码形式输出,就要进行转换,手动将其和十六进制数 0xffffffff 进行按位与操作,再交给 bin()进行输出,得到的才是负数的补码。

print(bin(-3 & 0xffffffff))  #按位与操作
# 0b11111111111111111111111111111101

print(bin(0xfffffffd))       
# 0b11111111111111111111111111111101

print(0xfffffffd)  # 4294967293
# 测试整型长度,是否会溢出
print(bin(1213554555544897444444445555666787))
#0b11101111010101001101100100000010011111010001001110110110110011100001011100000001001000001000011010111101100011

总结

  • Python中 bin一个负数(十进制表示),输出的是它的原码的二进制表示再加上个负号,巨坑!
  • Python中的整型是以补码形式存储的。
  • Python中整型是不限制长度的,不会超范围溢出。