为了知道Python代码底层都做了哪些操作,我们常常需要反编译Python代码以获得Python的字节码
我们可以获得: classes, methods, functions, or code 的字节码
获取字节码的方法
1 | # 比较`[]`和`list()`两者的不同 |
凡事预则立,不预则废
为了知道Python代码底层都做了哪些操作,我们常常需要反编译Python代码以获得Python的字节码
我们可以获得: classes, methods, functions, or code 的字节码
1 | # 比较`[]`和`list()`两者的不同 |
Python命名规范(Name Convention)
Reference: https://blog.csdn.net/real_myth/article/details/68927665
module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name.
- 单字符名称, 除了计数器和迭代器.
- 所谓”内部(Internal)”表示仅模块内可用, 或者, 在类内是保护或私有的.
- 自然语言使用双引号(想表达人为意思的,比如log,错误,提示等)
Type | Public | Internal |
---|---|---|
Modules | lower_with_under | _lower_with_under |
Packages | lower_with_under | |
Classes | CapWords | _CapWords |
Exceptions | CapWords | |
Functions | lower_with_under() | _lower_with_under() |
Global/Class Constants | CAPS_WITH_UNDER | _CAPS_WITH_UNDER |
gobal/Class Variables | lower_with_under | _lower_with_under |
Instance Variables | lower_with_under | _lower_with_under (protected) or __lower_with_under (private) |
Method Names | lower_with_under() | _lower_with_under() (protected) or __lower_with_under() (private) |
Function/Method Parameters | lower_with_under | |
Local Variables | lower_with_under |
Python值的判断与比较: np.nan, None
1 | type(None) |
1 | type(np.nan) |
1 | None == np.nan |
1 | np.nan > 10 |
np.nan != np.nan
或者np.nan is np.nan
时为True, 其他情况下和数字比较(包括和自身)都为FalseDataFrame
中的NaN
与数字比较时会出现有时候为True
有时候为False
的情况
1 | # Python3: |
1 | # Python2: |
参考链接: https://blog.csdn.net/weixin_39129504/article/details/85958295
&
|
^
~
>>
,<<
,<<=
和>>=
and
&&
or
||
not
!
Python中有些函数是直接操作当前对象的,有些函数是操作副本的
object.shape = 3,4
本文简单讲解input和raw_input函数的用法,两者都是内置函数,无需用户自己导入模块
用法
1 | input[[prompt]] |
实例
1 | while True: |
交互结果
1 | input: 123 |
总结:
"
)时,识别为str类型"
引用起来时,抛出语法错误异常用法与inputx完全相同
把所有的输入都当做字符串,注意,如果输入的字符串带有"
,那么"
会被保留在字符串内部
用法实例
1 | while True: |
交互结果
1 | input: 123 |
Python 编程中经验型的一些规范
持续更新
li[:]
等价于copy.copy(li)
li[:]
不等价于copy.deepcopy(li)
li[:]
可以简化代码1 | list1 = [1, 5, 2, 3] |
1 | def sum_all(alist): |
(比如:__len__)
len(object)
即可ob_size
属性,而不用调用__len__()
(这个函数往往会用迭代或者其他比较复杂的方法实现)(list comprehension, 简写listcomps)和生成器表达式(generator expression, 简写genexps)
listcomps
1 | [str(i) for i in range(1,10)] |
genexps
1 | (str(i) for i in range(1,10)) |
1 | def add(x, y): |
1 | from operator import mul |
1 | import pprint |
Python不像Java和C++一样,有x?y:z这样的三目运算符号,但是可以有自己的特殊使用方法,等价于三目运算符且更容易理解
1 | # same as x?y:z |
1 | list1 = [_ for _ in list2 if _.val > 10] |
异常处理的正确姿势, 注意如果不是必要的话不要使用Exception, 可以考虑列出来需要捕获的所有异常, 然后在函数内部判断异常类型
1 | try: |
当然, 我们一般为了方便也会直接使用下面的方法
1 | try: |
global
关键字声明(与外部函数一样)nonlocal
(仅限Python 3)关键字声明a.append()
这样的语句a = b
这样的语句如果在三元表达式使用在加法中,需要加上括号,不然整体意思会变成错误的
比如两个结点的加法操作,带有进位carry
,我们可以简单的写一行:
下面是错误示例:
1 | val = l1.val if l1 else 0 + l2.val if l2 else 0 + carry |
上面的表达式可以理解为如果l1
不为空,返回l1.val
,否则返回0 + l2.val if l2 else 0 + carry
当l1
为空时又可以理解为如果l2
不为空,返回0+l2.val
否则返回0+carry
正确的写法
1 | val = (l1.val if l1 else 0) + (l2.val if l2 else 0) + carry |
迭代键值时使用iterkeys()
而不是keys()
iterkeys()
返回一个迭代器而不是所有键值列表
keys()
返回所有键值列表
1 | # 迭代效率高 |
迭代值时也同理
1 | # 迭代效率高 |
只适用于Python3,因为涉及到*
操作
1 | a = [[1,2,3], |
*
作为操作列表解压符zip
函数返回的是一个生成器而不是列表,所以需要迭代成列表不建议使用
1 | print 0 or 1 |
理解
1 | print a or b |
记忆:
a
, b
当做逻辑表达式,如果访问到b
则返回b
,否则返回a
接受参数为可迭代对象,返回一个反向访问迭代对象的迭代器
1 | for i in reversed(range(n)): |
reversed
的使用似乎更优雅,也更容易理解
容易遗忘的点,需要注意: reversed的参数必须是可迭代的对象,而不是两个数字
返回值
1 | if i < 0: return Flase |
其他简单的执行语句直接合并
1 | i = 10; j = 10 |
判断语句之后使用
1 | if bool: i = 10; |
判断语句后使用多条
1 | if bool: i = 10; j = 20 |
while语句后使用
1 | while(bool): print 10; print 20 |
当句子较长时不建议使用
一般为了美观,平时的项目也不建议使用
刷题时为了让代码看起来简便,是可以使用的,但是这样会使得代码不易调试
总之:慎用
1 | x = y = value |
1 | head, curr = ListNode(None) |
collections.Counter
1 | import collections |
Python编程笔记,各种易忘点总结
持续更新
1 | l = [0] * 10 |
1 | l = [1, 3, 2, 3, 3, 3] |
1 | s = "12345" |
1 | import random |
1 | l = [1,3,4,2] |
bool(object)
bool(object)
调用的时object.__bool__()
__bool__
方法,那么会尝试调用__len__
方法1 | id(object) |
*=
和+=
,表现也是一样的,只是对象id会改变,等价于调用了__add__()
然后又赋值给当前变量*1 | tu1 = (1,2,3) |
key
“一些需要比较功能的函数都会有此参数
key = len
排序,忽略大小写排序key = str.lower
比较等功能1 | # Python |
1 | // Java |
i
是局部变量,所以在代码执行完成后变量i
是不能访问的i
是全局变量,所以i的值为最后一次迭代的值9
1 | import re |
1 | def visit(): |
Python里面的无穷大与C++不同,C++里面是定义一个最大的整数实现,Python里面可以视为一个无穷大的对象
和数学分析里面一样,我们可以和无穷大做计算,加上无穷大还是无穷大
1 | x = float('inf') |
nan == nan
返回False
copy.deepcopy支持对可变对象的深度复制,直到解析到不可变对象为止
1 | import copy |
如果list对象元素都是不可变对象,那么可以有简便实现
1 | list1 = [1,3,4,5,6] |
测试
1 | import copy |
not " "
返回的是False
not " "
是True
" "
不是什么都没有,而是有个space字符None
等是空的,not None
, not []
, not ''
等均为True
1 | print not " " |
1 | # max |
1 | print abs(-11) |
1 | print 3.5 // 2 |
//
是整除符号,只保留整数部分,但是结果的类型可能为整数,也可能为浮点数,具体取决于除法两边是否含有浮点数1 | l = [1,2,3,4,5] |
l
中使用-1
可以理解为len(l)-1
,不管是字列表还是元素的索引操作1 | print sorted("1523") |
Python
1 | for i in range(0, 5): |
Java/C++
1 | int i; |
如果想得到Java/C++的效果,可以使用while语句
1 | i = 0 |
特别注意: join函数的参数只能是字符串,不能是数字
1 | l = [1,2,3,4] |
原始定义
1 | dict.get(key[,default=None]) |
default
参数可以指定默认值,当key
值不存在时可以返回默认值,如果不指定,则默认key
值不存在时返回None
与dict[key]
对比
dict[key]
时要确保key
在dict
中,否则会报异常必须在每个子行行尾部使用\
子行内部不用对齐,因为解析时Python解释器会将所有子行合并成一行
示例:
1 | if 9 < 10 and 11 < 12 and 13 < 14: |
等价于
1 | if 9 < 10 and \ |
等价于
1 | if 9 < 10 and \ |
x=10
这样的赋值算是变量的定义,不是使用),那么默认函数认为他是全局变量,当函数被调用的时候,才会寻找全局变量是否在当前Python运行环境中1 | def sum_x(y): |
测试代码
1 | a = [1,2,3,4,5,6] |
d
,所以修改d
的值将不影响原始的列表b
del
删除列表或字典中的元素删除列表或字典中的元素
1 | l = [1, 2, 3] |
注意不能删除元组中的元素
1 | t = (1,2,3) |
1 | d = {"m": 10, "x": 11} |
1 | ['x', 'm'] |
1 | dict_keys(['m', 'x']) |
set
信息,占用空间小,但是会造成使用x in d.keys()
时变成线性搜索时间 O(n)dict_keys
类型的对象,保留了set
信息,占用空间也大了,便于使用x in d.keys()
时变成常数搜索时间 O(1)[::-1]
切片完整用法
1 | li[start:end:step] |
start
: 开始索引,包含li[start]
,默认为0
end
: 结束索引, 不包含li[end]
,默认为len(li)
step
: 跳着取元素,step
为间隔,默认为1
step
可以设置为负, 此时若start > end
则能得到,从[start,end]
结束的序列,包含li[start]
, 不包含li[end]
, 由于此时start > end
, 所以得到的是逆序列step
参数省略的话第二个:
也能省略代码示例
1 | A = [0,1,2,3,4,5,6,7,8,9] |
vars
函数的使用定义
1 | def vars(p_object=None): # real signature unknown; restored from __doc__ |
vars(object)
返回对象的字典代码示例
1 | class A: |
注意: object.__dict__
一般在序列化的时候访问,平时不会访问
方法1
1 | a = 10.234 |
方法2
1 | a = 10.234 |
问题代码
1 | funs = [] |
i
作为引用对象解决方案:
1 | funs = [] |
i
的值复制给默认参数,这一步实现了值的复制Pandas库中apply, applymap和map函数的使用
DataFrame
类和Series
类DataFrame
类Series
类DataFrame
中是对列或者行操作,每一列或者行都是一个Series
(列: axis=0
[默认值],行: axis=1
)Series
中是对每个元素进行操作(其实换个角度理解为对Series
的每一列操作也行,此时的每一列就是一个元素,值得注意的是此时的每个元素是数值类型而不是Series
类型,所以不能对其调用sum
等函数)# a simple example for apply(), applymap() and map()
func_series = lambda x: x.sum()
func_element = lambda x: "%.2f" % x
df.apply(func_series)
df.applymap(func_element)
ser.apply(func_element)
ser.map(func_element)