Effective_Python要点笔记

effective python 要点笔记

Pythonic Thinking

查看Python版本

遵循PEP8风格编程风格

关于空格的使用

使用空格而不是tab键来缩进 每行代码应尽量的少于79个字符

命名

函数的变量以及属性应该使用小写,如果多个残次推荐使用下划线进行分隔

被保护的属性应该使用前导下划线来进行声明

私有的属性应该使用两个前导下划线来进行声明

类和异常信息应使用单次首字母大写形式,也就是驼峰命名法

模块解包的常量应该全部使用大写的形式

表达式和语句

使用内联否定而不是显示的表达式

if a is not b   √
if not a is b   x

当引用一个模块的时候使用绝对的模块名称,而不是与当前模块路径相关的名称

按照以下规则引入模块: 标准库/第三方库.自己的库

str和unicode相关

可以使用+运算符合并str和unicode

如何分片

分片可以以最小的代价访问到子序列的某一项

简单分片基本形式:somelist[start:end]

当分片是从头开始的,下标可以省略 assert [a:5]== a0:5]

简单分片中避免使用start,end,stride

分片中Python有针对步幅的特殊语法,形如:somelist[start:end:stride]

步幅递进时,可以使用-1来实现字符串逆序

1
2
3
4
5
x = b'abcdefg'
y = x[::-1]
print(y)

#output: b'gfedcba'

使用列表表达式而不是map和filter

python提供了从一个列表导出另一个列表的紧凑语法

1
2
3
4
5
6
7
8
9
#列表表达式
a = [1,2,3,4,5]
squares = [x*x for x in a]
print(squares)
#map
squares = map(lambda x:x ** 2,a)

#output: [1, 4, 9, 16, 25]

在列表表达式中避免使用超过两个的表达式

1
2
3
matrix = [[1,2,3],[4,5,6],[7,8,9]]
flat = [x for row in matrux for x in row]
print(flat)

复杂地方考虑使用生成器表达式

python提供了一个generator expression(生成器表达式).在程序运行过程中,生成器表达式不实现整个输出序列.每次只处理一个迭代项,而不是整个序列

enumerate比range更好用

enumerate 可以读取数据的标号

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
flavor = [a,b,c,d,e,f,g]
for i,flavor in enumerate(flavor_list):
    print("%d:%s"%(i+1,flavor))

#1:a
#2:b
#3:c
#4:d
#5:e
#6:f
#7:g

用拉链来并行处理迭代器

python3中,zip通过生成器封装了两个或者更多的迭代器.

拉链函数处理时,迭代器的长度最好保持一致.如果其中一个的得带器走到头,则剩下的数据将不予展示,直接 截断输出.

for和while循环体后避免使用else语句块

当遍历数据结构为空,或不完整时,会执行其后的else,其他情况,需要避免

try/except/finally中受益

try/finally组合语句可以使得代码简洁和无视try块中是否发生异常

函数

返回exception而不是None

返回一个特殊的值为None时,可以将其转化为except

1
2
3
4
5
6
7
8
def divide(a,b):
    try:
        return a/b
    except ZeroDivisionError:
        return None 
result = divide(x,y)
if result is None:
    print('Invalid inputs!')

类和继承

  • 继承
  • 多态
  • 封装

##对简单接口使用函数而不是类

使用@classmethod多态性构造对象

多态是一个对于分层良好的类树中,不同类之间相同名称的方法却实现了不同的功能的体现.

Python的每个类只支持单个的构造方法 __init__

使用@classmethod可以为类定义可替代构造方法的方法

类的多态为具体子类的组合提供了一种更加通用的方式

使用super关键字初始化父类

super将父类的初始化顺序进行了标准化声明,保证了菱形继承中超类只执行一次.

多使用公共属性,而不是私有属性

访问私有属性时,需要利用baz._MyParentObject__private_field进行访问 否则会曝出异常AttributeError: ;MyChildObject' objetc has no attribute '__private_field'.


@classmethod和@staticmethod装饰器使用介绍

@classmethod和@staticmethod都是在类中定义函数时采用的

在定义一个函数时,没有用到任何类和实例的属性、变量,那么在定义该函数前添加@staticmethod就可以定义为 静态函数

如果在定义一个函数时,只用到了类属性但没有用到实例属性、变量,那么添加@classmethod就可以定义 类函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class test():
    my_name = "yuyu"
    def __init__(self,test_time):
        self.test_time = test_time

    @staticmethod
    def explain():
        print("This is a test class.")

    @classmethod
    def class_func(cls):
        print("My name is always",cls.my_name)

    def instance_func(self):
        print("The test time is uncertain,now is",self.test_time)

print("---if you create an instance,you can use the instance.---")
t_inst = test(12)
t_inst.explain()
t_inst.class_func()
t_inst.instance_func()


print("---if not,you can use the class without instance to call the stastic_fun and class_func---")
test.explain()
test.class_func()

#test.instance_func()
#TypeError: instance_func() missing 1 required positional argument: 'self'
  • @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
  • @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
  • 如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
  • @classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等.

updatedupdated2021-04-072021-04-07