记录goland-mod-无法使用后解决步奏

系统:mac软件:golandgo版本:1.13go环境变量: GO111MODULE="auto"GOARCH="amd64"GOBIN="/Users/panbing/mypro/golang/bin"GOCACHE="/Users/panbing/Library/Caches/go-build"GOENV="/Users/panbing/Library/Application Support/go/env"GOEXE=""GOFLAGS=""GOHOSTARCH="amd64"GOHOSTOS="darwin"GONOPROXY=""GONOSUMDB=""GOOS="darwin"GOPATH="/Users/panbing/mypro/golang"GOPRIVATE=""GOPROXY="https://goproxy.cn,direct"GOROOT="/usr/local/go"GOSUMDB="sum.golang.org"GOTMPDIR=""GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"GCCGO="gccgo"AR="ar"CC="clang"CXX="clang++"CGO_ENABLED="1"GOMOD=""CGO_CFLAGS="-g -O2"CGO_CPPFLAGS=""CGO_CXXFLAGS="-g -O2"CGO_FFLAGS="-g -O2"CGO_LDFLAGS="-g -O2"PKG_CONFIG="pkg-config"GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/jn/dz3nwd1j1h92f_g6d96nx6hc0000gn/T/go-build274903134=/tmp/go-build -gno-record-gcc-switches -fno-common"情景描述:1.使用 goland 创建 go mod 项目 os3,项目导入后执行 go get,goland 的外部库(External library)会显示 go mod(os3)字样,此时时正常的。2.我的项目是多个文件在 main 包下,我打开其中一个查看,然后就会外部库全部变红,再看外部库,就没有 go mod(os3)字样了。 尝试修复:1.重新创建,不成功2.根据报错拉取,不成功3.更改 GO111MODULE 为 on,不成功4.Google 搜索 goland 无法使用 go mod,不成功5.Google 搜索 goland go mod not working,成功 参考: 1.使用Go模块创建项目(vgo) 下的 创建依赖关系图 其中的引用图片中显示有 Sync Go Module(vgo)。2.我在我的项目中右击 go.mod 执行 Sync Go Module(vgo) 成功出现 go mod(os3) 字样,再次查看文件,引用包的红色错误消失。 总结:1.写文档是个好习惯:我本来是要在 segmentfault 提问的,实在自己找不到解决办法了,然后我边提问边总结边想还有什么办法没想到,最后找到了解决办法。2.有效分享是个好习惯:如果全凭我自己找,很难找到,幸亏有其他人的有效分享。3.原创很重要:我搜索到的很多文章都是重复的,有用的很少,希望大家也原创发布,提供不同的解决问题的思路和方法。 ...

November 4, 2019 · 1 min · jiezi

commonjs-ES-module-babel转码-webpack转码

