Python 包/pcakge排名 : pypi.org
那个搜索不知道结果是些啥玩意儿,最好在这里搜,前5000基本上都是主流的
安装方法 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 # for CentOSyum groupinstall -y 'development tools' yum install -y zlib-dev openssl-devel sqlite-devel bzip2-devel xz-libs libffi-devel # for Ubuntuapt-get install -y build-essential libssl-dev libffi-dev # for alpineapk add --update alpine-sdk # Linux下不区分64和32位 wget https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tar.xz xz -d Python-3.9.9.tar.xz tar -xvf Python-3.9.9.tar cd Python-3.9.9 # for Linux./configure && make && sudo make altinstall # altinstall能够不覆盖默认的python路径及可执行文件。但是注意通过altinstall安装的python在使用pip install后的包如果有可执行文件可能会覆盖默认的 # for Mac./configure --enable-framework --with-openssl=/usr/local/opt/openssl # 不加openssl可能会出现the SSL module is not available的错误 cd # 如果默认没有安装pip,那么可以这样安装 wget https://bootstrap.pypa.io/get-pip.py python3.5 get-pip.py # Python3.5版本默认有安装pip的,如果没有,那么就酱紫 wget https://bootstrap.pypa.io/get-pip.py python3.3 get-pip.py python3 -m venv/ path/to/venv # 创建virtualenv环境
基本语法
3.8开始支持海象运算符,又能少写一行代码了
1 2 if (n := len (a)) > 10 : print (n)
列表 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 30 all ([]) any ([]) li[10 :] li[::-1 ] li[::2 ] li[1 ::2 ] del (list ['下标' ]) li.index(min (li)) li.index(obj) li.remove(obj) while false: sdaghoahg else : aosdhgo for x in reversed (list ) for index, value in enumerate (list ) list (set (list )) li.insert(position, item) li.append([1 ,2 ]) li.extend([1 ,2 ]) li_1 + li_2 A.T @ A [x*x for x in range (10 )] (x*x for x in range (10 ))
元组tuple 1 2 3 a = ('1' , ) b = '2' a + (b,)
字符串
字典
字典也能用生成式,例如{a.id: a.value for a in list}
使用del删除字典的元素后,内存并不会释放,可能会有内存泄漏的问题
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 for key in dict : print (key, dict [key]) for key in dict .keys(): del dict [key] for key, vlaue in dict .items(): print (key, value) li = { 'a' : 'b' , None : 'c' , '' : '' } if 'a' in dict if dict .get('a' , {}).get('b' , {}).get('c' ) dict .get('a' , 'b' ) dict ['abc' ] = 'xxx' dict .keys() dict .values() list (dict ) list (dict .values()) a = {'x' : 1 , 'y' : 2 } globals ().update(a)print (x, y)print (json.dump(sdata, indent=2 ))from collections import OrderedDictd = OrderedDict() for k, v in d.items(): 通过某个关键字来排序 rows = [{}, {}] from operator import itemgetterresult = sorted (rows, key=itemgetter('onekey' )) 通过某个值排序,使用zip ()函数,它会先将键和值翻转过来,需要注意的是zip ()函数是一个只能访问一次的迭代器 prices = {'A' : 1 , 'B' : 2 , 'C' : 3 } min_price = min (zip (prices.values(), prices.keys())) prices_sorted = sorted (zip (prices.values(), prices.keys())) for a, b in zip (x, y) sorted (mydict.keys()) sorted (mydict.items(), key=lambda item:item[1 ]) from collections import ChainMapc = ChainMap(a, b) class ErrorMsg (dict ): """自定义错误类""" def __init__ (self, e: Exception, code: int ): dict .__init__(self, msg=str (e), code=code) class CustomError (Exception ): def __init__ (self, message, status ): super ().__init__(message, status) self.message = message self.status = status json.dumps(ErrorMsg(e, 200 )) filter (lambda person: person['name' ] == 'haofly' , people_list) [person for person in people_list if person['name' ] = name] d = {key: value for (key, value) in iterable} dict (dict1.items() + dict2.items())dict (dict1, **dict2)dict1.update(dict2) import randomdict_list = list (dict1.items()) random.shuffle(dict_list) dict2 = dict (dict_list)
集合 1 2 3 4 a = {'a' , 'b' } a.add('b' ) a.remove('b' ) a.clear()
类/函数
定义在__init__
外的属性相当于静态变量,所有对象公用,__init__
内部的才是对象私有的
在3以前,类有经典类和新式类(显示继承自object)的区分,区别就是前者是深度优先去搜索方法,后者是广度优先去搜索方法,3以后都是新式类了
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 x.__class__.__name__ super ().__init__() super (self.__class__, self).__init__() ChildClass.mro() super ().func() super (ChildClass, self).func() getattr (foo, 'bar' )() hasattr (foo, 'bar' ) g = lambda x: x*2 g(3 ) from collections import namedtupleUserResponse = namedtuple('UserResponse' , [ 'uid' , 'name' ]) @staticmethod def get (): pass def get (cls ): pass dict = {'a' : 1 , 'b' : 2 , 'c' : 3 }func(**t) func(*t) func(*l) @attr.s class Product (object ): id = attr.ib() name = attr.ib() comment = attr.ib(repr =False , cmp=False , hash =False ) price = attr.ib(validator=[attr.validators.instance_of(int ), check_func]) min_price = attr.ib(converter=int ) x = attr.ib(metadata={'a' : 'b' }) @id.validator def check (self, attribute, value ): raise ValueError(...) new Project(1 , 'name' )
元类 Python里面所有的类也都是一个对象,type是Python用来创建所有类的元类,元类是用来创建“类”这个对象的东西。通过在类中定义metaclass
(python2中是在函数内部定义__metaclass__
属性),可以指定该类使用哪个元类来创建,如果没有改属性,并且父类里面都没有,那么默认就用type这个元类来创建。很好的元类使用的例子就是Django ORM,这就是元类的作用,把内部很复杂的东西变成一个简单的API。
1 2 3 4 5 6 7 8 9 10 11 12 class ListMetaclass (type ): def __new__ (cls, name, bases, attrs ): print (cls) print (name) print (bases) print (attrs) attrs['add' ] = lambda self, value: self.append(value) return type .__new__(cls, name, bases, attrs) class MyList (list , metaclass=ListMetaclass): pass
类型检查相关(Type Hint) 从3.5开始,Python提供了类型检查功能,当然类型检查仅仅用于检查,并不会对程序的执行有任何的影响,但是配合IDE有代码提示过后,一切都变得方便了起来
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 30 31 32 33 type ('string' ) is str isinstance ('string' , str ) a:int =123 b: typing.Optional [int ] = None def func (a: int ) -> int def func (a: int =None ) def func (a: int =None ) -> typing.Optional [int ] def func (a: Union [int , str ] ) @enforce.runtime_validation def foo (text: str ) -> None :...name: str = 'haofly' people: People from typing import List , Tuple Result = Tuple [Tuple [int , int ], str ] def foo (strings: str , lines: List [str ], line_number: int ) -> Result: MY_TYPE = TypeVar('MY_TYPE' , str , int ) from abc import ABCMeta, abstractmethodclass IStream (metaclass=ABCMeta): @abstractmethod def read (self, abc ): pass
数字 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 import randomrandom.choice(list ) random.sample(list , n) random.shuffle(list ) random.randint(0 , 10 ) random.random() random.getrandbits(100 ) random.uniform(begin, end) math.ceil(10 /3 ) = 4 math.floor(10 /3 )= 3 round (1.23 , 1 ) format (x, '0.2f' ) abs (-123 ) 14 /3 = 4.666666666666667 14 //3 = 4 14 %3 = 2 range (2 ) // 生成[0 , 1 ]range (1 , 2 ) // 生成[1 ]range (0 , 6 , 2 ) // 生成(0 , 2 , 4 )xrange用法与range 一样,只是返回的不是一个生成好的列表,而是一个生成器,所以性能更好
其他类型 Enum枚举类型 1 2 3 4 5 6 7 8 9 Month = Enum('Month' , ('Jan' , 'Feb' , 'Mar' , 'Apr' )) class Weekday (Enum ): Sun = 0 Mon = 1 Weekday['Sun' ].value [e.value for e in Weekday] Weekday(1 ).name
NamedTuple类似结构体 1 2 3 4 5 6 7 8 from typing import NamedTupleclass Student (NamedTuple ): name: str address: str age: int = 13 haofly = Student(name='haofly' , address='abc' , age=12 ) isinstance (haofly, tuple ) haofly[0 ]
MappingProxyType只读字典 1 2 from types import MappingProxyTypedata = MappingProxyType({'a' : 1 })
SimpleNamespace简单的“基类” 类似于其他语言的基类,仅仅提供属性的快速访问与设置
1 2 3 from types import SimpleNamespacedata = SimpleNamespace(a=1 ) data.b = 2
文件目录 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 os.mkdir os.makedires('a/b' ) pathlib.Path('src/' ).mkdir(parents=True , exist_ok=True ) os.path.join(path, filename) os.path.abspath(__file__) pathlib.Path(__file__) pathlib.Path(__file__).resolve().parent.parent pathlib.Path(__file__).resolve().parent.joinpath('abc' ) os.path.expanduser('~' ) pathlib.Path.home() os.path.basedir('/a/b' ) os.remove(filename) os.rmdir(dirname) os.walk(dirname) import shutilshutil.rmtree('mydir' ) shutil.copy(originame, tmpname) shutil.copytree(root_of_tree, desetination_dir, True ) os.listdir('dirname' ) os.path.isabs(filename) os.path.isdir(filename) os.path.isfile(filename) os.path.islink os.path.getsize(filename) os.path.getatime(filename) os.path.getctime(filename) os.path.getmtime(filename) os.path.basename(fname) os.path.dirname(fname) os.getcwd() os.chdir(newdir) os.path.exists(name) os.rename(original_name, new_name) pathlib.Path('.original_name' ).rename('newname' ) fp = open ('a.txt' , 'w' , 1 ) fp.close() 或者 with open ('a.txt' , 'w' ) as fp: print ('it' s...', file=fp) # 或者 import codecs fp = codecs.open(filename, ' w', ' utf-8 ') # 这种方式可以解决很多编码问题 fp.write(string) fp.close() # 文件操作的标识 w: 只读 r: 只写 r+: 可用于读写,但是如果打开不读,直接就写,可能会覆盖,因为一打开的时候文件指针是在文件开头的 # 验证文件或者文件夹的可读可写 os.access(path, os.W_OK) os.access(path, os.R_OK) # 读取文件 fp.readline() # 从文件读取一行数据 for each_line in fp: # 可迭代获取每一行数据 print(each_line) fp.read() # 读取所有数据 fp.readlines() # 读取所有的行,返回一个列表,需要注意的是这个只会读取一次,读取第二次的时候就会返回空了 codecs.open(path, ' r', ' utf-8 ').read().splitlines() # 获取所有的数据,并使用splitlines()分隔行,这样在每行的后面就不会出现换行符了 print(' string', file=fp) # 直接写入文件 # 写入文件 ## 使用fileinput实现只修改文件中某一行的功能 fp.write() fp.writelines() # 并不会自动换行 # 清空文件内容 fp.seek(0, 0) # 这一句可以保证之前是否读取,都能清空 fp.truncate() # 清空语句 # 文件压缩zipfile库,这个库是纯Python写的,不是用C,解压速度比较慢,而且不支持压缩的时候加密,如果要想在压缩的时候加密,可以使用网上现成的一个库https://github.com/smihica/pyminizip,依赖于zlib库,但是如果要依赖zlib库为什么不直接用python调用zlib库的代码呢 # 计算文件的md5值 import hashlib hashlib.md5(open(' filename.exe', ' rb').read()).hexdigest() # 递归便利文件路径,例如 glob.globa(' /path/**/*.avi', recursive=True) # 可以找到path目录下的所有avi文件
异常处理 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 30 import tracebacktry : raise RuntimeError('错误原因' ) except (SystemErrork, SyncError) as e: traceback.print_exc() print (traceback.format_exc()) raise RuntimeError('' ) except Exception as e: print (e)或者print (str (e))或者print (unicode(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1 ] print (exc_type, fname, exc_tb.tb_lineno) else : pass finally : pass except (OneExcetion, SecondException) as e: pass class BadRequestException (BaseException ): def __init__ (self, message, status=400 ): super ().__init__(message, status) self.message = message def __str__ (self ): return self.message
系统相关 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import subprocessresult = subprocess.check_output(command, shell=True , encoding='utf-8' ) subprocess.check_output(command, shell=True , stdin=subprocess.PIPE) try : subprocess.check_output(command, shell=True , stderr=subprocess.PIPE) output = subprocess.run(command, shell=True , check=True , stderr=subprocess.PIPE, stdout=subprocess.PIPE) print (output.stderr, output.stdout) except subprocess.CalledProcessError as e: print ('exit code: {}' .format (e.returncode)) print ('stdout: {}' .format (e.output.decode(sys.getfilesystemencoding()))) print ('stderr: {}' .format (e.stderr.decode(sys.getfilesystemencoding()))) result = subprocess.check_call(command, shell=True ) result = subprocess.call(command, shell=True ) child = subprocess.Popen(['xargs' , 'ls' ], stdin=subprocess.PIPE, child.poll() child.wait() child.send_signal(signal) child.terminate() child.kill() child.pid child.returncode stdoutdata, stderrdata = child.communicate(input =None ) a = input ('Input: ' ) sys.getsizeof(name) sys.argv id (x) platform.system() platform.release() sys.version os.dup2(fp1, fp2) os.environ['name' ] os.environ['name' ] = value os.geteuid() == 0 os.setsid() os.umask(0 )
网络相关 socket网络编程客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1 ) s.connect(('haofly.net' , 80 )) s.send(b'GET / HTTP/1.1\r\nHost: haofly.net\r\nConnection: close\r\n\r\n' ) buffer = [] while True : d = s.recv(1024 ) if d: buffer.append(d) else : break data = b'' .join(buffer) s.close() header, html = data.split(b'\r\n\r\n' , 1 ) socket.gethostbyname('haofly.net' ) socket.connect_ex((host, port)) == 0
socket网络编程服务器端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1' , 9999 )) s.listen(5 ) while True : sock, addr = s.accept() t = threading.Thread(target=tcplink, args=(sock, addr)) t.start() def tcplink (sock, addr ): sock.send(b'Welcome!' ) while True : data = sock.recv(1024 ) time.sleep(1 ) if not data or data.decode('utf-8' ) == 'exit' : break sock.send(('Hello, %s!' % data.decode('utf-8' )).encode('utf-8' )) sock.close()
包 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 30 31 32 33 34 35 36 37 38 39 40 41 # 在模块级别暴露接口 在目录下面加上__init__.py就变成了一个包,import包内部的模块使用'.'来分割,__init__.py里面可以定义一些全局变量,__all__指定了此包被import *的时候,哪些模块会被import进来。最好在创建一个包的时候都加上这个,避免有些模块被外部引用。如果没有定义__init__,那么import *的时候会将非下划线开头的成员都导入到当前命名空间中。 使用这种方式,在外部引入模块内部的模块会更加方便,而且比较不容易出错。特别是在交叉引用的时候,有时候会无法引用,但是如果直接在内部模块之间引入父模块就不会有这种错误,避免在文件开头交叉引用的时候无法找到模块。另外__init__.py是给包外部文件import的,内部文件之间引用不用从__init__.py中import # 单下划线和双下划线 __foo__: 一种约定,表示内部的名字,用来和其他用户自定义的变量名区分 _foo: 私有变量或者临时变量,不能用from import进行导入 # 带点号,表示当前目录下的模块,如 from . import client # 可以在一个模块的根目录下得__init__.py定义一些基本的东西,比如加载一些模块呀,设置一些全局变量(__author__这样的东西)啥的 package.__version__ #获取package的版本 # 从github直接安装包的方法http://stackoverflow.com/questions/8247605/configuring-so-that-pip-install-can-work-from-github?answertab=active # 需要注意的是github上的库要有个固定的目录格式,还要有个setup.py文件,才能直接使用如下的命令, pip install git+git@github.com:lynzt/python_people_names.git # 将python包打包成debian包,可以用https://github.com/spotify/dh-virtualenv # 从指定目录引入包,正如PyCharm里面经常不会出现import的问题,是因为它会首先将当前的项目路径添加到环境变量里面去,在终端执行的时候需要添加下面的代码,或者直接执行` export PYTHONPATH=$PYTHONPATH :/path/to/project` import sys sys.path.append('..') # 动态导入模块 __import__(module_name) # 相当于import __import__(name = module_name, fromlist=[a, b]) # 相当于from module_name import a, b # module = __import__('module_name', ['*']) for k in dir(module): locals()[k] = getattr(module, k) # 编码注释风格 # !/usr/bin/python # -*- coding: <encoding name> -*- # 直接用代码形式安装包 from pip import operations, main # pip version < 10 from pip._internal import operations, main # pip version >= 10 operations.freeze.freeze() # 返回所有安装的包 main(['install', 'requests']) # 安装包
名字空间 程序在使用一个名字时,会从当前名字空间开始搜索,顺序则是LEGB:
输入输出
Python默认会有输出缓冲区,所以有时候print
没有输出不用担心(systemd journal看不到print输出),可能是缓冲区没有刷新,可以在运行程序的命令加上-u
参数,例如python -u main.py
,或者直接添加一个环境变量PYTHONUNBUFFERED=1
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 print ('string' , file=sys.stderr) import sysfrom io import StringIOold_stdout = sys.stdout old_stderr = sys.stderr my_stdout = sys.stdout = StringIO() my_stderr = sys.stderr = StringIO() sys.stdout = self.old_stdout sys.stderr = self.old_stderr print (my_stdout.getvalue())print (my_stderr.getvalue())my_stdout.close() my_stderr.close() fp = open (...) sys.stdout = fp
魔术/自省方法 生命周期 1 2 3 4 5 6 7 8 9 10 __new__ __init__ __del__ def __new__ (cls, *args, **kwargs ): if cls._singleton is None : cls._singleton = object .__new__(cls) return cls._singleton
属性 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 30 31 32 33 34 35 36 37 38 39 40 41 __dir__ class AttrDict (dict ): def __getattr__ (self, item ): if item in self.my_dict: return self[item] raise AttributeError def __dir__ (self ): return super ().__dir__() + [str (k) for k in self.keys()] __getattr__(self, name) __setattr__(self, name, value) __delattr__(self, name) __getattribute__(self, name)
运算符 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
类型
序列化
特殊方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 __call__ class A (): def __call__ (self, key ): print (key) a = A() a('key' ) with class Count (): def __enter__ (self ): print (time()) def __exit__ (self ): print (time()) with Count(): func() class test : __slots__ = ['field1' , 'field2' ]
装饰器 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 def new_func (func ): def wrapper (*args, **kwargs ): print ('in wrapper' ) return func(*args, **kwargs) return wrapper @new_func def test (): pass class NewClass : def __init__ (self, func ): self._func = func def __call__ (self ): print ('调用' ) self._func() @NewClass def test (): pass @dataclass class A : a: float b: int = 1
property(描述符) 可将类的方法变为类的属性,比如之前用person.name()
,现在可以直接person.name
了。
1 2 3 4 5 class A : @property def value (self ): return 'ok' A().value
标准库 argparse(命令行程序) optparse
从2.7开始不推荐使用了
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import argparseparser = argparse.ArgumentParser(description='命令介绍' , usage='[options] (start|stop|status|restart|condrestart|version)' , epilog='help信息之后的信息' ) parser.add_argument('action' , choices=('start' , 'stop' , 'status' , 'restart' )) parser.add_argument('-d' , help ='添加一个参数 (default: 一半在括号里面设置用户看的默认值)' ) parser.add_argument('-v' , '--version' , help ='设置简写' ) parser.add_argument('-v' , '--version' , action='version' , version='1.0' ) parser.add_argument('-c' , metavar='FILENAME' ) parser.add_argument('--debug' , action='store_true' , help ='print debug messages to stderr' ) if len (sys.argv) == 1 : parser.print_help() sys.exit() args = parser.parse_args() args.d vars (args) import argparsedef task_a (alpha ): print ('task a' , alpha) def task_b (beta, gamma ): print ('task b' , beta, gamma) if __name__ == '__main__' : parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='subparser' ) parser_a = subparsers.add_parser('task_a' ) parser_a.add_argument('-a' , '--alpha' , dest='alpha' , help ='Alpha description' ) parser_b = subparsers.add_parser('task_b' ) parser_b.add_argument('-b' , '--beta' , dest='beta' , help ='Beta description' ) kwargs = vars (parser.parse_args()) globals ()[kwargs.pop('subparser' )](**kwargs)
ast抽象语法树 ast作用在python代码的语法被解析后,被编译成字节码之前,所以我用它来检测代码中是否有未安装的包,解析在docstring中定义的meta等,因为代码还未执行,所以并不会报错。
1 2 3 with open (file, 'r' ) as fp: syntax_tree = ast.parse(fp.read()) print (ast.get_docstring(syntax_truee))
ast还能代替eval
的功能执行安全的操作将字符串类型的对象转换为对应的对象。(eval
)会转换所有的操作,有很大的安全风险。
1 ast.literal_eval("{'field1' : 'value1', 'field2' : 'value2'}" )
atexit 可以定义整个程序结束之前需要执行的代码,相当于程序的析构函数,可以使用register函数注册程序退出时的回调函数。当然,如果程序crash
掉或者通过os._exit()
退出,该函数不会被执行。可以同时注册多个函数,到时候会按照逆序来执行。
1 2 import atexitatexit.register(my_func)
collections 参考 ,提供额外的数据类型
**namedtuple()**:生成可以使用名字来访问元素内容的tuple子类
deque :双端队列
Counter :计数器,可用于统计字符串中字符数量。找出序列中出现次数最多的元素
OrderedDict :有序字典
defaultdict :带有默认值的字典,这样访问不存在的dict就不会出错了
ConfigParser配置读取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cf = configparser.ConfigParser() cf.read('test.conf' ) cf.sections() cf.options('db' ) cf.items('db' ) cf.get('db' , 'host' ) cf.getboolean('db' , 'host' ) cf.getfloat('db' , 'host' ) cf.getint('db' , 'host' ) cf.has_option('section' , 'option' ) cf.has_section('section' ) cf.read_dict({'section1' : {}}) cf.add_section('section' ) cf.set ('section' , 'option' , 'value=None' ) fp.write(cf)
contextlib 加强with语句,with本身是配合__enter__
和__exit__
来进行上下文管理的,但是有了contextlib
,我们可以更方便写适合于with的代码,例如:
1 2 3 4 5 6 7 8 9 10 11 12 @contextlib.contextmanager def make_context (obj ): print ('__enber__' ) try : yield () except xxxError as e: print (e) finally : print ('__exit__' ) with make_context(myclass()) as func: func....
copy 深拷贝与浅拷贝 简单地说,python中对象的赋值都是进行对象引用(内存地址、指针)传递,浅拷贝复制了对象,变成了两个对象,但是对于对象中的元素,依然使用的原始的引用,深拷贝则是一个完全新的对象
1 2 3 4 5 6 7 8 9 copy.copy() copy.deepcopy() a = {'a' : {'b' : 1 }} b = a b = copy.copy(a) b = copy.deepcopy(a)
cProfile/Profile: 函数运行时间度量 1 2 3 4 import cProfilefrom time_profile import * cProfile.run("timeit_profile()" )
ctypes 提供C语言兼容的数据类型,可以方便调用DLL中的函数,例如win/mac平台的系统库。
Python3
里面跟C语言传参时需要encode('utf-8')
一下,以防出现<class 'TypeError'>: wrong type
错误
1 2 3 from ctypes import *dll = cdll.LoadLibrary('./libtest.so' ) print (dll.__dict )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import functoolsdef add (a, b ): return a + b plus3 = functools.partial(add, 3 ) plus3(4 )
heqpq 查找最大或最小的几个元素。
importlib
resources : 在静态文件所在的文件夹添加一个__init__.py
文件,那么这个文件夹就变成一个module
,就可以使用`importlib.resourcesd来直接导入静态文件,而不用像以前那样拼接参数了。
inspect 用于直接访问一个类或对象内部的各个属性
1 2 3 4 5 6 inspect.ismodule(object ) inspect.isclass(object ) inspect.getdoc(object ) inspect.getfile(object ) inspect.getsource(object ) inspect.getfullargspec(func).args
ipaddress IP地址处理模块
1 2 3 ip = ipaddress.ip_address('192.0.2.1' ) network = ipaddress.ip_network('192.0.2.1/24' , strict=False ) ip in network
参考
**count(start=0, step=1)**:创建连续整数
**cycle(iterable)**:创建一个迭代器,可以反复循环的,此时用在for里面如果不加终止条件会无限循环
**repeat(object, times)**:创建一个迭代器,根据指定数量,生成重复的对象
**chain(*iterables)**:将多个迭代器作为参数, 但只返回单个迭代器, 它产生所有参数迭代器的内容, 就好像他们是来自于一个单一的序列.
**compress(data, selectors)**:提供一个选择列表,对原始数据进行筛选
**dropwhile(predicate, iterable)**:创建一个迭代器,只要函数predicate(item)为True,就丢弃iterable中的项,如果predicate返回False,就会生成iterable中的项和所有后续项
**groupby(iterable, key)**:返回一个产生按照key进行分组后的值集合的迭代器.
**ifilter(predicate, iterable)**:与dropwhile相反
**ifilterfalce(predicate, iterable)**:与上面这个相反
**islice(iterable, stop)**:返回的迭代器是返回了输入迭代器根据索引来选取的项。可用于跳过一个循环前面几项的for循环。比如跳过前面3个项目: for x in islice(items, 3, None)
**imap(function, *iterables)**:返回一个迭代器, 它是调用了一个其值在输入迭代器上的函数, 返回结果. 它类似于内置函数 map() , 只是前者在任意输入迭代器结束后就停止(而不是插入None值来补全所有的输入).
**starmap(function, iterable)**:创建一个迭代器,生成值func(*item),其中item来自iterable,只有当iterable生成的项适用于这种调用函数的方式时,此函数才有效。
**tee(iterable[, n=2])**:从iterable创建n个独立的迭代器,创建的迭代器以n元组的形式返回,n的默认值为2
**takewhile(predicate, iterable)**:与takewhile相反
**izip(*iterables)**:返回一个合并了多个迭代器为一个元组的迭代器. 它类似于内置函数zip(), 只是它返回的是一个迭代器而不是一个列表
**izip_longest(*iterables[, fillvalue])**:与izip()相同,但是迭代过程会持续到所有输入迭代变量iter1,iter2等都耗尽为止,如果没有使用fillvalue关键字参数指定不同的值,则使用None来填充已经使用的迭代变量的值。
**product(*iterables[, repeat])**:笛卡尔积,排列组合
**permutations(iterable[, r])**:排列
**combinations(ierable, r)**:创建一个迭代器,返回iterable中所有长度为r的子序列,返回的子序列中的项按输入iterable中的顺序排序 (不带重复)
**combinations_with_replacement(iterable, r)**:创建一个迭代器,返回iterable中所有长度为r的子序列,返回的子序列中的项按输入iterable中的顺序排序 (带重复)
iterator迭代器 1 2 3 4 5 6 7 8 9 next (iterator) yield a yield from iterator def generator (): jump = yield a next (iterator) iterator.send(2 )
logging日志模块 日志格式
实例:
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 30 31 32 33 34 35 36 37 38 import logginglogger = logging.getLogger('AppName' ) formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s' ) file_handler = logging.FileHandler("test.log" ) console_handler = logging.StreamHandler(sys.stdout) file_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.removeHandler(file_handler) logger.setLevel(logging.INFO) logger.debug('this is debug info' ) logger.info('this is information' ) logger.warn('this is warning message' ) logger.error('this is error message' ) logger.fatal('this is fatal message, it is same as logger.critical' ) logger.critical('this is critical message' ) logger.error('%s service is down' , 'own' ) logging.basicConfig(filename='test.log' , level=logging.DEBUG) logger.info('test' , extra={'key' : value}) os.environ['TZ' ] = 'Asia/Chongqing' time.tzset() from pytz import timezone, utcdef customTime (*args ): utc_dt = utc.localize(datetime.utcnow()) my_tz = timezone("Asia/Chongqing" ) converted = utc_dt.astimezone(my_tz) return converted.timetuple() logging.Formatter.converter = customTime
http.server(SimpleHTTPServer) 最简单的web服务器,十分方便,最多的用途是用来进行局域网其他设备访问本机文件目录python -m SimpleHTTPServer 8000
即可,Python3
里面,模块更改为python3 -m http.server
另外,如果要想使SimpleHTTPServer
能增加CORS特性,可以创建一个这样的文件simple-cors-http-server.py
,之后直接用python执行即可,文件内容如下:
1 2 3 4 5 6 7 8 9 10 from SimpleHTTPServer import SimpleHTTPRequestHandlerimport BaseHTTPServerclass CORSRequestHandler (SimpleHTTPRequestHandler ): def end_headers (self): self.send_header('Access-Control-Allow-Origin' , '*' ) SimpleHTTPRequestHandler.end_headers(self) if __name__ == '__main__' : BaseHTTPServer.test(CORSRequestHandler, BaseHTTPServer.HTTPServer)
pickle: 序列化工具 将一个对象序列化为一个字节流,这样方便将对象保存在文件中。对于那种需要在不同地方执行,或者直接想以文件的方式保留执行过程变量,而不借助复杂的数据库的情况,是非常方便的。
需要注意的是pickle会将对象引用的所有的对象都进行序列化,所以体积往往会比getsizeof
大得多。如果想要渐小体积,可以直接用ba2.BZ2File(filename, 'w')
来写入文件,用bz2.open(filename)
来读取文件
pickle.dump
的第三个参数是协议版本,如果是同版本语言之间dump
和load
,那么完全可以用pickle.HIGHEST_PROTOCOL
目前是5,而默认值pickle.DEFAULT_PROTOCOL
默认是3,会根据语言版本不同而改变,最好就用最新的,在效率上肯定更好
1 2 3 4 5 6 7 8 import picklefp = open ('test' , 'wb' ) pickle.dump(data, fp) s = pickle.dumps(data) fp = open ('test' , 'rb' ) data = pickle.load(fp) data = pickle.load(s)
smtplib: 用于发送邮件 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 30 31 import smtplibfrom email.header import Headerfrom email.mime.text import MIMETextmail_host = '发件服务器' mail_user = '发件人' mail_pass = '收件人' sender = '发件人' receivers = ['收件人' ] message = MIMEText('这是邮件内容' , 'plain' , 'utf-8' ) message['From' ] = "\"%s\" <%s>" % (Header('发件人' , 'utf-8' ), Header('发件人' , 'utf-8' )) message['To' ] = Header('to' , 'utf-8' ) message['Subject' ] = Header('邮件主题' , 'utf-8' ) smtpObj = smtplib.SMTP() smtpObj.connect(mail_host) smtpObj.login(mail_user, mail_pass) smtpObj.sendmail(sender, receivers, message.as_string()) print ('邮件发送成功' )smtp = smtplib.SMTP(smtpHost, smtpPort) smtp.starttls() smtp.login(mail_user, mail_pass) smtp = smtplib.SMTP_SSL(smtpHost, smtpPort) smtp.login(mail_user, mail_pass)
sorted: 数组/字典排序 1 2 3 4 5 sorted ([5 ,4 ,3 ,2 ,1 ]) sorted ("This is a test string from Andrew" .split(), key=str .lower) student_tuples = [('john' , 'A' , 15 ),('jane' , 'B' , 12 ),('dave' , 'B' , 10 ),] sorted (student_tuples, key=lambda student: student[2 ]) sorted ([5 ,3 ], reverse=False )
sys
executable : 获取解释器的路径
meta_path : 这个功能就强大了,可以实现在import的时候触发相关操作,相当于import操作的一个hook。
timeit: 时间度量 1 2 3 import timeittimeit.Timer('x=range(1000)' ).timeit() timeit.Timer('sum(x)' , 'x = (i for i in range(1000)' ).timeit()
SocketServer :参考 两种服务模型:ThreadingMinxln(有新请求时,创建一个新的进程)、ForkingMinln(有新请求时,创建一个新的线程)
TCPServer
UDPServer
UnixStreamServer
UnixDatagramServer
weakref :弱引用,与常规的引用相对,这种引用在对象只剩下一个弱引用的时候,就可能会被回收,多见于类的嵌套定义防止错误回收,weakref的失效依赖于对象实际销毁。gc销毁的时机未知,引用计数的销毁则是可控的,比如(del),可以减少异常的发生。使用方式例如:
1 2 3 4 5 6 7 class Parent (object ): def __init__ (self ): self.children = [Child(self)] class Child (object ): def __init__ (self, parent ): self.parent = weakref.proxy(parent)
PIP版本管理/包管理 pip
可以使用==、>=、<=、>、<
几个符号来指定需要安装的依赖版本,并且可以同时使用多个,例如Django>1.0,<2.0
则安装的是她们之间的最接近的指定版本的版本,如果想要直接用最新的,那么不用符号,直接写名字就好了。常用命令:
1 2 3 4 pip install Django --upgrade # 更新指定package pip freeze --local | grep -v '^\-e' | cut -d = -f 1 | xargs pip install -U # 升级所有的包 pip install --pre sqlalchemy # 安装prelease版本 sudo pip3 install scrapy -i https://pypi.douban.com/simple # 使用豆瓣的PIP源,例如
pipenv 最新的包管理工具,使用pip install pipenv
直接安装。其配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [[source]] # 源地址 url = "https://pypi.python.org/simple" verify_ssl = true name = "pypi" [[source]] url = "https://pypi.douban.org/simple" verify_ssl = true name = "douban" [packages] # 运行锁依赖的包 sqlalchemy = "*" mysqlclient = "*" sanic-graphql = "*" graphene = "*" graphene-sqlalchemy = {version='*', index='douban'} # 指定需要的源 django = ">=2.0.0" # 指定版本 [dev-packages] # 开发所依赖的包 [requires] # 需要的python版本,把本模块删除表示不限制python版本 python_version = "3.7"
pipenv常用命令
1 2 3 4 pipenv --python 3.7 # 指定python版本 pipenv check # 检查已安装的包中是否有安全隐患 pipenv check --style test.py # 检查指定文件的编码风格 pipenv uninstall --all # 删除所有的安装包
语言本身 性能分析与优化
使用timeit
使用cProfile,精确到函数
使用vprof,可视化
line_profiler,精确到行
SQLite数据库 Python语言内置了SQLite
轻量级数据库。
1 2 3 4 5 6 7 8 9 10 11 import sqlite3conn = sqlite3.connect('test.db' ) cursor = conn.cursor() cursor.execute('正常的sql语句' ) cursor.execute('select * from user where id=?' , ('1' , )) cursor.fetchall() cursor.lastrowid cursor.rowcount cursor.close() conn.commit() conn.close()
TroubleShooting
ValueError: Attempted relative import in non-package
相对路径问题,所谓的相对路径其实是相对于当前module的路径,而不是当前目录的路径,如果当前目录不是module,那么当前module的name就是__main__
,所以会出错
Python中一切都是对象,a=1,b=1,两个是同一个对象,所以Python是无法通过变量名获取同名字符串的
在调试某些代码的时候发现print没有输出 : 这是有可能将print重定向了,这是用sys.stdout.write(‘’)可以实现打印输出到控制台
zsh: no matches found: requests[socks]
: 原因是zsh这个工具会把方括号解析为正则匹配,这时候只需要加上引号即可,例如pip install 'requests[socks]'
segmentation fault
,在使用keyboard
和pynput
的时候曾经遭遇过不可预料的原因,原因是这两个库都没有考虑中文输入法的问题,对于中文输入法,MacOS的Carbon库有另外兼容的做法(详见Pynput的issue)。最简单的解决方法就是切换到American
Python序列化出现maximum recursion depth
错误 。可以设置sys.setrecursionlimit(2000)
来解决,默认的递归深度是1000
__main__ is not a package
: 去掉import前面的点
**ImportError: cannot import name 'xxx'
**。请先检查是否存在交叉引用。
安装涉及到openssl lib的库的时候出现错误openssl/opensslv.h
或者openssl/err.h
not found等错误 ,首先要确定确实有安装该库。Mac下安装用brew install openssl
,然后如果还是不行就用这种方式进行安装pip install cryptography --global-option=build_ext --global-option="-L/usr/local/opt/openssl/lib" --global-option="-I/usr/local/opt/openssl/include"
no module named _sqlite3
,原因是系统多个python
版本导致 首先安装sqlite库,yum install sqlite-devel
,然后重新安装python
Python执行js : js2py
和execjs
都只能执行简单的js脚本,要复杂的,还是直接调用系统解析器吧,例如node -e
unknown file type, first eight bytes : 这是在加载动态链接库.so的时候发生,原因是该.so文件是在linux平台下编译的,而我实在macos上调用,所以发生该错误。解决方法是在macos重新编译生成.so文件,或者直接在linux下调用。
pip出现ImportError: No module named pkg_resources
错误 :安装工具 pip install setuptools
ImportError: cannot import name ‘sysconfig’ :
1 2 sudo apt-get install zlib1g-dev sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev
TypeError: must be type, not classobj : 在2里面,继承的时候,父类没有继承自object
pipenv
初始化的目录出错 : 请检查其上级或者上上级目录里是否有Pipenv
文件,如果有没必要的文件,删除即可
Unsupported operation :not writeable python : 一般是在写文件时候打开方式没有加’w’,而是直接open('file')
fatal error: Python.h No such file or directory : 需要安装python相关的开发库: yum install python-devel
gcc failed with exit status 1 : 原因是没有安装python开发相关扩展,需要先安装yum install python-devel
Libraries for snappy compression codec not found : 需要安装依赖库
1 2 3 4 5 sudo apt-get install libsnappy-dev # debian yum install snappy-devel # centos brew install snapy # macos pip install python-snappy # 成功
from Crypto.Cipher import AES报错No module named ‘Crypto’ : 卸载pycrypto
直接安装pycryptodome
**安装完fabric但是执行却报错: no module named fabric.api **可以尝试这样解决:
1 2 pip uninstall fabric pip install fabric3
mac安装pillow, no module named PIL :
1 2 3 xcode-select --install brew install libjpeg pip install Pillow
ModuleNotFoundError: No module named ‘pip._internal’ : 可以尝试用这种方法:
1 2 sudo pip install --upgrade pip pip3 install --user --upgrade pip # 或者
pip requires Rust>1.41 : 升级pip试试: pip3 install "pip>=20"
Click will abort further execution because Python 3 was configured to use ASCII as encoding for the environment.
: 错误原理见click ,设置一下系统的语言就好了:
1 2 3 # 先通过locale -a看当前系统有哪些语言,然后填入正确的语言即可, 例如 export LC_ALL=en_US.utf8 export ALL=en_US.utf8
psycopg2安装失败 : 可以尝试export ARCHFLAGS="-arch x86_64" pip install psycopg2 --global-option=build_ext --global-option="-L/usr/local/opt/openssl/lib" --global-option="-I/usr/local/opt/openssl/include
#error architecture not supported : 安装某些包的时候会出现这个,可以尝试ARCHFLAGS="-arch x86_64" pip install nltk
No such file or directory: ‘c++’: ‘c++’ : apt install build-essential
**no module named bz2: **sudo apt-get install libbz2-dev
或者sudo yum install bzip2-devel
no module named cv2 : pip install opencv-python
urllib3 v2.0 only supports OpenSSL 1.1.1+ : 尝试降级: pip uninstall urllib3 && pip install urllib3<2.0
推荐Package
推荐阅读 Hidden features of Python
PyMOTW-3 : 由 Doug Hellmann 所写的Python标准库的示例用法。
深刻理解Python中的元类(metaclass)
Python项目的配置管理
Python十大web框架 : 全栈框架(Django/Pyramid/TurboGears/Web2py)、微框架(Flask/Bottle/CherryPy/)、异步框架(Sanic/Tornado)
Unofficial Windows Binaries for Python Extension Packages 非官方的Python扩展windows平台二进制包 : 对于windows平台总是安装不成功的包可以尝试这样安装
pyexcel : Python处理Excel表格数据,如果只是读取,可以直接用pyexcel-xls
Python连接FTP/FTPS