Python丨实用技巧Tips
语法糖(Syntactic sugar)
语法糖(Syntactic sugar),也译为糖衣语法,即用更简练的代码表达更复杂的功能。
- 就像“成语”,文字精炼,含义丰富。
- 在代码中加糖以后,语法并不改变,但代码会变得更加简洁。
Python中的语法糖:
- 切片
- 上下文管理器
- 装饰器
- with语法糖
- else语法糖:for else 、while else 、 try else
- …
Python之禅
在Python交互式解释器中输入 import this
就会显示Tim Peters的 The Zen of Python
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Python之禅 by Tim Peters
优美胜于丑陋(Python 以编写优美的代码为目标)
明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)
简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)
复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)
扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)
间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)
可读性很重要(优美的代码是可读的)
即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)
不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass 风格的代码)
当存在多种可能,不要尝试去猜测
而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)
虽然这并不容易,因为你不是 Python 之父(这里的 Dutch 是指 Guido )
做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)
如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)
命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)
方便的字符串
在Python中字符串支持乘法操作,所以可以使用这样的方式输出一些特殊的字符串。
print('*'*20)
print(' '*20)
print(' '*7+'Python'+' '*7)
print(' '*20)
print('*'*20)
输出结果:
********************
Python
********************
灵魂互换
在程序中实现a和b两个人的灵魂(对应的值)互换。
a = 10
b = -10
temp = b
b = a
a = temp
×
a = 10
b = -10
a,b = b,a
√
三目运算符
- 比较两个数字,输出大的那个:
if a > b:
print(a)
else:
print(b)
- 简化
print(a if a>b else b)
使用 if-else 简化的写法称为三目运算符(三元表达式) exp1 if contion else exp2
隐式的判断条件
在判断条件中使用隐式的 True 和 False
if 1 == True:
print(True)
if 10>15 == True:
print()
if a != None:
print()
👇
if 1 :
print(True)
if 10>15 :
print()
if a :
print()
简洁的推导式
- 生成一个列表:
[i**2 for i in range(-5,5) if i%2 ]
- 生成一个集合:
{i**2 for i in range(-5,5) if i%2 }
- 生成一个字典:
{x:y for xy in zip(["a","b"],(1,2))}
小整数对象池
Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间。
- 小整数范围 [-5,256]。
- 这些整数对象会被实现建立好,不会被回收,为变量赋值时直接指向这些建立好的地址。
a = 257
b = 257
id(a) == id(b)
#
False
a = 0
b = 0
id(a) == id(b)
#
True
a = 1-1
b = 1-1
id(a) == id(b)
#
True
简单的字符串在内存使用上同样也有优化,当字符串中不存在空格和特殊字符。
a = "Python"
b = "Python"
a is b
#
True
a = "Py$thon"
b = "Py$thon"
a is b
#
False
a = "Py thon"
b = "Py thon"
a is b
#
False
变量的作用域规则 - LEGB
在Python中变量的作用域可以分为四个部分
- Local(function):函数内的名字空间;
- Enclosing function locals:外部嵌套函数的名字空间(例如closure);
- Global(module):函数定义所在模块(文件)的名字空间;
- Builtin(Python):Python内置模块的名字空间。
数据解包
获取一个列表的所有数据
for i in [1, 2, 3]:
print(i)
这样方便吗?
解包
- 使用相同数量的变量接收
a, b, c = [1, 2, 3]
print(a, b, c)
- 使用
*
L = [1, 2, 3]
print(*L)
Python中的“动态”
- 在Python中声明变量时不需要指定类型。
>>> a = 1
>>> b = 'Python'
>>> c = [1, 2, 3]
>>> print(type(a))
<class 'int'>
>>> print(type(b))
<class 'str'>
>>> print(type(c))
<class 'list'>
- 在类和对象的使用中可以动态的为对象添加属性和方法。
>>> class student(object):
def __init__(self):
self.age = 18
>>> s = student()
>>> s.name = 'axyzdong'
>>> print(s.age, s.name)
18 axyzdong
Python中的垃圾回收机制
- Python的内存管理是由Python的解释器负责的,开发人员可以从内存管理事务中解放出来。
- Python中的垃圾回收机制以“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题。通过“分代回收”(generation collection)以空间换取时间来进—步提高垃圾回收的效率。
引用计数:当一个对象的引用被创建或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1;当对象的引用计数减少为0时,就意味着对象已经没有被任何人使用了,可以将其所占用的内存释放了。
标记-清除:不改动真实的引用计数,而是将集合中对象的引用计数复制一份副本,改动该对象引用的副本。对于副本做任何的改动,都不会影响到对象生命周期的维护。
将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
分代回收
- 默认一个对象被创建出来后,属于 0 代
- 如果经历过这一代"垃圾回收"后,依然存活,则划分到下一代
- "垃圾回收"的周期顺序为
- 0代"垃圾回收"一定次数,会触发 0代和1代回收
- 1代"垃圾回收"一定次数,会触发0代,1代和2代回收
![](https://img-blog.csdnimg.cn/04115f1c0a924a34b94619aafadeab62.png#pic_center =500x)
-
当0代检测P了1次后,P若不是垃圾,则P转入1代。
-
0代继续检测,1代暂不检测。当0代检测10次,则1代开始检测1次,P若不是垃圾,则P转入2代。
-
0代和1代继续检测,2代暂不检测。当0代检测100次,1代检测10次时,则2代开始检测1次。
设计的初衷在于:若一个对象能够多次存活,则减少它的检测频率,以此来节约内存。
查看以及修改机制配置参数
垃圾回收器当中,新增对象个数减去消亡对象个数,达到一定阈值的时候,才会触发垃圾检测机制。
可以通过gc模块中的gc.get_threshold()查询参数,也可以用gc.get_threshold(500, 5, 5)来自定义参数。第一个参数是新增对象个数减去消亡对象个数的值,第二个参数是0代被检测几次式触发1代的检测,第三个参数是1代被检测几次触发2代的检测。
>>> import gc
>>> print(gc.get_threshold())
(700, 10, 10)
>>> gc.set_threshold(500,5,5)
>>> print(gc.get_threshold())
(500, 5, 5)
参考文献
- 点赞
- 收藏
- 关注作者
评论(0)