js模块发展历程-javaScript模块七日谈前端模块化开发那点历史 #588现代ES模块也需要各种转码工具才可以在浏览器里正常运行,下面是转码现代ES模块需要了解到的知识点 commonjs & ES module & babel转码 & webpack转码 CommonJS简述CommonJS 模块输出的是一个值的 拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值了如果输出的是对象,改变其属性的话,外部引用的地方是会发生变化的如果直接改变输出的引用,那外界引用的地方是不会变化的(取缓存里面的结果)CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成commonjs 一个模块就是一个文件,require 命令第一次执行加载该脚本就会执行整个脚本,然后在内存中生成一个对象{ id: '...', // 模块名 exports: {}, // 真实的模块 loaded: true // 是否加载完毕}以后再次 require 该模块时,就会去缓存里取该对象的 exports 的属性无论 require 多少次,模块都只会运行一次,后续加载都是从缓存里面取module.exports 与 exports 的关系commonjs 规范仅仅定义了 exportsmodule.exports 是 nodejs 对 commonjs 规范的实现我们把这种实现称为 commonjs2https://github.com/webpack/webpack/issues/1114#issuecomment-105509929exports 只是在初始化对 module.exports 的引用初始化指向同一片内存空间模块导出的是 module.exports 如果对 module.exports 重新赋值,exports 上,挂的方法/属性将会失效require 引入的是 module.exports 导出的东西为避免混乱/错误,一般导出模块只建议用 module.exports 一般第三方包都用这种方式导出 modules.exports = exports = {}循环引用问题 (某个模块出现循环加载,就只输出已经执行的部分,还未执行的部分不会输出)// 代码如下// a.jsexports.A = '我是a模块';var b = require('./b.js');console.log('在 a.js 之中, 输出的 b模块==> ', b.B);exports.A = '我是后期修改过的a模块';console.log('a.js 执行完毕');// b.jsexports.B = '我是b模块';var a = require('./a.js');console.log('在 b.js 之中,输出a模块 ==>', a.A);exports.B = '我是修改后的b模块';console.log('b.js 执行完毕');// main.jsvar a = require('./a.js');var b = require('./b.js');console.log('在 main.js 之中,输出的 a模块=%j, b模块=%j', a.A, b.B);// 输出结果如下:➜ webpack-plugin git:(master) ✗ node src/babel/index 在 b.js 之中,输出a模块 ==> 我是a模块b.js 执行完毕在 a.js 之中, 输出的 b模块==> 我是修改后的b模块a.js 执行完毕在 main.js 之中,输出的 a模块="我是后期修改过的a模块", b模块="我是修改后的b模块"// 执行过程如下:执行 a.js 遇到 require b.js,暂停 a.js 执行,去执行 b.jsb.js 执行到第二行,遇到 require a.js ,从缓存中拿出刚刚 a.js 导出的模块,在 b.js 里面使用继续执行 b.js 后面的代码待 b.js 执行完毕后,控制权交还 a.js,继续执行拿到 b.js 导出的模块,在 a.js 继续使用 ... 直到结束 循环引用注意点:由于 commonjs 模块遇到循环加载时,返回的是当前已经执行的部分的值,而不是全部代码之后的值,两者可能会有差异,所以输入变量的时候必须非常小心,使用 var a = require('a') 而不是 var a = require('a').fooES6 Module基本使用export default A // 用户不需要知道导出模块的变量名import a from 'a.js'// 可以导出多个export var a = 1 // 这种方式可以直接导出一个表达式或var a = 1export {a} // 必须用花括号包起来import {a} from 'a.js'// as 关键字重命名模块export { a as A }// 导入导出合并export { default as Comps } from '../xxx'相当于import Comps from './xx'export { Comps }// 执行 loadsh 模块,但并不输出任何值import 'lodash';// 整体加载所有模块,访问时用 circle.xxx 访问import * as circle from './circle';简述: ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入,它的接口只是一种静态定义,在代码静态解析阶段就会生成。// ES6模块import { stat, exists, readFile } from 'fs';上面代码的实质是从fs模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。由于 ES6 模块是编译时加载,使得静态分析成为可能import命令具有提升效果,会提升到整个模块的头部,首先执行import命令是编译阶段执行的,在代码运行之前。由于 import 是静态执行,所以不能使用表达式和变量(这类只有在运行时才能得到结果的语法结构)静态加载模块的好处:1. 不再需要UMD模块2. 浏览器API可以用模块格式提供,不必再做成全局变量,不再需要全局对象如:Math (可以像Python一样用模块导入)动态 import动态import() 是非常有用的。而静态型的 import 是初始化加载依赖项的最优选择,使用静态 import 更容易从代码静态分析工具和 tree shaking 中受益import(模块路径) 返回 promise,从 then 的结果里拿到加载的模块webpack 2.x 之后,有一个魔力注释的功能,会把加载的模块重命名为你注释里的文字ES6模块的浏览器加载传统方法加载js脚本script type="application/javascript"异步加载: async defer脚本异步加载,不会阻塞dom结构的解析async:加载完立即执行,渲染引擎中断,待之脚本执行完继续渲染defer:加载完会等待页面渲染完毕及页面其他脚本执行完毕才会执行多个 async 执行没有顺序保证,多个 defer 有顺序保证 es6 模块加载script type="module"浏览器对 type="module" 的处理和 defer 标志一致es6 模块的循环加载ES6 处理“循环加载”与 CommonJS 有本质的不同。ES6 模块是动态引用,如果使用import从一个模块加载变量(即import foo from 'foo'),那些变量不会被缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。es6 模块会在使用使用时才去加载对应的模块如果是循环应用,可以将对应的输出改写成函数形式,利用函数的变量提升功能CommonJS 与 ES Module 的对比// 此处是对比CommonJS 模块时运行时加载 -- 值得拷贝ES6模块时 编译时 输出接口 -- 值得引用commonjs 模块只会加载一次,以后在 碰到 require 同样的东西就从缓存里面加载如果把原模块导出的东西改变,引入模块不会跟着改变,还是从缓存里面取原来的值ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6的输入有点像Unix系统的“符号连接”,原始值变了,import输入的值也会跟着变。ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。commonjs: module.exports = {} exports 运行阶段才加载模块,可以使用逻辑语句 模块就是对象加载的就是该对象 加载的是整个模块即将所有的接口都加载进来 输出的是值得拷贝,原模块发生变化不会影响已经加载的 this 指向当前的模块es6 模块 export 可以输出多个 {} export default 解析阶段确定对外的接口,解析阶段输出接口,不可以使用逻辑语句 加载的模块不是对象 可以单独加载其中的几个模块 静态分析,动态引用输出的是值得引用,原模块变化会影响已加载的模块 this 指向 underfinedBabel 转换 ES6 的模块化语法Babel 对 ES6 模块转码就是转换成 CommonJS 规范模块输出语法转换Babel 对于模块输出的转换,就是把所有输出都赋值到 exports 对象的属性上,并加上 ESModule: true 的标识表示这个模块是由 ESModule 转换来的 CommonJS 输出对于解构赋值输入import {a} from './a.js'转义为var _c = require('./a.js')然后取 _c.a 对于 defaultimport a from './a'import {default as a} from './a'babel转义时的处理,引入了一个 函数function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : {'default': obj}}var _a = _interopRequireDefault(require("./a.js"));console.log(_a["default"]);// 意思就是如果不是 esmodule 就为其手动添加个 default 属性,取值时统一取 default有个疑问:babel 为什么 会把 export export.default 导出的模块转换为 exports.xxx 和 exports.default 呢?而不是 module.exports ???我没有找到解释,如果您知道,麻烦给我留言下webpack 对 es6 模块和commonjs 的处理webpack本身维护了一套模块系统,这套系统兼容所有历史进程下的前端规范写一个简单的webpack配置module.exports = { entry: "./index.js", output: { path: path.resolve(__dirname, "dist"), filename: "[name].[contenthash:8].js" }, mode: "development"};执行打包命令 webpack --config webpack.config.js --env=dev 输出 main.[hash].js// 打包后代码简化如下// 首先是一个 webpack 模块运行时代码(function(modules) { // webpackBootstrap // 缓存模块 var installedModules = {}; // 函数 __webpack_require__ 参数 模块 id,用于加载和缓存模块 function __webpack_require__(moduleId) { // Check if module is in cache if(installedModules[moduleId]) { return installedModules[moduleId].exports; } // Create a new module (and put it into the cache) var module = installedModules[moduleId] = { i: moduleId, l: false, exports: {} }; // Execute the module function modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // Flag the module as loaded module.l = true; // Return the exports of the module return module.exports; } /*** 所有加载的模块都存在于 installedModules 内,其结构为: id: { id, loaded: Boolean // 是否加载过 exports // 模块的导出 } */ // 省略... 定义各种工具函数和变量 // Load entry module and return exports // 加载 entry 模块,并返回其导出,我们写的模块才会被真正执行 return __webpack_require__(__webpack_require__.s = "./index.js");})({ "./index.js": (function(module, __webpack_exports__, __webpack_require__) { // ... }, "./src/a.js": (function(module, __webpack_exports__, __webpack_require__) { // ... }, // ...})这个自调用的函数的参数 modules,就是包含所有待加载模块的一个对象{ [id: string]: Function}异步加载: import ==> webpack.requireEnsure ==> webpackJsonphttps://www.njleonzhang.com/2018/12/30/webpack-bundle-1.html其他常见问题1. babel 与 webpack 的关系webpack:将 ES6、CommonJS、amd、cmd 等模块化通过自己内部的机制统一成 webpack 的模块化。babel:转码 es6 语法,配合一些列 babel 工具链可以将新的 es2015+ 代码转换成所有浏览器支持的 es代码,babel 也可以将 es6 模块转换成 commonjs 模块2. es module 与 commonjs 为何可以混用因为 babel 会把 es module 转换成 commonjs 规范的代码babel 转码 es module 时如果遇到 export default 这种导出模块的书写方式后,会将其转换成 exports.default ,这时如果用 require 引入时,需要对其加上 .default 如 require('./a.js').a 这样才能获取 a 模块 export default 导出的 aimport 动态加载的模块也需要 .default 才能获取真实模块导出的值,如 import('./a.js').then(res => res.dafault)3. antd、element-ui 等ui框架的按需加载组件的实现需要 babel-plugin-component ...

