概述
- 学习地址: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) = tureor
或 (1 > 3) or (9 < 2) = falsenot
非 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
补充:
- bin() 返回一个整数 int 或者长整数 long int 的二进制表示,例如:
>>>bin(10)
'0b1010'
>>> bin(20)
'0b10100'
- 进制规则:
十进制(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
…………
- 进制前后缀
二进制:(前缀: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 << i
将num
的二进制表示向左移动i
位所得的值。
00 00 10 11 -> 11
11 << 3
---
01 01 10 00 -> 88
- 按位右移操作
>>
num >> i
将num
的二进制表示向右移动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()进行输出,得到的才是负数的补码表示。