首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >编写高质量代码:改善Python程序的91个建议.1

编写高质量代码:改善Python程序的91个建议.1

作者头像
云深无际
发布2021-03-12 14:45:34
发布2021-03-12 14:45:34
5410
举报
文章被收录于专栏:云深之无迹云深之无迹

-U 是--upgrade的缩写,如果以已经安装就升级到最新版

先得安装一下

输出的没毛病

我们实验一下

我提前把代码改过

代码语言:javascript
复制
pep8 
--show-source 
--show-pep8 
.\search2.py    
代码语言:javascript
复制
--show-source 
--show-pep8

一个是显示哪里不符合

一个是显示正确的写法

笔记

Python的库

sphinx,生成文档注释

注释

就是先写注释,再写逻辑.对于不用的代码要不要保留的.注意空行的使用,保持上下文语言的理解性,调用者在上,被调用者在下

代码语言:javascript
复制
def A(): 
    B()
def B():
    pass

避免过长的代码行,最好不要超过80个字符.逗号和分号前不要使用空格

函数的设计原则

1.函数的设计要短小,嵌套的层次不宜过深(控制在三层以内) 2.函数的声明应该做到合理,简单,易于使用 3.函数参数参数设计应该考虑向下兼容 4.一个函数只能做一件事,尽量保证函数语句粒度的一致性. \

函数的向下兼容

通过加入默认参数来避免这种退化,做到向下兼容,不要在函数中定义可变对象作为默认值,使用异常替换返回错误,保证通过单元测试

常量

Python内部没有常量的功能.通过命名风格标识,通过定义的类来实现

代码语言:javascript
复制
import sys
class _const:
    class ConstError(TypeError):
        pass

    class ConstCaseError(ConstError):
        pass

    def __setattr__(self, name, value):
        if self.__dict__.has_key(name):
            raise self.ConstError, "Can't change const.%s" % name
        if not name.issuper():
            raise self.ConstError, 'const name'"%s" is not all uppercas'% name
        self.__dict__[name] = value


sys.modules[__name__] = _const()

以上代码就完成了,使用的时候:

代码语言:javascript
复制
import const
const.COMPANY = "IBM"

这样处理过后,代码一旦赋值就不会被更改.最好集中在一起统一管理

代码语言:javascript
复制
import const
import sys


class _const:
    class ConstError(TypeError):
        pass

    class ConstCaseError(ConstError):
        pass

    def __setattr__(self, name, value):
        if self.__dict__.has_key(name):
            raise self.ConstError, "Can't change const.%s" % name
        if not name.issuper():
            raise self.ConstError, 'const name'"%s" is not all uppercas'% name
        self.__dict__[name] = value


sys.modules[__name__] = _const()
const.MY_CONST = 1
const.MY_SCOND_CONST = 2
const.MY_THIRD_CONST*2

最后的文件就是这样的

代码语言:javascript
复制
from constant import const
print(const.MY_SCOND_CONST)
print(const.MY_THIRD_CONST)

调用的时候就是这样的写法

assert(断言)语句

代码语言:javascript
复制
x = 1
y = 2
assert x == y,"not equals"

我们先写一个,看看是什么样的

代码语言:javascript
复制
AssertionError                            Traceback (most recent call last)
<ipython-input-1-12234b9328bc> in <module>
      1 x = 1
      2 y = 2
----> 3 assert x == y,"not equals"

AssertionError: not equals

以上为打印的结果

代码语言:javascript
复制
x = 1
y = 2
# assert x == y,"not equals"
if __debug__ and not x==y:
    raise AssertionError("not equals")

其实等价的语句为这样

代码语言:javascript
复制
AssertionError                            Traceback (most recent call last)
<ipython-input-2-a11717d6503d> in <module>
      3 # assert x == y,"not equals"
      4 if __debug__ and not x==y:
----> 5     raise AssertionError("not equals")

AssertionError: not equals

这个是等价的输出.

需要知道一点,断言是影响性能的,需要在后面加上**-O**这样的执行开关

代码语言:javascript
复制
python -O filename.py

这样就可以了.

以及注意,如果本身的异常可以处理就不要用断言了,不要用断言来检查用户的输入,应该使用条件判断,不符合的时候打印一些错误提示.当函数有返回值的时候可以使用断言.判断业务逻辑的时候可以使用断言

数据交换

代码语言:javascript
复制
x,y = y,x

直接这样写就好了.那里面是什么样的原理呢? x,y = y,x的实现机制--元组 假如x=2,y=3。运行时,首先构造一个元组(y,x),然后构造另一个元组(x,y),接着用元组(y,x)赋值给(x,y),元组赋值过程从左到右,依次进行。根据元组的特性,此时构造的元组的两个元素并不是x和y,而是这两个变量所指向的地址空间里的内容。如果此时再另x=y,即x=3,在地址空间中会另开辟出一块空间存储3,x进而指向这块空间,而元组中的值仍然保持不变,即元组中的x仍然等于2。因此,再实现y=x的赋值时,y的值为2,从而实现交换变量的值。

代码语言:javascript
复制
简单来说,对于“x,y=y,x”,有y,x所构成的元组(y,x)其实应该表示为(3,2),然后进行赋值就可以交换变量的值了。
代码语言:javascript
复制
import dis
def swep1():
    x=2
    y=3
    x, y = y, x