August 18, 2019 · 4 min · jiezi

go-使用-gomod-管理项目依赖

go 1.11.1开始可以使用更优雅灵活的module机制做包依赖管理,能直接感受到的优点如下: 项目路径可以脱离$GOPATH了,不需要必须放在$GOPATH/src下。项目内部模块的引入是基于moduleName而不再死板的基于projectName了。半自动维护依赖,如果你很懒,你甚至可以不需要使用get预先安装依赖,module在run test build时会检测未下载的依赖,并自动下载它们。回想以前吧!$GOPATH/src/projectName后,项目中各模块互相引用的话都是基于projectName(go 的包加载机制导致的,去 $GOROOT/src 和 $GOPATH/src 去寻址,所以projectName也需要作为包引入路径的一部分),别人使用你的项目时也必须是projectName,否则就得把项目内的所有projectName改为他们的项目名,不优雅极了。 而module模式下,项目的包域是moduleName,和projectName无关,项目名称怎样都好,moduleName会注册到加载路径中去。 虽然module可以灵活到消除项目名作为项目模块引入路径的槽点,但如果后面要转为普通的vendor模式的话,我们还是建议moduleName同projetName保持一致。init初始化项目为module模式:go mod init moduleName # 不需要必须在 $GOPATH/src 下mkdir go_mod_proj && cd go_mod_projgo mod init app# go: creating new go.mod: module app# 会生成一个 go.mod 文件 查看内容如下vi go.modmodule appgo 1.12# module app 即定义了当前项目的包域# 往常我们要引入 go_mod_proj 下的 test 包需要# import "go_mod_proj/test"# module 模式下则是 优雅的很 像 PHP 的命名空间映射一样灵活# import "app/test"示例 tree ..├── go.mod├── main.go└── utils └── msg.go# go.modmodule appgo 1.12# utils/msg.gopackage utilsfunc Hello() { println("hello go")}# main.gopackage mainimport ( "app/utils" // 注意项目模块包的引入是以 moduleName 作为包域的)func main() { utils.Hello()}# go run main.go自动维护我们日常开发时需要某依赖包的话,都会使用 go get下载后再运行,module模式下因为会自动的解析项目依赖,会自动的去下载那些未在本地的依赖包,删除那些不再需要的依赖包。 ...

