概述

  • 学习地址:https://tianchi.aliyun.com/s/58327c15d1faee512c008128d3bb9e32
  • 学习内容:运算符、数据类型与转换、位运算
  • 问题:对按位运算不熟悉
  • 总结:编程基础知识需要加强

一、注释

#表示注释,作用于整行
''' '''或者""" """表示区间注释,在三引号之间的所有内容被注释

二、运算符

1. 算数运算符

// 整除(地板除) 3//4=0
注释:整除是将原本带小数的结果向负无穷方向去,取最近的整数;而int是向0靠近,取最近的整数。

print(11 // 2) # 5
print(-11 // 2) # -6
print(0.4//0.2) # 2.0
print(0.6//0.2) # 2.0

注:
浮点数近似到最近的偶数
0.5/0.1=4.9999999999 (所以//后,是4.0)
资料:https://www.zhihu.com/question/68131179/answer/261539674

% 取余 3%4=3
** 幂 2**3=8

2. 比较运算符

>= 大于等于
<= 小于等于
!= 不等于

3. 逻辑运算符

and 与 (3 > 2) and (3 < 5) = ture
or 或 (1 > 3) or (9 < 2) = false
not 非 not (2 > 1) =false

4. 位运算符

& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0。

| 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。

^ 按位异或运算符:当两对应的二进位相异时,结果为1。

~按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 。~x 类似于 -x-1

<<左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0。

>>右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数。

print(bin(4))  # 0b100
print(bin(5))  # 0b101
print(bin(~4), ~4)  # -0b101 -5
print(bin(4 & 5), 4 & 5)  # 0b100 4
print(bin(4 | 5), 4 | 5)  # 0b101 5
print(bin(4 ^ 5), 4 ^ 5)  # 0b1 1
print(bin(4 << 2), 4 << 2)  # 0b10000 16
print(bin(4 >> 2), 4 >> 2)  # 0b1 1

补充:

  1. bin() 返回一个整数 int 或者长整数 long int 的二进制表示,例如:
>>>bin(10)
'0b1010'
>>> bin(20)
'0b10100'
  1. 进制规则:
    十进制(D):
    进位规则:满十进一
    二进制(B)
    进位规则:逢二进一
    借位规则:借一当二
    数据以补码的形式储存
    十六进制(H):
    由0-9,A-F组成(不区分大小写)

(补)小数二进制:

文字描述该过程如下:将该数字乘以2,取出整数部分作为二进制表示的第1位;然后再将小数部分乘以2,将得到的整数部分作为二进制表示的第2位;以此类推,知道小数部分为0。
特殊情况: 小数部分出现循环,无法停止,则用有限的二进制位无法准确表示一个小数,这也是在编程语言中表示小数会出现误差的原因

例:0.6的二进制

0.6 * 2 = 1.2 ——————- 1 
0.2 * 2 = 0.4 ——————- 0 
0.4 * 2 = 0.8 ——————- 0 
0.8 * 2 = 1.6 ——————- 1 
0.6 * 2 = 1.2 ——————- 1 
…………
  1. 进制前后缀
    二进制:(前缀:0b/0B)(后缀:b/B)
    八进制:(前缀:0)(后缀:o/O)
    十进制:(前缀:无,可加+/-)(后缀d/D)
    十六进制:(前缀:0x/0X)(后缀:h/H)

5.三元运算符

三元运算符是软件编程中的一个固定格式,语法是“条件表达式?表达式1:表达式2”。

x, y = 4, 5
if x < y:
    small = x
else:
    small = y

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

6. 其他运算符

in存在
‘A’ in [‘A’, ‘B’, ‘C’]
not in不存在
‘h’ not in [‘A’, ‘B’, ‘C’]
is
“hello” is “hello”
not is不是
“hello” is not “hello”

letters = ['A', 'B', 'C']
if 'A' in letters:
    print('A' + ' exists')
if 'h' not in letters:
    print('h' + ' not exists')
**********************************************
a = "hello"
b = "hello"
print(a is b, a == b)  # True True
print(a is not b, a != b)  # False False

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

注意:

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

7. 运算符优先级

  • 一元运算符优于二元运算符。例如3 ** -2等价于3 ** (-2)。
  • 先算术运算,后移位运算,最后位运算。例如 1 << 3 + 2 & 7等价于 (1 << (3 + 2)) & 7。
  • 逻辑运算最后结合。例如3 < 4 and 4 < 5等价于(3 < 4) and (4 < 5)。
print(-3 ** 2)  # -9 指数(最高优先级)
print(3 ** -2)  # 0.1111111111111111
print(1 << 3 + 2 & 7)  # 0
print(-3 * 2 + 5 / -2 - 4)  # -12.5
print(3 < 4 and 4 < 5)  # True

补:

运算符

描述

**

指数 (最高优先级)

~ + -

按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@)

* / % //

乘,除,取模和取整除

+ -

加法减法

>> <<

右移,左移运算符

&

位 ‘AND’

^ |

位运算符

<= < > >=

比较运算符

<> == !=

等于运算符

= %= /= //= -= += *= **=

赋值运算符

is is not

身份运算符

in not in

成员运算符

not and or

逻辑运算符

以上表格转载自:https://www.runoob.com/python/python-operators.html

三、变量与赋值

  • 在使用变量之前,需要对其先赋值。
  • 变量名可以包括字母、数字、下划线、但变量名不能以数字开头。
  • Python 变量名是大小写敏感的,foo != Foo。
myTeacher = "老马的程序人生"
yourTeacher = "小马的程序人生"
ourTeacher = myTeacher + ',' + yourTeacher
print(ourTeacher)  # 老马的程序人生,小马的程序人生

四、数据类型与转化

1. 数据类型

类型

名称

示例

int

整型 <class ‘int’>

-876, 10

float

浮点型<class ‘float’>

3.149, 11.11

bool

布尔型<class ‘bool’>

True, False

a = 1031
print(a, type(a))
# 1031 <class 'int'>
*******************************
print(1, type(1))
# 1 <class 'int'>

print(1., type(1.))
# 1.0 <class 'float'>

a = 0.00000023
b = 2.3e-7
print(a)  # 2.3e-07
print(b)  # 2.3e-07
  • 有时候我们想保留浮点型的小数点后 n 位。可以用 decimal 包里的 Decimal 对象和 getcontext() 方法来实现。Decimal 对象的默认精度值是 28 位 (prec=28)
import decimal
from decimal import Decimal
b = Decimal(1) / Decimal(3)
print(b)

# 0.3333333333333333333333333333
**********************************************************
b=1/3
print(b)

# 0.3333333333333333
  • 布尔 (boolean) 型变量只能取两个值,True 和 False。当把布尔型变量用在数字运算中,用 1 和 0 代表 True 和 False。
print(True + True)  # 2
print(True + False)  # 1
print(True * False)  # 0
  • bool() 作用在基本类型变量:X 只要不是整型 0、浮点型 0.0,bool(X) 就是 True,其余就是 False
print(type(0), bool(0), bool(1))
# <class 'int'> False True

print(type(10.31), bool(0.00), bool(10.31))
# <class 'float'> False True

print(type(True), bool(False), bool(True))
# <class 'bool'> False True
  • bool 作用在容器类型变量:X 只要不是空的变量,bool(X) 就是 True,其余就是 False
print(type(''), bool(''), bool('python'))
# <class 'str'> False True

print(type(()), bool(()), bool((10,)))
# <class 'tuple'> False True

print(type([]), bool([]), bool([1, 2]))
# <class 'list'> False True

print(type({}), bool({}), bool({'a': 1, 'b': 2}))
# <class 'dict'> False True

print(type(set()), bool(set()), bool({1, 2}))
# <class 'set'> False True
  • 确定bool(X) 的值是 True 还是 False,就看 X 是不是空,空的话就是 False,不空的话就是 True。
    (对于数值变量,0, 0.0 都可认为是空的。
    对于容器变量,里面没元素就是空的。)
  • 如果要判断两个类型是否相同推荐使用 isinstance()。
print(isinstance(1, int))  # True
print(isinstance(5.2, float))  # True
print(isinstance(True, bool))  # True
print(isinstance('5.2', str))  # True

2. 类型转换

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

print(int('520'))  # 520
print(int(520.52))  # 520
print(float('520.52'))  # 520.52
print(float(520))  # 520.0
print(str(10 + 10))  # 20
print(str(10.1 + 5.2))  # 15.3

五、print() 函数

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
  • 将对象以字符串表示的方式格式化输出到流文件对象file里。其中所有非关键字参数都按str()方式进行转换为字符串输出;
  • 关键字参数sep是实现分隔符,比如多个参数输出时想要输出中间的分隔字符;
  • 关键字参数end是输出结束时的字符,默认是换行符\n
  • 关键字参数file是定义流输出的文件,可以是标准的系统输出sys.stdout,也可以重定义为别的文件;
  • 关键字参数flush是立即把内容输出到流文件,不作缓存。

【例子】没有参数时,每次输出后都会换行。

shoplist = ['apple', 'mango', 'carrot', 'banana']
print("This is printed without 'end'and 'sep'.")
for item in shoplist:
    print(item)

# This is printed without 'end'and 'sep'.
# apple
# mango
# carrot
# banana

【例子】每次输出结束都用end设置的参数&结尾,并没有默认换行。

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

【例子】item值与’another string’两个值之间用sep设置的参数&分割。由于end参数没有设置,因此默认是输出解释后换行,即end参数的默认值为\n。

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

六、位运算

1. 原码、反码和补码

二进制有三种不同的表示形式:原码、反码和补码,计算机内部使用补码来表示。

原码:就是其二进制表示(注意,有一位符号位)。

00 00 00 11 -> 3
10 00 00 11 -> -3

假设计算机的储存数长为8位,符号位+数值位=8

反码:正数的反码就是原码,负数的反码是符号位不变,其余位取反(对应正数按位取反)。(0-正;1-负)

00 00 00 11 -> 3
11 11 11 00 -> -3

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

00 00 00 11 -> 3
11 11 11 01 -> -3

符号位:最高位为符号位,0表示正数,1表示负数。在位运算中符号位也参与运算。

2. 按位运算

  • 按位非操作 ~~num的补码中的 0 和 1 全部取反(0 变为 1,1 变为 0)有符号整数的符号位在 ~ 运算中同样会取反。
00 00 01 01 -> 5
~
---
11 11 10 10 -> -6
  • 按位与操作 & 只有两个对应位都为 1 时才为 1
00 00 01 01 -> 5
&
00 00 01 10 -> 6
---
00 00 01 00 -> 4
  • 按位或操作 | 只要两个对应位中有一个 1 时就为 1
00 00 01 01 -> 5
|
00 00 01 10 -> 6
---
00 00 01 11 -> 7
  • 按位异或操作 ^ 只有两个对应位不同时才为 1
00 00 01 01 -> 5
^
00 00 01 10 -> 6
---
00 00 00 11 -> 3
异或操作的性质:满足交换律和结合律
A: 00 00 11 00
B: 00 00 01 11

A^B: 00 00 10 11
B^A: 00 00 10 11

A^A: 00 00 00 00
A^0: 00 00 11 00

A^B^A: = A^A^B = B = 00 00 01 11
  • 按位左移操作 <<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

3. 利用位运算实现快速计算

  • 通过 <<>> 快速计算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 位置的整数。
00 00 01 01 -> 5
&
11 11 10 11 -> -5
---
00 00 00 01 -> 1 #最后为1的数在第一位

00 00 11 10 -> 14
&
11 11 00 10 -> -14
---
00 00 00 10 -> 2 #最后为1的数在第二位

4. 利用位运算实现整数集合

比如集合 {1, 3, 4, 8},可以表示成 01 00 01 10 10 而对应的位运算也就可以看作是对集合进行的操作。
注:二进制表示集合,从右往左数,起始位是0位

  • 元素与集合的操作:
a | (1<<i)  -> 把 i 插入到集合中
a & ~(1<<i) -> 把 i 从集合中删除
a & (1<<i)  -> 判断 i 是否属于该集合(零不属于,非零属于)
  • 集合之间的操作:
a 补   -> ~a
a 交 b -> a & b
a 并 b -> a | b
a 差 b -> a & (~b)

注意:整数在内存中是以补码的形式存在的,输出自然也是按照补码输出。

【例子】 Python 的bin() 输出。

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

print(bin(-3 & 0xffffffff))  
# 0b11111111111111111111111111111101

print(bin(0xfffffffd))       
# 0b11111111111111111111111111111101

print(0xfffffffd)  # 4294967293

是不是很颠覆认知,我们从结果可以看出:

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

所以为了获得负数(十进制表示)的补码,需要手动将其和十六进制数0xffffffff进行按位与操作,再交给bin()进行输出,得到的才是负数的补码表示。