NSF Back-end Dev Engineer

python

2022-10-27
nsf

请带上游标卡尺

1.基础知识

1.1.关键字

['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

1.2.类

内置方法

__delattr__: 删除属性
__dir__: 返回一个包含有所有属性名和方法名的有序列表
__eq__: 用来判断两个对象实例是否相等
__format__: 格式化实例时使用
__getattribute__: 属性访问拦截器,就是当这个类的属性被实例访问时,会自动调用类的__getattribute__方法
__ge__: 对象比较大小使用,相当于>=
__gt__: 对象比较大小使用,相当于>
__hash__: 生成唯一id,唯一标记对象
__init_subclass__: 当子类定义之后触发,
第一个参数是 cls 而不是常见的 self ,这是因为这个方法隐式地被 @classmethod 装饰(PEP-487)。
__init__ : 构造函数,在生成对象时调用
__le__: 对象比较大小使用,相当于<=
__lt__: 对象比较大小使用,相当于>=
@staticmethod __new__: 创建类实例的静态方法,优先 __init__() 初始化方法被调用
__ne__: 对象比较大小使用,相当于!=
__reduce_ex__: 用于pickle,可以指定版本
__reduce__: 用于pickle,不能指定版本
__repr__ : 打印,转换
__setattr__: 在对一个属性设置值的时候,会调用到这个函数
__sizeof__: 
__str__: str(self)
@classmethod __subclasshook__: 接收两个类,判断一个类是不是另一个类的子类
__class__: 类的实例当成函数调用
__dict__: 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性
__doc__: 注释内容
__module__: 对象在哪个模块

函数属性

__annotations__: 参数和返回值注解
__closure__: 函数闭包,自由变量的绑定(通常为None)
__code__: 编译成字节码的函数元数据和函数定义体
__defaults__: 形式参数的默认值
__get__: 实现只读描述符协议
__global__: 函数所在模块中的全局变量
__kwdefaults__: 仅限关键字形式参数的默认值
__name__: 函数名称
__qualname__: 函数限定名称

可附加的一些 方法

1.3.字符串

Python正则替换字符串函数re.sub

命令:re.sub(pattern, repl, string, count=0, flags=0)
re.sub 用于替换字符串的匹配项。如果没有匹配到规则,则原字符串不变。

第一个参数:规则 
第二个参数:替换后的字符串 
第三个参数:字符串 
第四个参数:替换个数。默认为0,表示每个匹配项都替换

1.4.list

list做减法操作

问题描述:假设我有这样两个list,
          一个是list1,list1 = [1, 2, 3, 4, 5]
          一个是list2,list2 = [1, 4, 5] 
          我们如何得到一个新的list,list3,
          list3中包括所有不在list2中出现的list1中的元素。
          即:list3 = list1 - list2
          
解决方案:我们可以用set(集合)操作
          list3 = list(set(list1) - set(list2))
          
          set操作会将一个list转换成一个集合。
          假设:list_t = [1, 2, 3, 1]
          那么:list(set(list_t)) = [1, 2, 3]
          是的,重复的项会被删除。

其他方案:list3 = [i for i in list1 if i not in list2]       #可用于list分片
          这样写也很直观。
          但是在list很大的时候,没有set方法快。

额外知识:a = [[i,j] for i in range(2) for j in range(3)]
          这个和“其他方案”非常相似,
          都是在[]里面进行判断和计算。
          感觉很方便,至少比下面这样要方便、要快:
          a = []
          for i in range(2):
              for j in range(3):
                  a.append([i,j])

某些问题:如果list_tmp = [[1,2],[2,3]]
          即list里面不是单独的元素组成,而是list,
          那么set(list_tmp)会出问题。

1.5.import

from xx import *形式容易造成命名冲突,建议慎用!

主模块的名称在运行时会被Python强制命名为__main__,相对导入方式可以解决导入当前目录、上级目录、上上级目录下模块的需求,但使用相对导入的文件不能直接以脚本方式运行,只能以模块方式(-m选项)运行,并且当前路径要处于import语句定位的路径或更高层路径

pip freeze > requirements.txt生成该文件

ip install -r requirements.txt安装该文件所有库

1.6.异常

使用异常时如果没有引发异常是很快的,但是如果会时常引发异常,建议使用if-else,因为捕获异常是很昂贵的。

2.附加知识

2.1.反编译

安装反编译库,命令如下

pip install uncompyle

uncompyle6 –help 查看帮助 uncompyle6 models.pyc > models.py 将models.pyc反编译成py文件 uncompile -o . *.pyc 将当前文件夹中所有的pyc文件反编译成后缀名为.pyc_dis的源文件

2.2.缓存

介绍functools.lru_cache使用,我们先看下区别,测试代码如下

import timeit
from functools import lru_cache

@lru_cache()
def f1(n):
    return 0 if n == 0 else(1 if n == 1 else f1(n - 1) + f1(n - 2))
def f2(n):
    return 0 if n == 0 else(1 if n == 1 else f2(n - 1) + f2(n - 2))
print(timeit.timeit('f2(40)', globals=globals(), number=1))

f2(40)耗时60.84906945534581s,f1(40)耗时6.381289836242231e-05s,区别巨大。

@lru_cache()使能够“被冻结”的函数缓存,能够“被冻结”的指的是:在函数参数不变的情况下,函数返回值不变,从而大大提升了效率。

2.3.元类

元类是用来创建类的

2.4.functools

partial:用来”冻结”一个函数的参数,并返回”冻结”参数后的新函数,比如timeit.timeit需要使用类方法时,需要用partial:

class Solution(object):
    def f(self, x: int, y: int) -> int:
        x = x ^ y
timeit.timeit(partial(s.f, x, y))

2.5.调用linux系统命令

python调用linux命令方式有好几种,比如os.system和subprocess的一些函数等,这些实际上都是对c语言调用linux系统命令的包装而已,有时会遇到使用python调用linux命令和自己在shell中调用出现不一致的情况,下面举个例子来说明可能有哪些区别。

 		事情的起因是这样的,近日接到一个需求要将md转doc,于是用到了pandoc这个库,首先我本地安装了pandoc,使用体验不错,顺便学习了md的标准法。
 		本地使用pycharm,在python中使用pypandoc来进行文件转换,结果发现内存暴涨的问题,后面看了pypandoc代码,发现是使用subprocess.Popen调用linux下pandoc相应命令来运行,所以理论上应该和再shell中调用pandoc命令效果一致才对。
 		接下来查看进程详情才发现python使用的是/bin/sh,而我自己用的是/bin/bash,于是将/bin/sh的软链接改成了/bin/bash,但是问题仍未解决,最后抱着试一试的态度在命令行中运行了python脚本,结果发现竟然问题解决了。
 		后面本地将/bin/sh软链接恢复后发现问题解决,最终确定问题根源只有pycharm。
 		总结:虽然上面的例子中的问题根源不是由python调用linux命令引起,但是在定位问题的过程中能发现python调用linux命令是会指定某个shell来运行命令的,这可能会导致一些问题,需要我们额外注意。

2.6.hook

目的是为了预留功能,比如在一件事情做之前,可以选择做事情A(当然也可以不做),那么可以实现这个一个事情A,这就是一个hook,举例:

class Watermelon:
    def __init__(self):
        self.say_it_hook = None

    def register_say_it_hook(self, say_it_hook):
        self.say_it_hook = say_it_hook

    def say_it(self, content):
        if self.say_it_hook is not None:
            self.say_it_hook(content)
        print('so big')


watermelon = Watermelon()
watermelon.register_say_it_hook(lambda x: print(x))
watermelon.say_it('have fun')

3.常用场景

3.1 获取可迭代对象中满足条件的第一个元素

next((_ for _ in range(100) if _ %2 == 0), 1))

Similar Posts

上一篇 django-urls

Comments