July 10, 2019 · 1 min · jiezi

golang内置包管理工具go-mod简明教程

go modgo buildin package manager. go mod是go语言内置的包管理工具,集成在go tool中,安装好go就可以使用。 要求: go version >= 1.11 官方文档: https://tip.golang.org/cmd/go... 环境变量# 通过环境变量GOPROXY设置代理export GOPROXY=https://goproxy.io# go mod功能开关,默认是auto,在gopath中不启用# 可设置为on强制启用export GO111MODULE=on初始化 go mod initinit报错outside gopath no import comments # 方法一 手动创建go.mod文件, 写入module xxxecho 'module xxx' > go.mod# 方法二 main包加入import声明package main // import "xxx"go mod download下载依赖 go mod tidy同步依赖包,添加需要的,移除多余的 go mod vendor将依赖包放入vendor go get 下载/升级依赖go mod不再下载源码进$GOPATH/src go mod的下载目录在$GOPATH/pkg/mod,并且是文件权限是只读的-r--r--r-- # tag必须以v开头 v1.2.3格式go get -u xxx.com/pkg@2.1.0vendor 模式go mod是不推荐使用vendor目录的,而是直接使用source或cache中的包。 ...

May 28, 2019 · 1 min · jiezi

python模块之getopt脚本参数解析

