本文是在天池学习路线中的『python基础入门』板块, 之前学习过部分, 在此记录一些易错点和不熟悉的地方. 仅作补充, 并不是全部知识点.
详细知识点的所有代码均可在我的GitHub仓库TianChi-Studying中找到.
本笔记为阿里云天池龙珠计划Python训练营的学习内容,链接为:https://tianchi.aliyun.com/specials/promotion/aicamppython;
文章目录
运算符
位运算
位运算对于我们人类来说是反直觉的, 而对于计算机来说是更加符合计算方式的, 所以位运算的速度通常来的较快.
二进制有原码-反码-补码3种形式, 计算机存储的二进制是补码
的形式.
正数的原码补码和反码都相同.
负数是开头使用一位符号位1, 其余部分: 原码同正数, 反码取反, 补码是反码+1.
例如:
# 原码
0000 0011 -> 3
1000 0011 -> -3
# 反码
0000 0011 -> 3
11 11 1100 -> -3
# 补码
0000 0011 -> 3
1111 1101 -> -3
那我们来看看python中二进制转换函数bin的表现吧.
print(bin(3)) # 0b11
print(bin(-3)) # -0b11
print(bin(-3 & 0xffffffff))
# 0b11111111111111111111111111111101
⚠️ 注意到-3
是不是跟我们说的不一样(@_@😉, 而实现正则的负数需要和0xffffffff
按位与才行, 记住就行.
下面列举常见操作符:
操作符 | 名称 | 示例 |
---|---|---|
~ | 按位取反 | ~4 |
& | 按位与 | 4 & 5 |
| | 按位或 | 4 | 5 |
^ | 按位异或 | 4 ^ 5 |
<< | 左移 | 4 << 2 |
>> | 右移 | 4 >> 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
在算法中也经常有使用整数的二进制位来表示类似数组元素存在与否, 可以降低时空复杂度, 不在此处阐述. 当然还有其他的技巧, 可以多搜搜看.
补充2个位运算的小技巧: 练习的话可以参考leetcode231. 2 的幂和191. 位1的个数
- 判断偶数:
(n & 1)
- 消去二进制位最后一个1:
(n & (n-1))
is 和 ==
is
: 表示是或不是;==
: 表示等或不等.
看起来差别不大, 但是他们比较的对象不同
is
: 比较的是变量的内存地址;==
: 比较的是变量的值.
针对不可修改的变量, 例如字符串, 值相同的变量, 指向的内存地址是一致的.
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 | 身份运算符 |
in 和 not in | 成员运算符 |
not and or | 逻辑运算符 |
数据类型
浮点型
浮点型的赋值还可以使用e
来表示
a = 0.00000023
b = 2.3e-7
print(a) # 2.3e-07
print(b) # 2.3e-07
如果精度要求比较高可以考虑使用decimal
库, 一般感觉很少需要.
import decimal
from decimal import Decimal
判断数据类型
使用isinstance
查看数据类型是否符合预期.
print(isinstance(1, int)) # True
print(isinstance(5.2, float)) # True
print(isinstance(True, bool)) # True
print(isinstance('5.2', str)) # True
循环
与else
之前知道while
循环后可以跟一个else
, 但是感觉没什么用, 最近刷leetcode
后再学习这个知识, 发现原来是while
中break
的话else
可以不执行, 感觉稍微有些用了, for
也同理可跟else
.
for num in range(10, 20): # 迭代 10 到 20 之间的数字
for i in range(2, num): # 根据因子迭代
if num % i == 0: # 确定第一个因子
j = num / i # 计算第二个因子
print('%d 等于 %d * %d' % (num, i, j))
break # 跳出当前循环
else: # 循环的 else 部分
print(num, '是一个质数')
# 输出
# 10 等于 2 * 5
# 11 是一个质数
# 12 等于 2 * 6
# 13 是一个质数
# 14 等于 2 * 7
# 15 等于 3 * 5
# 16 等于 2 * 8
# 17 是一个质数
# 18 等于 2 * 9
# 19 是一个质数
与enumerate
enumerate(sequence, [start=0])
- sequence:一个序列、迭代器或其他支持迭代对象.
- start:下标起始位置.
- 返回 enumerate(枚举) 对象.
用 enumerate(A)
不仅返回了 A
中的元素, 还顺便给该元素一个索引值 (默认从 0 开始). 此外, 用 enumerate(A, j)
还可以确定索引起始值为 j
.
languages = ['Python', 'R', 'Matlab', 'C++']
for i, language in enumerate(languages, 2):
print(i, 'I love', language)
print('Done!')
# 2 I love Python
# 3 I love R
# 4 I love Matlab
# 5 I love C++
# Done!
元组推导式和next
列表推导式得到的结果是一个列表无疑. 而元组推导式得到的结果是一个『生成器对象』, 这一点需要注意一下. 如果需要转化成元组, 则使用tuple()
函数.
此外, 需要使用生成器对象时, 可以使用next(iterator[, default])
进行遍历.
e = (i for i in range(10))
print(e)
# <generator object <genexpr> at 0x0000007A0B8D01B0>
print(next(e)) # 0
print(next(e)) # 1
for each in e:
print(each, end=' ')
# 2 3 4 5 6 7 8 9
print()
# print(next(e)) # StopIteration
print(next(e, 'hh')) # hh
可以发现, 不管是使用next
还是for
循环进行遍历, 生成器对象的元素每输出一次都会减少一个, 是一次性消耗品.
对next函数给定默认值时, 则会在生成器对象为空时输出默认值, 否则抛出StopIteration异常.
异常处理
标准异常
1. Python 标准异常总结
- BaseException:所有异常的 基类
- Exception:常规异常的 基类
- StandardError:所有的内建标准异常的基类
- ArithmeticError:所有数值计算异常的基类
- FloatingPointError:浮点计算异常
- OverflowError:数值运算超出最大限制
- ZeroDivisionError:除数为零
- AssertionError:断言语句(assert)失败
- AttributeError:尝试访问未知的对象属性
- EOFError:没有内建输入,到达EOF标记
- EnvironmentError:操作系统异常的基类
- IOError:输入/输出操作失败
- OSError:操作系统产生的异常(例如打开一个不存在的文件)
- WindowsError:系统调用失败
- ImportError:导入模块失败的时候
- KeyboardInterrupt:用户中断执行
- LookupError:无效数据查询的基类
- IndexError:索引超出序列的范围
- KeyError:字典中查找一个不存在的关键字
- MemoryError:内存溢出(可通过删除对象释放内存)
- NameError:尝试访问一个不存在的变量
- UnboundLocalError:访问未初始化的本地变量
- ReferenceError:弱引用试图访问已经垃圾回收了的对象
- RuntimeError:一般的运行时异常
- NotImplementedError:尚未实现的方法
- SyntaxError:语法错误导致的异常
- IndentationError:缩进错误导致的异常
- TabError:Tab和空格混用
- SystemError:一般的解释器系统异常
- TypeError:不同类型间的无效操作
- ValueError:传入无效的参数
- UnicodeError:Unicode相关的异常
- UnicodeDecodeError:Unicode解码时的异常
- UnicodeEncodeError:Unicode编码错误导致的异常
- UnicodeTranslateError:Unicode转换错误导致的异常
断言 assert 关键词
assert
这个关键词我们称之为『断言』, 当这个关键词后边的条件为 False 时, 程序自动崩溃并抛出AssertionError
的异常.
age = 17;
assert age > 18 # 程序停止, 抛出异常
常用于单元测试.
try - except - finally 语句
之前我也一直以为finally没什么用的, 这次学到了.
- 若
try
没有异常, 那么程序执行完try
后执行finally
; - 若
try
存在异常, 并被except
拦截到了, 那么执行except
后执行finally
; - 若
try
存在异常, 但是没有被except
拦截到, 那么先执行finally
, 再报错!
def divide(x, y):
try:
result = x / y
print("result is", result)
except ZeroDivisionError:
print("division by zero!")
finally:
print("executing finally clause")
divide(2, 1)
# result is 2.0
# executing finally clause
divide(2, 0)
# division by zero!
# executing finally clause
divide("2", "1")
# executing finally clause
# TypeError: unsupported operand type(s) for /: 'str' and 'str'
raise语句
Python 使用raise
语句抛出一个指定的异常.
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
# An exception flew by!
之前我一直以为raise没什么用, 这次还是o(▽)q.
参考
个人收获
巩固了python基础知识, 补充了一些小知识, 一鼓作气继续学.