分享 100 题之前,先给大家推荐一个工具,是一个对 Python 运行原理进行可视化分析的工具,Python Tutor,点击 Next 按钮就会根据执行步骤显示原理,对新手理解代码运行原理有很大帮助。
可以明显看到 sort() 会就地在原序列上排序,sorted() 新建了一个新的序列。
解法1:直接用运算符 **
用 join 方法,合并序列的元素
用字符串中的 center 方法,他会在两边自动填充字符(默认为空格),让字符串居中
用 find 方法,如果找到,就返回子串的第一个字符的索引,否则返回 -1
解法2:用切片赋值的方法
extend 是直接在 l 列表里加入元素,相加会生成一个新元素,并不会对 l 做修改。
解法2:用切片的方式插入
pop 方法可以删除指定元素,不指定位置的话默认删除最后一个元素
remove 方法只会删除第一次出现的元素
1个元素的元组,必须在唯一的元素后加上逗号,否则不是元组
用 split 方法,括号为空的情况下默认以空格拆分
用 pass 占位,当你还没想好代码块的逻辑时,你需要运行代码调试其他功能,需要加占位符,不然会报错
在 def 语句后面把注释文档放在引号(单引、双引、三引都可以)里面就行,这个文档可以通过 function.__doc__访问。
在方式名称前加两个下斜杠 __
用 issubclass 方法,2 个参数,如果第一个参数是第二个参数的子类,返回 True,否则返回 False
用 all 方法,这个方法查出的是模块下不带_的所有方法,可以直接调用。
解法2:使用按位或运算符 |
差集指的是两个集合交集外的部分
解法1: 使用运算符 ^
用 open 函数,模式用 r(默认情况下是r)
用 sys 下的 path 方法,返回的是目录名称的字符串列表
很明显,用列表推导式实现比 for 循环加 append 更高效简洁,可读性更好。
解法1:使用生成器表达式产生笛卡尔积,可以帮忙省掉运行 for 循环的开销。
我们经常用 for 循环提取元组里的元素,对于我们不想接收的元素,我们可以用占位符 _ 接收。
用 *args 的方式,*args 位置可以在任意位置。
不会,可变序列用*=(就地乘法)后,不会创建新的序列,新元素追加到老元素上,以列表为例,我们看下新老列表的id,相等的。
会,不可变序列用*=(就地乘法)后,会创建新的序列,以元组为例,我们看下新老元组的id,是不同的。
所以,对不可变序列进行重复拼接操作的话,效率会很低,因为每次都有一个新对象,而解释器需要把原来对象中的元素先复制到新的对象里,然后再追加新的元素。
到底会发生下面4种情况中的哪一种?
b.因为tuple不支持对它的元素赋值,所以会抛出TypeError异常。
d. a和b都是对的。
答案是d,请看下运行结果。
通过 Python Tutor 工具我们可以看到,sort() 会就地在原序列上排序,sorted() 新建了一个新的序列。
list.sort方法会就地排序列表,也就是说不会把原列表复制一份。这也是这个方法的返回值是None的原因,提醒你本方法不会新建一个列表。在这种情况下返回None其实是Python的一个惯例:如果一个函数或者方法对对象进行的是就地改动,那它就应该返回None,好让调用者知道传入的参数发生了变动,而且并未产生新的对象。
可以通过切片指定位置插入,头部就是[0:0]
还可以通过 insert() 方法插入,第一个参数是位置的坐标,从 0 开始。
在第一个元素之前添加一个元素之类的操作是很耗时的,因为这些操作会牵扯到移动列表里的所有元素。有没有更高效的方法?用双向队列 deque 类。
deque 类可以指定这个队列的大小,如果这个队列满员了,还可以从反向端删除过期的元素,然后在尾端添加新的元素。
Python中,你知道怎么创建字典吗?
用字典推导(dictcomp)构建字典
用setdefault方法,只查询一次,效果更快
如果用下面这种方法,需要查询三次
像k in my_dict.keys( )这种操作在Python 3中是很快的,而且即便映射类型对象很庞大也没关系。这是因为dict.keys( )的返回值是一个“视图”。视图就像一个集合,而且跟字典类似的是,在视图里查找一个元素的速度很快。在“Dictionary view objects”里可以找到关于这个细节的文档。Python 2的dict.keys( )返回的是个列表,因此虽然上面的方法仍然是正确的,它在处理体积大的对象的时候效率不会太高,因为k in my_list操作需要扫描整个列表。
用collections中的Counter方法统计,返回的结果是对应元素和个数形成的键值对。
怎么统计出排名前n的元素?
用most_common方法,参数里填n,比如前两名的话
如果m和n不是集合的话,直接转换后再取交集
高级解法的另一种写法:
使用 dir 函数来获取对象的所有属性。
创建一个空的用户定义的类和空的函数,计算差集,然后排序。
那就要在关键字参数前加一个 *。
这样的话,b 参数强制必须传入实参,否则会报错。
代码执行时,注解不会做任何处理,只是存储在函数的__annotations__属性(一个字典)中。
函数声明中的各个参数可以在:之后增加注解表达式。如果参数有默认值,注解放在参数名和=号之间。如果想注解返回值,在)和函数声明末尾的:之间添加->和一个表达式。
Python对注解所做的唯一的事情是,把它们存储在函数的__annotations__属性里。仅此而已,Python不做检查、不做强制、不做验证,什么操作都不做。换句话说,注解对Python解释器没有任何意义。注解只是元数据,可以供IDE、框架和装饰器等工具使用
函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。这突出了Python程序员所说的导入时和运行时之间的区别。
会报错,Python编译函数的定义体时,先做了一个判断,那就是 b 是局部变量,因为在函数中给它赋值了。但是执行 print(b) 时,往上又找不到 b 的局部值,所以会报错。
Python 设计如此,Python 不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量。
我们知道,在闭包中,声明的变量是局部变量,局部变量改变的话会报错。
为了解决这个问题,Python 3引入了 nonlocal 声明。它的作用是把变量标记为自由变量
用 is 比较,ID一定是唯一的数值标注,而且在对象的生命周期中绝不会变
可以用内置的 format( )函数和str.format( )方法。
可能有同学会想到用 pop(),但这个方法会就地删除原序列,不会复制出一个新的序列。
可以用切片的思想,比如复制后去掉后两个元素。
在属性前加两个前导下划线,尾部没有或最多有一个下划线
两边必须是同类型的对象才能相加,+= 右操作数往往可以是任何可迭代对象。
高效的方法需要用到 itertools 和 operator 模块,导包后一行代码搞定。