getopt模块用于解析脚本参数。 getopt.getopt(args, shortopts, longopts=[])解析命令行选项及参数列表。 args:要解析的参数列表,但不包括当前执行的python脚本名称,一般等同于sys.argv[1:]。 shortopts:要识别的短选项字符串,如果后接:表示需要给定参数。如ab:c:,表示识别-a, -b和-c的短选项,其中-b和-c需要后接参数。如果不需要短选项,可以设置为空字符串。 longopts:要识别的长选项列表(不包括--前缀),长选项如果后接=表示需要给定参数,不支持可选参数。如["help", "user=", "password="],表示识别--help, --user=root, --password=123456的长选项。 函数返回值由两个元素组成。第一个是(option, value)元组的列表,第二个是args剥离短选项及其参数和长选项及其参数之后剩余的参数列表。(option, value)元组中的option表示包含-或--前缀的选项,value表示该option对应的参数,可以为空字符串表示无参数。 import getopt# 模拟向MySQL的test库导入tb_country.sql的命令行args = "-uroot -p --host=127.0.0.1 --port=3306 --verbose -Dtest < tb_country.sql".split()options, arg = getopt.getopt(args, "u:pD:", ["host=", "port=", "verbose"])print(arg) # ['<', 'tb_country.sql']for option in options: print(option)# ('-u', 'root')# ('-p', '')# ('--host', '127.0.0.1')# ('--port', '3306')# ('--verbose', '')# ('-D', 'test')一旦遇到非选项参数,将停止选项解析,从该非选项参数开始的所有参数全部视为返回值中的第二个元素 import getoptargs = "-a root 123456 -b --opt1 --opt2".split()options, arg = getopt.getopt(args, "ab", ["opt1", "opt2"])print(arg) # ['root', '123456', '-b', '--opt1', '--opt2']print(options) # [('-a', '')]getopt.gnu_getopt(args, shortopts, longopts=[])和getopt()类似,但默认使用GNU风格的选项解析模式,这意味着选项参数和非选项参数可以混合,而getopt()会在遇到第一个非选项参数时停止解析。 ...

May 8, 2019 · 1 min · jiezi

go module使用本地包