def swep2():
    x =2
    y =3
    temp = x
    x = y
    y = temp

# print('swep1()')
# swep1()
dis.dis(swep1)
dis.dis(swep2)

此为用字节码分析的源码

代码语言:javascript
复制
  3           0 LOAD_CONST               1 (2)
              2 STORE_FAST               0 (x)

  4           4 LOAD_CONST               2 (3)
              6 STORE_FAST               1 (y)

  5           8 LOAD_FAST                1 (y)
             10 LOAD_FAST                0 (x)
             12 ROT_TWO
             14 STORE_FAST               0 (x)
             16 STORE_FAST               1 (y)
             18 LOAD_CONST               0 (None)
             20 RETURN_VALUE
代码语言:javascript
复制
  8           0 LOAD_CONST               1 (2)
              2 STORE_FAST               0 (x)

  9           4 LOAD_CONST               2 (3)
              6 STORE_FAST               1 (y)

 10           8 LOAD_FAST                0 (x)
             10 STORE_FAST               2 (temp)

 11          12 LOAD_FAST                1 (y)
             14 STORE_FAST               0 (x)

 12          16 LOAD_FAST                2 (temp)
             18 STORE_FAST               1 (y)
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE

执行结果,第二段代码生成了三个load_fast和三store_fast的指令,而rot_two是交换两个栈的最顶层元素,它比执行一个load_fast+store_fast快

惰性运算

Lazy evaluation常被译为“延迟计算”或“惰性计算”,指的是仅仅在真正需要执行的时候才计算表达式的值。人的自然性情,在多的情况下,倾向于快。计算机性能优越的情况下,程序员倾向快速编写出可运行的代码,质量的问题会凸显。延迟计算这样的方法,是需要花费心力的,Lazy evaluation 其实并不 lazy .而且资源永远都是有限的,而需求永远都是无法满足的。性能效率是永恒的话题。

短路求值

短路求值。几乎所有语言都有的特性,这说明了这个优化的重要性。但觉得这不是lazy evaluation的重点。lazy evaluation还是一种“能拖就拖,假装自己完成了每项工作流程,但其实只是记到小本本上了,直到老师要求交作业时实在没法拖时才真正开始写”的感觉。但是老师不收作业的时候,它就可以不用写了~lazy的目的是万一最后不需要计算就省资源.因此在编程过程中,如果对于or条件表达式应该将值为真可能性较高的变量写在or的前面,而and则应该推后。

无限的数据结构

生成器可以节省空间,因为它的操作结果是“一个”而不是“一组”。常见的生成器函数包含yield和无限循环,而且会被多次调用,每次调用走到yield语句即返回,下次再被调用则从yield 语句的下一个语句开始执行,直到yield语句返回,循环往复因此可以“无限”. itertools模块包含创建有效迭代器的函数,可以用各种方式对数据进行循环操作,此模块中的所有函数返回的迭代器都可以与for循环语句以及其他包含迭代器(如生成器和生成器表达式)的函数联合使用。 创建一个迭代器,生成项的方式类似于切片返回值:iterable[start : stop : step],将跳过前start个项,迭代在stop所指定的位置停止,step指定用于跳过项的步幅。与切片不同,负值不会用于任何start,stop和step,如果省略了start,迭代将从0开始,如果省略了step,步幅将采用1.

代码语言:javascript
复制
 def islice(iterable, *args):
      # islice('ABCDEFG', 2) --> A B
      # islice('ABCDEFG', 2, 4) --> C D
      # islice('ABCDEFG', 2, None) --> C D E F G
      # islice('ABCDEFG', 0, None, 2) --> A C E G
      s = slice(*args)
      it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
      nexti = next(it)
      for i, element in enumerate(iterable):
         if i == nexti:
             yield element
             nexti = next(it)
 
#如果start为None,则迭代从零开始。如果step为None,则该步骤默认为1。
#在版本2.5中已更改:默认设置为start和step,不接受None值。

枚举二三事

谈起枚举的话,最经典的就是季节和星期了.,它能够以更接近自然语言的方式来表达数据,可是在Python内没有被加进来,之前也申请过~ 1.使用类属性

代码语言:javascript
复制
class Season:
    Spring = 0
    Summer = 1
    Autumn = 2
    Winter = 3
print(Season.Spring)

让我们再简化一点,让他看起来更像是一个枚举~

代码语言:javascript
复制
class Season:
    Spring,Summer,Autumn,Winter = range(4)

或者...为什么不写一个函数呢?

代码语言:javascript
复制
def enum(*posarg,**kwargs):
    return type("Enum",(object,),dictt(zip(posarg,xrange(len(posarg))),**kwargs))
Seasons = enum("Spring", "Summer", "Autumn", "Winter1=1")
Seasons.Spring

不推荐使用type来进行类型检查

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 笔记
    • Python的库
    • 注释
    • 函数的设计原则
      • 函数的向下兼容
    • 常量
    • assert(断言)语句
    • 数据交换
    • 惰性运算
      • 短路求值
      • 无限的数据结构
      • 枚举二三事
      • 不推荐使用type来进行类型检查
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档