go module的使用非常简单初始化go.modgo mod init整理依赖包go mod tidy 如果想缓存到vendor目录go mod vendor 执行命令之后都会自动把依赖搞定. 但是, 如果我们是本地开发的包, 还没有远程仓库的时候, 要怎么解决本地包依赖问题呢?使用replace将远程包替换为本地包服务幸运的是, go module 提供了另外一个方案, replace, 这个replace怎么使用的呢? 我们先看一下一个最基本的mod文件module GoRoomDemogo 1.12require ( github.com/gin-gonic/gin v1.3.0 github.com/gohouse/goroom v0.0.0-20190327052827-9ab674039336 github.com/golang/protobuf v1.3.1 // indirect github.com/gomodule/redigo v2.0.0+incompatible github.com/mattn/go-sqlite3 v1.10.0 github.com/stretchr/testify v1.3.0 // indirect golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 // indirect)这是一个简单的GoRoom框架的依赖关系包, 如果我想使用本地的goroom, 只需要使用replace即可module GoRoomDemogo 1.12require ( github.com/gin-gonic/gin v1.3.0 github.com/gohouse/goroom v0.0.0-20190327052827-9ab674039336 github.com/golang/protobuf v1.3.1 // indirect github.com/gomodule/redigo v2.0.0+incompatible github.com/mattn/go-sqlite3 v1.10.0 github.com/stretchr/testify v1.3.0 // indirect golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 // indirect)replace github.com/gohouse/goroom => /path/to/go/src/github.com/gohouse/goroom这里的 path/to/go/src/github.com/gohouse/goroom 是本地的包路径这样, 我们就可以愉快的使用本地目录了 ...

March 27, 2019 · 1 min · jiezi

python模块之functools

functools模块提供了某些高阶函数(high-order function)。functools.cmp_to_key(func)比较函数是接收两个参数进行比较的函数,返回一个负数表示<,返回0表示=,返回一个正数表示>。key函数接收一个参数并返回另一个值作为进行排序的键。将比较函数转换为key函数,常在用到key关键字的函数如sotred(), min(), heapq.nlargest(), itertools,groupby()中使用。cmp_to_key主要作为过渡工具将python2中支持的比较函数进行转换。def numeric_compare(x, y): return x - y# python2print(sorted([5, 2, 4, 1, 3], cmp=numeric_compare))# python3print(sorted([5, 2, 4, 1, 3], key=cmp_to_key(numeric_compare)))@functools.lru_cache(maxsize=128, typed=False)使用memoize包装函数,保存最近maxsize次的函数调用结果。在I/O-bound函数上装饰,处理相同参数时可以节省函数执行时间。如果maxsize为None,会禁用LRU缓存特性且缓存大小会无限增长。maxsize设置为2的n次方时性能最优。如果typed为True,不同类型函数参数的执行结果会被分别缓存,例如f(3)和f(3.0)会被视为有两个不同结果的不同调用。因为该装饰器使用字典缓存函数执行结果,所以函数的位置参数和关键字参数必须是可哈希的。不同的参数模式可能会被视为不同的缓存实体。例如f(a=1, b=2)和f(b=2, a=1)虽然只是关键字顺序不同但可能有两个单独的缓存实体。被包装的函数可以调用cache_info(),它返回一个(hits, misses, maxsize, currsize)形式的命名元组;可以调用cache_clear()清空或使缓存无效;还可以调用__wrapped__属性绕过缓存,访问原始的底层函数。LRU(least recently used)缓存通常应仅用在需要重用先前计算的值的场景,其他场景如使用LRU有不良影响、每次调用需要返回不同结果、time()、random()等应禁止使用。maxsize表示缓存大小限制,确保不会无限制增长。@lru_cache(maxsize=32)def get_pep(num): ‘Retrieve text of a Python Enhancement Proposal’ resource = ‘http://www.python.org/dev/peps/pep-%04d/' % num try: with urllib.request.urlopen(resource) as s: return s.read() except urllib.error.HTTPError: return ‘Not Found’>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:… pep = get_pep(n)… print(n, len(pep))>>> get_pep.cache_info()CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)@functools.total_ordering类装饰器,包装在定义了一个或多个富比较排序方法的类上,会补足其他的比较方法。该类必须定义__lt__(), le(), gt(), 或__ge__()中至少一个方法,并建议额外定义__eq__()方法。@total_orderingclass Student: def init(self, lastname, firstname): self.lastname = lastname self.firstname = firstname def _is_valid_operand(self, other): return (hasattr(other, “lastname”) and hasattr(other, “firstname”)) def eq(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lower(), other.firstname.lower())) def lt(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))NOTE:使用这个装饰器的代价是,装饰器自动补足的比较方法耗费了更多的执行时间并拥有更复杂的堆栈跟踪。如果应用性能基准测试表明是使用此装饰器造成的瓶颈,手动实现所有六种富比较方法可以带来直观的速度提升。functools.partial(func, args, *keywords)偏函数,返回一个partial对象,调用时等同调用了使用预设位置参数和关键字参数的func函数。如果partial对象调用时又提供了额外的位置参数,追加到args,如果提供了额外的关键字参数,扩展keywords并覆盖相同的键值。大致等同于:def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func(*args, *fargs, **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfuncpartial()用于“冻结”函数的部分位置参数和/或关键字参数而产生一个代表某部分函数功能的简化标志。>>> from functools import partial>>> basetwo = partial(int, base=2)>>> basetwo.doc = ‘Convert base 2 string to an int.’>>> basetwo(‘10010’)18class functools.partialmethod(func, args, *keywords)后续补充functools.reduce(function, iterable[, initializer])将可迭代对象iterable中的元素从左到右累计到接收两个参数的函数func中。例如reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])的计算等同于((((1+2)+3)+4)+5)。如果设置了可选参数initializer,它被放置在要计算的序列之前,并在序列为空时作为默认值;如果未提供initializer的值且序列仅包含一个元素,返回该元素。@functools.singledispatch将函数转换为单分派泛函数(single-dispatch generic function)。使用@singledispatch装饰器定义一个泛函数,单分派仅限于第一个参数的类型:from functools import singledispatch@singledispatchdef fun(arg, verbose=False): if verbose: print(“Let me just say,”, end=" “) print(arg)使用泛函数的register()属性添加重载实现,该属性是一个装饰器。对于使用类型注解的函数,该装饰器将自动推断第一个参数的类型:@fun.registerdef _(arg: int, verbose=False): if verbose: print(“Strength in numbers, eh?”, end=” “) print(arg)@fun.registerdef _(arg: list, verbose=False): if verbose: print(“Enumerate this:”) for i, elem in enumerate(arg): print(i, elem)如果不使用类型注解,可以显式地给装饰器传递类型参数:@fun.register(complex)def _(arg, verbose=False): if verbose: print(“Better than complicated.”, end=” “) print(arg.real, arg.imag)也可以以函数的形式使用register()注册lambda函数和已定义的函数:def nothing(arg, verbose=False): print(“Nothing.")fun.register(type(None), nothing)register()属性返回允许装饰器堆叠、序列化以及创建独立的单元测试的未装饰的函数:from decimal import Decimal@fun.register(float)@fun.register(Decimal)def fun_num(arg, verbose=False): if verbose: print(“Half of your number:”, end=” “) print(arg / 2)>>> fun_num is funFalse调用时,泛函数只分派第一个参数的类型:>>> fun(“Hello, world.")Hello, world.>>> fun(“test.”, verbose=True)Let me just say, test.>>> fun(42, verbose=True)Strength in numbers, eh? 42>>> fun([‘spam’, ‘spam’, ’eggs’, ‘spam’], verbose=True)Enumerate this:0 spam1 spam2 eggs3 spam>>> fun(None)Nothing.>>> fun(1.23)0.615如果某个类型没有相应的实现,将查找更通用的实现进行解析。使用@singledispatch装饰的原始函数注册为object类型,将在没有更好实现的情况下使用。调用dispatch()属性查看泛函数使用了哪个实现:>>> fun.dispatch(float)<function fun_num at 0x1035a2840>>>> fun.dispatch(dict) # note: default implementation<function fun at 0x103fe0000>调用registry属性查看注册的所有实现:>>> fun.registry.keys()dict_keys([<class ‘NoneType’>, <class ‘int’>, <class ‘object’>, <class ‘decimal.Decimal’>, <class ’list’>, <class ‘float’>])>>> fun.registry[float]<function fun_num at 0x1035a2840>>>> fun.registry[object]<function fun at 0x103fe0000>functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)更新包装函数(wrapper),使其看起来更像被包装的原始函数(wrapped)。元组类型的可选参数assigned指定wrapped函数的哪些属性直接分派到wrapper函数对应的属性上,updated参数指定使用wrapped函数的哪些属性更新wrapper函数对应的属性上。WRAPPER_ASSIGNMENTS的默认值是’module’, ‘name’, ‘qualname’, ‘doc’,’annotations‘WRAPPER_UPDATES的默认值是’dict‘通过访问包装函数的__wrapped__属性可以获取到被包装的原始函数。该函数主要用于装饰器使用场景下,如果不更新包装函数,返回函数的元数据将指向包装函数而非被包装的原始函数,一般来说没太大意义。def wrapper(f): def wrapper_function(*args, **kwargs): “““this is a wrapper function””” return f(*args, **kwargs) # update_wrapper(wrapper_function, f) return wrapper_function@wrapperdef wrapped(): “““this is a wrapped function””” passprint(wrapped.doc)print(wrapped.name)# 不使用update_wrapper的结果:>>> this is a wrapper function>>> wrapper_function# 使用update_wrapper的结果:>>> this is a wrapped function>>> wrapped@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)等同于partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated),不过是作为包装函数定义时的装饰器使用。def wrapper(f): @wraps(f) def wrapper_function(*args, **kwargs): “““this is a wrapper function””” return f(*args, **kwargs) return wrapper_function@wrapperdef wrapped(): “““this is a wrapped function””” passprint(wrapped.doc)print(wrapped.name)partial对象partial对象是由partial()方法创建的可调用对象,它有三个只读属性:partial.func一个可调用对象或函数。调用partial对象将使用新的位置参数和关键字参数转发到func。partial.args调用partial()时提供的位置参数partial.keywords调用partial()时提供的关键字参数 ...

January 15, 2019 · 2 min · jiezi

python练习时出现module 're' has no attribute 'match'错误

练习python中正则表达式,使用import re,并且写了最简单的匹配,运行py文件,却提示module ’re’ has no attribute ‘match’错误。仔细查看原因,原来是自己把python package写成了re了。导致python在执行import re时,以为我们要他导入我自己定义的package呢,将包名字改成retest,重新运行py文件,成功运行。

April 6, 2018 · 1 min · jiezi