教程
信息差
资源
软件工具
技术笔记
AIGC
视频
Search
1
使用AI实现高精度钢琴曲转谱Piano Transcription简明使用教程
37,794 阅读
2
使用ESP8266Wifi模块制作Wifi杀手
37,467 阅读
3
unravel 让图片唱歌详细教程 Real Time Image Animation 项目
27,386 阅读
4
佳能相机刷Magic Lantern魔灯固件
23,503 阅读
5
战地3 正版账号免费分享!
16,213 阅读
教程
信息差
资源
软件工具
技术笔记
AIGC
视频
Search
标签搜索
python
前端
环境搭建
空镜素材
Ubuntu
markdown
神器
黑苹果
编码
技巧
Git
数据库
开发
下载工具
Youtube
CDN
PDF
OST
电影原声带
音乐
易小灯塔
累计撰写
176
篇文章
累计收到
44
条评论
首页
栏目
教程
信息差
资源
软件工具
技术笔记
AIGC
视频
页面
搜索到
175
篇与
的结果
2017-08-07
JavaScript学习笔记
最近在复习之前学过的JavaScript,现在把笔记整理一下数据类型整数和浮点数不区分整形和浮点数,统一使用Number表示123 0.456 1.2345e3 -99 NaN Infinity 字符串使用单引号或者双引号括起来的文本,比如'abc',"abc"都是字符串 使用转义字符''可以帮我们使用一些功能字符,如下 'I'm "OK"!';//打印结果是I'm "OK"! ASCII表示:\x## Unicode表示:\u####多行字符串(下面这种写法只支持ES6标准)`多行 字符串 测试` 模板字符串 为了方便进行字符串的拼接var name = 'Jack'; var age = 20 var message = `hello, ${name},are you ${age} year old!`; alert(message); 获取字符串长度var s = 'hello'; s.length 布尔值true; false; 2 > 1;//true 2 >= 3 ;//false 比较(注意)==,自动转换数据类型再进行比较 ===,不会转换类型,在数据类型不一致的情况下会返回false\ ps:坚持使用= NaN = NaN;//false,NaN和任何值都不想等,包括自己 可以通过isNaN()方法来对其进行判断 isNaN(NaN);//true 浮点数的比较不能进行直接比较,而要将结果与一个精确值进行比较 Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001;//truenull表示空,和0或者''都不一样,前者表示数值0,后者表示长度为0的字符串,而null表示空 数组可以是任意数据的集合 var arr = [1,2,3.14,'hello',true]; 创建数组var arr1 = new Array(1,2,3); 获取数组长度 arr.length; 通过索引获取数组的索引位置值 arr[2];//3.14 超出访问会扩充数组 arr1[5] = 2;//数组变为[1,2,3,undefined,undefined,2] 常用的数组函数如下indexOf:根据值求索引 slice:取子数组 push:把元素添加到末尾 pop:返回并移除末尾元素 unshift:把元素添加到头部 shift:删掉头部元素 sort:把数组进行排序 reverse:翻转数组 splice(start,num,arg1...argn):从start开始删除num个元素,并在后面添加n个元素 concat:拼接数组 join:将数组的每个元素都使用join中的元素进行连接 对象一组由键-值组成的无序集合var person = { name:'Bob', age:20, city:'ShangHai', hasCar:true, zipcode:null } 可以使用对象名.属性名的方式来获取对象的属性 在属性名包含特殊字符,比如单引号时,可以使用对象名[属性名]来访问对象的属性 访问不存在的属性返回undefined 可以使用如下方式进行删除和新增属性,以及判断属性是不是在对象中person.wife = 'Linda';//增加wife属性 delete person.zipcode;//删除zipcode属性 person.son;//返回undefined,因为没有son属性 hasCar in person;//true,person包含hasCar属性 属性可能是继承得到的,比如toString属性,于是我们使用hasOwnProperty来判断对象自身是不是包含该属性变量使用var进行定义,比如var a = 12;1、a可以是任意类型 2、a的初始类型为int型,但是可以转化为字符串型 strict模式变量假如没有进行声明即使用,那么变量就会变成全局变量,这样将会对程序的运行进行严重的影响,我们使用strict模式来强制进行变量声明,使用的方式如下'use strict'; //code体 ... ... ... 判断语句if(some){ } some是布尔类型,则根据布尔值进行判断 some不是布尔类型,null,undefined,0,NaN和''表示false,其它一律视为true循环for ... in//对对象或者数组中的元素进行遍历 for(var key in o){ }集合MapMap是一个键值对的结构,查询速度很快 创建一个Map对象方式如下var m = new Map([['Michael',95],['Bob',75],['Tracy',85]]);//创建一个Map m.get('Michael');//通过键值获取值 m.set('Jack',89);//设置一个键值对 Set没有值重复的一个无序集合,创建如下var s = new Set([1,2,3,4,3]); s;//{1,2,3,4} s.add(5);//添加值 s.delete(4);//删除值 iterableMap、Array、Set都属于iterable类型,可以使用for ... of来进行遍历var a = ['A', 'B', 'C']; var s = new Set(['A', 'B', 'C']); var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]); for (var x of a) { // 遍历Array alert(x); } for (var x of s) { // 遍历Set alert(x); } for (var x of m) { // 遍历Map alert(x[0] + '=' + x[1]); } for ... in和for ... of的区别,前者得到的是索引,后者得到的是值函数 一系列动作的抽象 定义 方法1function 函数名(){ 函数体 } 方法2var 函数名 = function(){ 函数体 } 举例如下function abs(x){ if(x >= 0) return x; else return -x; } 调用abs(10); abs(-9); 调用函数时,即使调用参数与定义的不一样也没关系,可以多出参数数量,也可以少于参数数量,可以调用,但是结果可能不同,总之,JavaScript允许接收任意个参数函数参数arguments我们调用函数时,函数中会有一个默认的关键字,代表了当前函数的调用参数的集合,举个例子function foo(x){ alert(x); for(var i = 0;i < arguments.length;i++) alert(arguments[i]); } foo(10,20,30); rest参数表示函数参数列表的剩余项,并且只能放在函数参数项的最后,如下所示function foo(a,b, ...rest){ console.log('a = ' + a); console.log('b = ' + b); console.log(rest); } foo(1,2,3,4,5); foo(1); 以上,即使参数没有达到rest所需的条件,rest也不会是undefined,而是会返回一个空的数组return要注意JavaScript引擎有个问题,就是你把一句话写成两行的时候,此时该引擎就会在行的末尾自动添加分号,因此我们在return语句中千万注意将一句话写在一行函数的作用域1、如果不同的函数各自声明了同一个变量,那么该变量只在各自的函数体中起作用 2、内部函数可以访问外部变量 3、内部函数中的变量假如和外部函数中的变量重名,那么先访问内部函数的变量全局作用域不在函数中定义的变量具有全局作用域,实际上,JavaScript将该变量绑定到window上面去了,如下var course = 'Learn JavaScript'; alert(course); alert(window.course);// 上面的运行结果是一样的let我们使用var定义变量是不能定义具有局部作用域的变量的'use strict'; function foo() { for (var i=0; i<100; i++) { // } i += 100; // 仍然可以引用变量i } 为了解决这个问题,我们可以使用let进行定义块级的作用域,如下'use strict'; function foo() { var sum = 0; for (let i=0; i<100; i++) { sum += i; } i += 1; // SyntaxError } constconst是来定义常量的,并且和let一样具有块级作用域方法对象中绑定的函数称为对象的方法,如下var person = { name:'Jack', birth:1992, age:function(){ var y = new Date().getFullYear(); return y - this.birth; } } person.age;//25 person.age();//25 age();//NaN //这两种方式都可以调用方法 上面的返回结果与this关键字有关,假如我们通过对象调用age方法,那么this指向对象自身,假如我们直接调用age方法,那么this指向windowapplyapply是一个回调的自带函数,我们看一个例子function getAge(){ var y = new Date().getFullYear(); return y - this.birth; } var person = { name:'Jack', birth:1992, age:getAge }; person.age();//25 getAge.apply(person,[]);//25 高阶函数JavaScript的函数其实都指向一个变量,所以一个函数可以接收另一个函数作为参数,这称为高阶函数,如下function add(x,y,f){ return f(x) + f(y); } map/reducemap作为高阶函数,它抽象了运算规则,把运算的方法当成map函数的参数进行传递,然后对计算的结果进行返回,举例如下function pow(x){ return x * x; } var arr = [1,2,3,4,5,6,7]; arr.map(pow);//返回结果[1,4,9,16,25,36,49] //arr计算的结果不会覆盖arr原先的值,因此需要进行定义一个变量来接受计算的值 reduce的用法则是,reduce必须接收两个参数,并且将这两个参数计算的结果和下一个元素进行累积运算,如下[a,b,c,d].reduce(f) = f(f(f(a,b),c),d) 举个例子,将一个数组变成一个整数,如下var arr = [1,2,3,4]; arr.reduce(function(x,y){ return x * 10 + y; });//结果为1234 filter用于把数组的某些元素过滤掉,然后返回剩下的元素,如下var arr = [1,2,3,4,5,6,9,10,15]; var r = arr.filter(function(x){ return x % 2 !=== 0 }); alert(r);//[1,3,5,9,15] sort对数组进行排序,但是默认情况下是将数组元素转化为字符串再进行比较,但是我们依然可以对比较的函数进行定义,如下var arr = [10,20,1,2]; arr.sort(function(x,y){ if(x < y) return -1; else return 1; }); 闭包function lazy_sum(arr){ var sum = function(){ return arr.reduce(function(x,y){ return x + y; }); } } var f = lazy_sum([1,2,3,4,5]); f(); 像上面这样,将相关参数和变量都保存在返回的函数中,这种结构被称为闭包 创建一个匿名函数并立即执行的语法(function (x){ return x * x; })(3);//9 闭包可以进行私有变量的封装,如下所示function create_counter(initial){ var x = initial || 0; return { inc:function(){ x += 1; return x; } } } var c1 = create_counter(); c1.inc(); c1.inc(); c1.inc() 箭头函数箭头函数与匿名函数的意思是差不多的,而且简化了函数定义,箭头函数有两种形式,一种是只包含一个表达式,另一种可以包含多条语句,这时候就不能省略{...}和return了,如下 形式1var fn = x => x * x; 形式2var fn = x => { if(x > 0) return x * x; else return - x * x; } this箭头函数和匿名函数虽然很像,但是它们的this的作用域是不同的,匿名函数的this指向window,而箭头函数的this指向词法作用域generatorgenerator和函数的不同之处在于其可以返回多次,它的写法如下所示function* foo(x){ yield x + 1; yield x + 2; return x + 3; } 标准对象JavaScript的一切都是对象Date对象:用来表示日期和时间,可以获取系统的时间,也可以自行设置var now = new Date();//获取系统的时间 var d = new Date(2015,5,14,20,15,30,123);//设置指定的时间 RegExp对象:正则表达式对象,用于对字符串进行特定规则的匹配正则匹配(基本)\d:表示匹配一个数字 \w:表示匹配一个字符 \s:表示匹配一个空格 .:表示匹配任意一个字符 *:表示匹配任意个字符 +:表示匹配至少1个字符 ?:表示匹配0或1个字符 {n}:表示匹配n和字符 {n,m}:表示匹配n-m个字符 正则匹配(进阶)精确匹配可以使用`[]`来表示范围 [0-9a-zA-Z\_]:表示匹配一个数字、字母或下划线 [0-9a-zA-Z\_]+:表示匹配至少一个数字、字母或下划线 [a-zA-Z\_\$][0-9a-zA-Z\_\$]*:匹配由字母、下划线或$开头,后面跟上任意个数字、字母、下划线或者$的字符串 [a-zA-Z\_\$][0-9a-zA-Z\_\$]{0, 19}:对上面的后面字符串的个数进行了限定,不得超出20个 A|B:表示匹配A或B ^表示行的开头,^\d表示必须以数字开头 $表示行的结束,\d$表示必须以数字结束 有两种方式创建一个正则表达式var re1 = /ABC\-001/;//第一种方法 var re2 = new RegExp('ABC\\-001');//第二种方法 创建完RegExp对象之后,使用test(参数)方法来进行测试var re = new RegExp('^\d{3}-\d{3,8}'); re.test('010-12345');//true re.test('010-1234x');//false re.test('010 12345');//false 切分字符串 str.split('正则表达式'),如下'a b c'.split(' ');//['a','b','c'] 'a b c'.split('\s+');//['a','b','c'] 分组 对字符串进行提取,提取的规则是正则表达式,它的作用是这样的,使用()对正则表达式进行分组,匹配成功之后,返回的结果是一个数组,包括:1、匹配成功的字符串,2、根据()对匹配字符串进行分组的每一个组元素var re = new RegExp('^(\d{3})-(\d{3,8})$'); re.exec('010-12345');//返回['010-12345','010','12345'] 贪婪匹配 匹配尽可能多的字符,正则表达式默认的是贪婪匹配,如下var re = /^(\d+)(0*)$/ re.exec('102300');//结果为['102300','102300',''] 如何采用非贪婪匹配呢,也就是采用尽可能少的匹配呢,加个?就可以了,如下var re = /^(\d+?)(0*)$/ re.exec('102300');//结果为['102300','1023','00'] 全局搜索 全局匹配可以多次执行exec()方法来搜索一个匹配的字符串,如下var re = /[a-zA-Z]+Script/g; var s = 'JavaScript,VBScript, JScript and ECMAScript'; re.exec(s);//['JavaScript'] re.lastIndex;//10 re.exec(s);//['VBScript'] re.lastIndex;//20 JSON一种用来进行传递数据的格式,它规定了字符集必须是UTF-8,规定了字符串和Object的键都必须使用双引号"" 使用stringify可以将对象进行序列化,如下var person = { name: '小明', age: 14, gender: true, height: 1.65, grade: null, 'middle-school': '\"W3C\" Middle School', skills: ['JavaScript', 'Java', 'Python', 'Lisp'] }; JSON.stringify(person);//'{"name":"小明","age":14,"gender":true,"height":1.65,"grade":null,"middle-school":"\"W3C\" Middle School","skills":["JavaScript","Java","Python","Lisp"]}' //也可以使用参数让结果更加美观 JSON.stringify(person,null,' ');//{ "name": "小明", "age": 14, "gender": true, "height": 1.65, "grade": null, "middle-school": "\"W3C\" Middle School", "skills": [ "JavaScript", "Java", "Python", "Lisp" ] } 反序列化就是讲JSON格式解析成JavaScript对象,使用的方法是parse,如下JSON.parse('[1,2,3,true]'); // [1, 2, 3, true] JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14} JSON.parse('true'); // true JSON.parse('123.45'); // 123.45 面向对象编程JavaScript语言没有类和实例的概念,而是通过原型来进行面向对象编程,看下面var robot = { name:'Robot', height:1.6, run:function(){ console.log(this.name + ' is running...'); } }; var xiaoming = { name:'xiaoming' }; xiaoming.__proto__ = robot; xiaoming.name; xiaoming.run(); JavaScript和Java的区别就在于JavaScript没有‘class’概念,而是通过原型链的方式来进行继承,而这种继承,只是将一个对象的原型指向另一个对象而已 JavaScript进行获取对象属性的操作时,会现在当前的对象中找,没有找到就到其原型对象中去找,没有找到就一直追溯到Object.prototype,如果还没找到就返回undefined构造函数function Student(name){ this.name = name; this.hello = function(){ alert('Hello, ' + this.name + '!'); } } var Jack = new Student('Jack'); Jack.name; Jack.hello(); //上面的函数,如果就是普通调用,就会返回一个undefined,如果使用new关键字,那么就是一个构造函数,它绑定的this指向新建的对象, 如果不同的对象可以共用一部分方法,那么就可以大大减少内存的使用,比如下面function Student(name){ this.name = name; } Student.prototype.hello = function(){ alert('Hello, ' + this.name + '!'); }; 上面用到了原型的概念,当我们在函数的原型上定义方法时,那么假如定义了该函数的对象,那么不同的对象就可以使用相同的原型方法,这样做可以增加内存的使用效率原型继承由于JavaScript没有类的概念,那么JavaScript也不能像类那样进行继承,但是假如我想创建一个继承自原先实例的类,那么我们可以使用原型继承的方式进行继承function PrimaryStudent(props){ Student.call(this,props); this.grade = props.grade || 1; } function F(){ } F.prototype = Student.prototype; PrimaryStudent.prototype = new F(); PrimaryStudent.prototype.constructor = PrimaryStudent; PrimaryStudent.prototype.getGrade = function(){ return this.grade; }; var xiaoming = new PrimaryStudent({ name:'小明', grade:2 }); xiaoming.name;//小明 xiaoming.grade;//2 浏览器浏览器对象window:表示当前浏览器窗口 navigator:获取浏览器的信息 screen:表示屏幕的信息 location:表示当前页面的URL信息 document:表示当前页面,由于HTML在浏览器中以DOM形式表示为树结构,因此document表示DOM数的根节点 document.getElementById();//由于ID是唯一的,因此可以通过id唯一定位一个元素 document.getElementsByTagName();//返回一组节点,这组节点包含参数而不是和参数一致 document.getElementsByClassName();//返回一组节点,这组节点包含参数而不是和参数一致 history:保存了浏览器的历史记录(不应该继续使用这个对象了) 操作DOM更新:更新DOM节点表示的HTML内容 有两种形式可以用来更新HTML内容 1、直接修改innerHTML//获取<p id="p-id">...</p> var p = document.getElementById('p-id'); p.innerHTML = 'ABC';//结果为<p id="p-id">ABC</p> p.innerHTML = 'ABC<span style="clolr:red">RED</span>XYZ' 2、通过修改innerText,这样只会修改元素的内容var p = document.getElementById('p-id'); p.innerText = '<script>alert</script>';//只是会设置p的内容,而不会修改节点的属性 遍历:遍历DOM节点下的子节点 使用节点的children属性可以对节点的子节点进行遍历var parent = document.getElementById('parent'); var i = 0; var arr = []; for(i = 0;i < parent.children.length;i++) arr.push(parent.child[i]); 添加:在该DOM节点下新增一个子节点 有两种方法可以添加新的节点 1、使用appendChildvar js = document.getElementById('js'), list = document.getElementById('list'); list.appendChild(js);//会将原先的节点添加到list的末尾 2、使用insertBefore 把子节点插入到指定的位置var list = document.getElementById('list'), ref = document.getElementById('python'), haskell = document.createElement('p'); haskell.id = 'haskell'; haskell.innerText = 'Haskell'; list.insertBefore(haskell,ref); 删除:将该节点从HTML中删除 使用removeChild函数可以将节点进行删除,但是此时节点还在内存中var self = document.getElementById('to-be-removed');//获取被删除的节点 var parent = self.parentElement; var removed = parent.removeChild(self); removed = self;//true,说明被删除的节点还存在于内存中 操作表单 获取值,可以通过拿取input节点的value属性来获取用户对应的输入值var input = document.getElementById('email'); input.value;// 这对于单选或复选只能获取预设值,假如我们需要获取其是否被选上,那么我们可以用checked来进行获取设置值 对表单节点的value或者checked进行值的设置提交表单 有两种方式提交表单 1、使用form中的button的onclick进行提交<!-- HTML --> <form id="test-form"> <input type="text" name="test"> <button type="button" onclick="doSubmitForm()">Submit</button> </form> <script> function doSubmitForm() { var form = document.getElementById('test-form'); // 可以在此修改form的input... // 提交form: form.submit(); } </script> 2、使用表单自身的onsubmit事件<!-- HTML --> <form id="test-form" onsubmit="return checkForm()"> <input type="text" name="test"> <button type="submit">Submit</button> </form> <script> function checkForm() { var form = document.getElementById('test-form'); // 可以在此修改form的input... // 继续下一步: return true;//只有return true才会提交,return false将不会提交 } </script> 第一种方式扰乱了浏览器form的正常提交操作文件 可以进行上传文件的唯一控件就是<input type="file"> 但是浏览器处于安全考虑只允许使用点击的方式来上传文件
2017年08月07日
540 阅读
0 评论
0 点赞
2017-08-07
JSON 和 BSON的区别
bson是由10gen开发的一个数据格式,目前主要用于mongoDB中,是mongoDB的数据存储格式。bson基于json格式,选择json进行改造的原因主要是json的通用性及json的schemaless的特性。bson主要会实现以下三点目标:1.更快的遍历速度对json格式来说,太大的json结构会导致数据遍历非常慢。在json中,要跳过一个文档进行数据读取,需要对此文档进行扫描才行,需要进行麻烦的数据结构匹配,比如括号的匹配。而bson对json的一大改进就是,它会将json的每一个元素的长度存在元素的头部,这样你只需要读取到元素长度就能直接seek到指定的点上进行读取了。2.操作更简易对json来说,数据存储是无类型的,比如你要修改基本一个值,从9到10,由于从一个字符变成了两个,所以可能其后面的所有内容都需要往后移一位才可以。而使用bson,你可以指定这个列为数字列,那么无论数字从9长到10还是100,我们都只是在存储数字的那一位上进行修改,不会导致数据总长变大。当然,在mongoDB中,如果数字从整形增大到长整型,还是会导致数据总长变大的。3.增加了额外的数据类型json是一个很方便的数据交换格式,但是其类型比较有限。bson在其基础上增加了“byte array”数据类型。这使得二进制的存储不再需要先base64转换后再存成json,大大减少了计算开销和数据大小。当然,在有的时候,bson相对json来说也并没有空间上的优势,比如对{“field”:7},在json的存储上7只使用了一个字节,而如果用bson,那就是至少4个字节(32位)目前在10gen的努力下,bson已经有了针对多种语言的编码解码包。并且都是Apache 2 license下开源的。并且还在随着mongoDB进一步地发展。总结:数据结构: json是像字符串一样存储的,bson是按结构存储的(像数组 或者说struct)存储空间 bson>json操作速度 bson>json。比如,遍历查找:json需要扫字符串,而bson可以直接定位修改: json也要大动大移,bson就不需要。
2017年08月07日
1,538 阅读
0 评论
0 点赞
2017-08-07
Linux 学习笔记
Linux 命令格式command [-options] [parameter1] … 说明: command:命令名,相应功能的英文单词或单词的缩写 [-options]:选项,可用来对命令进行控制,也可以省略,[]代表可选 parameter1 …:传给命令的参数,可以是零个或多个 --help一般 Linux 外部命令(非内建)自带的帮助信息:command --helpmanman 是 Linux 提供的一个手册,包含了绝大部分的命令、函数使用说明。使用格式:man commandman设置了如下的功能键: 功能键 功能 空格键 显示手册页的下一屏 Enter键 一次滚动手册页的一行 b 回滚一屏 f 前滚一屏 q 退出man命令 h 列出所有功能键 /word 搜索word字符串 lsls是英文单词list的简写,其功能为列出目录的内容,是用户最常用的命令之一,它类似于DOS下的dir命令。Linux文件或者目录名称最长可以有265个字符,“.”代表当前目录,“..”代表上一级目录,以“.”开头的文件为隐藏文件,需要用 -a 参数才能显示。ls常用参数: 参数 含义 -a 显示指定目录下所有子目录与文件,包括隐藏文件 -l 以列表方式显示文件的详细信息 -h 配合 -l 以人性化的方式显示文件大小 unix/Linux系统中常用的文件类型有5种:普通文件、目录文件、设备文件、管道文件和链接文件。 与DOS下的文件操作类似,在Unix/Linux系统中,也同样允许使用特殊字符来同时引用多个文件名,这些特殊字符被称为通配符。 通配符 含义 * 文件代表文件名中所有字符 ls te* 查找以te开头的文件 ls *html 查找结尾为html的文件 ? 代表文件名中任意一个字符 ls ?.c 只找第一个字符任意,后缀为.c的文件 ls a.? 只找只有3个字符,前2字符为a.,最后一个字符任意的文件 [] [”和“]”将字符组括起来,表示可以匹配字符组中的任意一个。“-”用于表示字符范围。 [abc] 匹配a、b、c中的任意一个 [a-f] 匹配从a到f范围内的的任意一个字符 ls [a-f]* 找到从a到f范围内的的任意一个字符开头的文件 ls a-f 查找文件名为a-f的文件,当“-”处于方括号之外失去通配符的作用 \ 如果要使通配符作为普通字符使用,可以在其前面加上转义字符。“?”和“*”处于方括号内时不用使用转义字符就失去通配符的作用。 ls *a 查找文件名为*a的文件 输出重定向命令:>, >>Linux允许将命令执行结果重定向到一个文件,本应显示在终端上的内容保存到指定文件中。如:ls > test.txt ( test.txt 如果不存在,则创建,存在则覆盖其内容输出重定向会覆盖原来的内容,>>输出重定向则会追加到文件的尾部。目录切换Unix/Linux路径由到达定位文件的目录组成。在Unix/Linux系统中组成路径的目录分割符为斜杠“/”,而DOS则用反斜杠“\”来分割各个目录。路径分为绝对路径和相对路径: 绝对路径 绝对路径是从目录树的树根“/”目录开始往下直至到达文件所经过的所有节点目录。 下级目录接在上级目录后面用“/”隔开。 注意:绝对路径都是从“/”开始的,所以第一个字符一定是“/”。 相对路径 相对路径是指目标目录相对于当前目录的位置。 如果不在当前目录下,则需要使用两个特殊目录“.”和“..”了。目录“.”指向当前目录,而目录“..”指上一级目录。 cd在使用Unix/Linux的时候,经常需要更换工作目录。cd命令可以帮助用户切换工作目录。Linux所有的目录和文件名大小写敏感。cd后面可跟绝对路径,也可以跟相对路径。如果省略目录,则默认切换到当前用户的主目录。 命令 含义 cd 切换到当前用户的主目录(/home/用户目录),用户登陆的时候,默认的目录就是用户的主目录。 cd ~ 切换到当前用户的主目录(/home/用户目录) cd . 切换到当前目录 cd .. 切换到上级目录 cd - 可进入上一个进入的目录 rm可通过rm删除文件或目录。使用rm命令要小心,因为文件删除后不能恢复。为了防止文件误删,可以在rm后使用-i参数以逐个确认要删除的文件。常用参数及含义如下表所示: 参数 含义 -i 以进行交互式方式执行 -f 强制删除,忽略不存在的文件,无需提示 -r 递归地删除目录下的内容,删除文件夹时必须加此参数 cpcp命令的功能是将给出的文件或目录复制到另一个文件或目录中,相当于DOS下的copy命令。常用选项说明: 选项 含义 -p 该选项通常在复制目录时使用,它保留链接、文件属性,并递归地复制目录,简单而言,保持文件原有属性。 -f 删除已经存在的目标文件而不提示 -i 交互式复制,在覆盖目标文件之前将给出提示要求用户确认 -r 若给出的源文件是目录文件,则cp将递归复制该目录下的所有子目录和文件,目标文件必须为一个目录名。 -v 显示拷贝进度 mv用户可以使用mv命令来移动文件或目录,也可以给文件或目录重命名。常用选项说明: 选项 含义 -f 禁止交互式操作,如有覆盖也不会给出提示 -i 确认交互方式操作,如果mv操作将导致对已存在的目标文件的覆盖,系统会询问是否重写,要求用户回答以避免误覆盖文件 -v 显示移动进度 findfind命令功能非常强大,通常用来在特定的目录下搜索符合条件的文件,也可以用来搜索特定用户属主的文件。按文件名查询:使用参数 -name 命令:find + 路径 + -name +“文件名” 示例:find /home -name “a.txt” 按文件大小查询:使用参数 -size 命令:find + 路径 + -size + 范围 范围 大于:+表示 -- +100k 小于:-表示 -- -100k 等于: 不需要添加符号 -- 100k 大小 M 必须大写(10M) k 必须小写(20k) 例子: 查询目录为家目录 等于100k的文件: find ~/ -size 100k 大于100k的文件: find ~/ -size +100k 大于50k, 小于100k的文件: find ~/ -size +50k -size -100k 按文件类型查询:使用参数 -type 命令:find + 路径 + -type + 类型 类型 普通文件类型用 f 表示而不是 - d -> 目录 l -> 符号链接 b -> 块设备文件 c -> 字符设备文件 s -> socket文件,网络套接字 p -> 管道 查找指定目录下的普通文件:find /home -type f grepLinux系统中grep命令是一种强大的文本搜索工具,grep允许对文本文件进行模式查找。如果找到匹配模式, grep打印包含模式的所有行。grep一般格式为:grep [-选项] ‘搜索内容串’文件名 在grep命令中输入字符串参数时,最好引号或双引号括起来,如:grep 'a' 1.txt 常用选项说明: 选项 含义 -v 显示不包含匹配文本的所有行(相当于求反) -n 显示匹配行及行号 -i 忽略大小写 grep搜索内容串可以是正则表达式。正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。grep常用正则表达式: 参数 含义 ^a 搜寻以 m 开头的行;grep -n '^a' 1.txt ke$ 行尾,搜寻以 ke 结束的行;grep -n 'ke$' 1.txt [Ss]igna[Ll] 匹配 [] 里中一系列字符中的一个;搜寻匹配单词signal、signaL、Signal、SignaL的行;grep -n '[Ss]igna[Ll]' 1.txt . (点) 匹配一个非换行符的字符;匹配 e 和 e 之间有任意一个字符,可以匹配 eee,eae,eve,但是不匹配 ee,eaae;grep -n 'e.e' 1.txt 管道 |管道(|):一个命令的输出可以通过管道做为另一个命令的输入。管道我们可以理解现实生活中的管子,管子的一头塞东西进去,另一头取出来,这里“ | ”的左右分为两端,左端塞东西(写),右端取东西(读)。压缩包管理1) tar计算机中的数据经常需要备份,tar是Unix/Linux中最常用的备份工具,此命令可以把一系列文件归档到一个大文件中,也可以把档案文件解开以恢复数据。tar使用格式:tar [参数] 打包文件名 文件 常用参数: 参数 含义 -c 生成档案文件,创建打包文件 -v 列出归档解档的详细过程,显示进度 -f 指定档案文件名称,f后面一定是.tar文件,所以必须放选项最后 -t 列出档案中包含的文件 -x 解开档案文件 注意: 除了f需要放在参数的最后,其它参数的顺序任意。 参数前面可以使用“-”,也可以不使用。 # 压缩 tar cvzf 压缩包名 文件1 文件2 # -z : 指定压缩包的格式为:file.tar.gz # 解压 tar zxvf 压缩包包名 (z可以省略) # -C 解压到指定目录 2) gzip tar与gzip命令结合使用实现文件打包、压缩。 tar只负责打包文件,但不压缩,用gzip压缩tar打包后的文件,其扩展名一般用xxxx.tar.gz。 gzip使用格式如下:gzip [选项] 被压缩文件 常用选项: 选项 含义 -d 解压 -r 压缩所有子目录 3) bzip2 tar与bzip2命令结合使用实现文件打包、压缩(用法和gzip一样)。 tar只负责打包文件,但不压缩,用bzip2压缩tar打包后的文件,其扩展名一般用xxxx.tar.bz2。 在tar命令中增加一个选项(-j)可以调用bzip2实现了一个压缩的功能,实行一个先打包后压缩的过程。 压缩用法:tar jcvf 压缩包包名 文件... (tar jcvf bk.tar.bz2 *.c) 解压用法:`tar jxvf 压缩包包名 (tar jxvf(j可省略) bk.tar.bz2) 4) zip、unzip 通过zip压缩文件的目标文件不需要指定扩展名,默认扩展名为zip。 压缩文件:zip -r 目标文件(可以不指定扩展名) 源文件 解压文件:unzip -d 解压后目录文件 压缩文件 文件权限管理chmod 修改文件权限有两种使用格式:字母法与数字法。字母法:chmod u/g/o/a +/-/= rwx 文件 [ u/g/o/a ] 含义 u user 表示该文件的所有者 g group 表示与该文件的所有者属于同一组( group )者,即用户组 o other 表示其他以外的人 a all 表示这三者皆是 [ +-= ] 含义 + 增加权限 - 撤销权限 = 设定权限 rwx 含义 r read 表示可读取,对于一个目录,如果没有r权限,那么就意味着不能通过ls查看这个目录内部的内容。 w write 表示可写入,对于一个目录,如果没有w权限,那么就意味着不能在目录下创建新的文件。 x excute 表示可执行,对于一个目录,如果没有x权限,那么就意味着不能通过cd进入这个目录。 数字法:“rwx” 这些权限也可以用数字来代替 r :读取权限,数字代号为 "4" w :写入权限,数字代号为 "2" x :执行权限,数字代号为 "1" - :不具任何权限,数字代号为 "0" 如执行:chmod u=rwx,g=rx,o=r filename 就等同于:chmod u=7,g=5,o=4 filenamechmod 751 file 文件所有者:读、写、执行权限 同组用户:读、执行的权限 其它用户:执行的权限
2017年08月07日
890 阅读
0 评论
0 点赞
2017-08-07
Python的其他高阶函数
map()函数map()是 Python 内置的高阶函数,它接收一个函数 f 和一个list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。def f(x): return x * x print map(f,[1,2,3,4,5,6,7]) #list里的每个元素都会走一遍f(x)方法123 结果将会是:[1, 4, 9, 10, 25, 36, 49] reduce()函数reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。def f(x ,y ): return x * y print reduce(f,[1,2,3,4]) #1*2*3*4=24 # 给初始值 def f(a,b): return a+ b print reduce(f,[1,2,3,4],10) #1+2+3+4+10.这里的第三个参数是做为初始值的。12345678 filter()函数filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。def is_odd(x): return x%2==1 print filter(is_odd,[1,2,3,4,5,6,7]) # [1, 3, 5, 7]123 sorted()函数sorted() 函数对所有可迭代的对象进行排序操作。sort 与 sorted 区别: sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。 list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。语法 sorted 语法:sorted(iterable[, cmp[, key[, reverse]]])1 参数说明: iterable -可迭代对象。 cmp -比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。 key -主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。 reverse -排序规则,reverse = True 降序 , reverse = False 升序(默认)。 返回值返回重新排序的列表。>>>a = [5,7,6,3,4,1,2] >>> b = sorted(a) # 保留原列表 >>> a [5, 7, 6, 3, 4, 1, 2] >>> b [1, 2, 3, 4, 5, 6, 7] >>> L=[('b',2),('a',1),('c',3),('d',4)] >>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1])) # 利用cmp函数 [('a', 1), ('b', 2), ('c', 3), ('d', 4)] >>> sorted(L, key=lambda x:x[1]) # 利用key [('a', 1), ('b', 2), ('c', 3), ('d', 4)] >>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)] >>> sorted(students, key=lambda s: s[2]) # 按年龄排序 [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)] >>> sorted(students, key=lambda s: s[2], reverse=True) # 按降序 [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)] >>>
2017年08月07日
640 阅读
0 评论
0 点赞
2017-08-07
Python的匿名函数
为什么Lisp语言如此先进?如果我们把流行的编程语言,以这样的顺序排列:Java、Perl、Python、Ruby。你会发现,排在越后面的语言,越像Lisp。Python模仿Lisp,甚至把许多Lisp黑客认为属于设计错误的功能,也一起模仿了。至于Ruby,如果回到1975年,你声称它是一种Lisp方言,没有人会反对。编程语言现在的发展,不过刚刚赶上1958年Lisp语言的水平。-- 《黑客与画家》Python匿名函数应该就是借鉴的Lisp语言的特点 使用Python写一些脚本时,使用lambda可以省去定义函数的过程,让代码更加精简。 对于一些抽象的,不会被别的地方再重复使用的函数,有时候函数起个名字也是个难题,使用lambda不需要考虑命名的问题 使用lambda在某些时候然后代码更容易理解 python 使用 lambda 来创建匿名函数。lambda这个名称来自于LISP,而LISP则是从lambda calculus(一种符号逻辑形式)取这个名称的。 在Python中,lambda作为一个关键字,作为引入表达式的语法。想比较def函数,lambda是单一的表达式,而不是语句块!所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。 lambda 只是一个表达式,函数体比 def 简单很多。 lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。 lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。 语法 lambda 函数的语法只包含一个语句,如下:lambda [arg1 [,arg2,.....argn]]:expression # lambda 参数列表:return [表达式] 变量 # 由于lambda返回的是函数对象(构建的是一个函数对象),所以需要定义一个变量去接收1234 实例一# 可写函数说明 sum = lambda arg1, arg2: arg1 + arg2; # 调用sum函数 print ("相加后的值为 : ", sum( 10, 20 )) # 相加后的值为 : 30 print ("相加后的值为 : ", sum( 20, 20 )) # 相加后的值为 : 40 1234567 实例二对字典排序infors = [{"name":"wang","age":10},{"name":"insmoin","age":20},{"name":"banzhang","age":10}] infors.sort(key=lambda x:x['age']) #根据age对字典排序 print(infors) # 排序结果 [{'name': 'wang', 'age': 10}, {'name': 'insmoin', 'age': 10}, {'name': 'xiaoming', 'age': 20}]1234567 实例三把lambda当一个变量def test(a,b,func): result = func(a,b) return result num = test(11,22,lambda x,y:x+y) print(num)
2017年08月07日
577 阅读
0 评论
0 点赞
2017-08-07
Python装饰器的理解
Python装饰器的理解 装饰器, 字面理解就是额外的装饰.装饰器的强大在于它能够在不修改原有业务逻辑的情况下对代码进行扩展,权限校验、用户认证、日志记录、性能测试、事务处理、缓存等都是装饰器的绝佳应用场景,它能够最大程度地对代码进行复用。函数作为返回值在Python中,一切皆为对象,函数也不例外,它可以像整数一样作为其它函数的返回值,例如:def foo(): return 1 def bar(): return foo print(bar()) # <function foo at 0x10a2f4140> print(bar()()) # 1 # 等价于 print(foo()) # 1 调用函数 bar() 的返回值是一个函数对象 ,因为返回值是函数,所以我们可以继续对返回值进行调用(记住:调用函数就是在函数名后面加())调用bar()()相当于调用 foo(),因为 变量 foo 指向的对象与 bar() 的返回值是同一个对象。函数作为参数函数还可以像整数一样作为函数的参数,例如:def foo(num): return num + 1 def bar(fun): return fun(3) value = bar(foo) print(value) # 4 函数 bar 接收一个参数,这个参数是一个可被调用的函数对象,把函数 foo 传递到 bar 中去时,foo 和 fun 两个变量名指向的都是同一个函数对象,所以调用 fun(3) 相当于调用 foo(3)。函数嵌套函数不仅可以作为参数和返回值,函数还可以定义在另一个函数中,作为嵌套函数存在,例如:def outer(): x = 1 def inner(): print(x) inner() outer() # 1 inner做为嵌套函数,它可以访问外部函数的变量,调用 outer 函数时,发生了3件事: 给 变量 x 赋值为1 定义嵌套函数 inner,此时并不会执行 inner 中的代码,因为该函数还没被调用,直到第3步 调用 inner 函数,执行 inner 中的代码逻辑。 闭包再来看一个例子:def outer(x): def inner(): print(x) return inner closure = outer(1) closure() # 1 同样是嵌套函数,只是稍改动一下,把局部变量 x 作为参数了传递进来,嵌套函数不再直接在函数里被调用,而是作为返回值返回,这里的 closure就是一个闭包,本质上它还是函数,闭包是引用了自由变量(x)的函数(inner)。装饰器继续往下看:def foo(): print("foo") 上面这个函数这可能是史上最简单的业务代码了,虽然没什么用,但是能说明问题就行。现在,有一个新的需求,需要在执行该函数时加上日志:def foo(): print("记录日志开始") print("foo") print("记录日志结束") 功能实现,唯一的问题就是它需要侵入到原来的代码里面,把日志逻辑加上去,如果还有好几十个这样的函数要加日志,也必须这样做,显然,这样的代码很Low。那么有没有可能在不修改业务代码的提前下,实现日志功能呢?答案就是装饰器。def outer(func): def inner(): print("记录日志开始") func() # 业务函数 print("记录日志结束") return inner def foo(): print("foo") foo = outer(foo) foo() 没有修改 foo 函数里面的任何逻辑,只是给 foo 变量重新赋值了,指向了一个新的函数对象。最后调用 foo(),不仅能打印日志,业务逻辑也执行完了。现在来分析一下它的执行流程。这里的 outer 函数其实就是一个装饰器,装饰器是一个带有函数作为参数并返回一个新函数的闭包,本质上装饰器也是函数。outer 函数的返回值是 inner 函数,在 inner 函数中,除了执行日志操作,还有业务代码,该函数重新赋值给 foo 变量后,调用 foo() 就相当于调用 inner()另外,Python为装饰器提供了语法糖 @,它用在函数的定义处:@outer def foo(): print("foo") foo() 这样就省去了手动给foo重新赋值的步骤。总结,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
2017年08月07日
783 阅读
0 评论
0 点赞
2017-08-07
Python2 编码问题
编解码 str--(decode)--unicode unicode--(encode)--str print 时会自动将unicode-->strPython2中默认的字符编码是ASCII码,也就是说Python在处理数据时,只要数据没有指定它的编码类型,Python默认将其当做ASCII码来进行处理。这个问题最直接的表现在当我们编写的python文件中包含有中文字符时,在运行时会提示出错python2中中文书写问题 按照u"中文"的方式书写,打印输出时可以指定encode方式,例如u"中文".encode("gbk"),u"中文".encode("utf-8") 如果是从变量获取的值,使用unicode(a) import sys info = raw_input(u'请输入:'.encode(sys.stdin.encoding).decode(sys.stdin.encoding or locale.getpreferredencoding(True))) 这是块级代码块
2017年08月07日
875 阅读
0 评论
0 点赞
2017-08-07
Pyhton 正则表达式 01
正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本许多程序设计语言都支持利用正则表达式进行字符串操作。Python也不例外.正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,模式描述在搜索文本时要匹配的一个或多个字符串在 Python 中,我们可以使用内置的 re 模块来使用正则表达式。有一点需要特别注意的是,正则表达式使用对特殊字符进行转义,所以如果我们要使用原始字符串,只需加一个 r 前缀,示例:r'chuanzhiboke\t\.\tpython' re模块的使用过程# 导入re模块 import re # 使用match方法进行匹配操作 result = re.match(正则表达式, 要匹配的字符串) # 如果上一步匹配到数据的话,可以使用group方法来提取数据 result.group() 使用示例匹配以insmoin开头的语句: import re result = re.match(r"insmoin","insmoin.com") #能够匹配出以insmoin开头的字符串 result.group() 字符功能 .匹配任意1个字符(除了\n)[ ]匹配[ ]中列举的字符\d匹配数字,即0-9\D匹配非数字,即不是数字\s匹配空白,即空格,tab键\S匹配非空白\w匹配单词字符,即a-z、A-Z、0-9、_\W匹配非单词字符 字符功能 *匹配前一个字符出现0次或者无限次,即可有可无+匹配前一个字符出现1次或者无限次,即至少有1次?匹配前一个字符出现1次或者0次,即要么有1次,要么没有{m}匹配前一个字符出现m次{m, n}匹配前一个字符出现从m到n次 字符功能 ^匹配字符串开头$匹配字符串结尾 字符功能 |匹配左右任意一个表达式(ab)将括号中字符作为一个分组|num引用分组num匹配到的字符串(?P)分组起别名(?P=name)引用别名为name分组匹配到的字符串 匹配出163、126、qq邮箱示例代码:import re ret = re.match("\w{4,20}@163\.com", "test@163.com") print(ret.group()) # test@163.com ret = re.match("\w{4,20}@(163|126|qq)\.com", "test@126.com") print(ret.group()) # test@126.com ret = re.match("\w{4,20}@(163|126|qq)\.com", "test@qq.com") print(ret.group()) # test@qq.com ret = re.match("\w{4,20}@(163|126|qq)\.com", "test@gmail.com") if ret: print(ret.group()) else: print("不是163、126、qq邮箱") # 不是163、126、qq邮箱
2017年08月07日
776 阅读
0 评论
0 点赞
2017-08-07
Pycharm自动导入模块小技巧
Pycharm是很多Python开发者的首选IDE,如果能把一个工具熟练运用,往往有事半功倍的效果,各种快捷键、重构功能、调试技巧。由于Python是一门动态语言,对于自动导入包模块没有静态语言那么方便,但是我们有了Pycharm,还是可以很强大的。平时写代码的时候,要引用系统自带的模块或者是第三方模块,甚至是项目中其它地方的模块,有时候代码快写了一整屏,为了把一个模块导入进来,我们不得不把光标拉到文件顶部,先把模块包名手动导入进来,再回到文件底部开始愉快地写代码,如此重复来回地切换,好麻烦。做开发的一个原则就是 Don't repeat yourself,重复的劳动应该让它自动去完成。其实,我们只需要简单两步配置就可以让Pycharm自动导入模块第一步:Pycharm->Perferences->Editor->Auto Import第二步:Pycharm->Perferences->Keymap就这么简单,设置完成后,来体验一下效果。导入random 模块,ctrl+空格(空格键按两下)就自动弹出可选的模块列表,上下移动进行切换。
2017年08月07日
1,433 阅读
0 评论
0 点赞
2017-08-07
Python的垃圾回收机制
像 c/c++ 这种语言是没有采用垃圾回收机制的,因此当一个对象再也不用时,程序员必须自己释放内存。但采用了垃圾回收机制的语言--如 python,程序员只管创建和使用,不管释放和回收。Python 的垃圾回收机制当前的垃圾回收算法多种多样,python 采用的是引用计数为主,标记清除和分代回收为辅的垃圾回收机制。引用计数原理:当创建或赋值对象的引用时,对象的引用计数加1;当销毁对象的引用时,对象的引用计数减1;当对象的引用计数值为0时,则说明对象已经没有被引用了,可以将对象所占用的内存释放。导致引用计数 +1 的情况: 对象被创建; 对象被引用; 对象作为参数传入函数中; 对象作为元素存储在容器中。 导致引用计数 -1 的情况: 对象被销毁; 对象的引用指向了新的对象; 对象离开了它的作用域; 对象所在的容器被销毁。 引用计数的优点: 无需挂起程序;(相对于标记清除法) 引用局部性比较好; 废弃及回收。 引用计数的缺点: 更新引用计数值的花销; 引用计数占据额外的空间; 无法处理环形引用的情况。 环形引用的产生什么是环形引用?比如, A 对象里引用了 B 对象,B 对象引用了 A 对象,这样就形成了环形引用。class A: pass a = A() # 这里 a 的引用是 1 次 b = A() # 这里同上 a.t = b # 这里 b 的引用 +1 ,因为 b 的引用为 2 次 b.t = a # 这里同上 del b # 这里 b 的引用 -1,因为原来 b 的引用是 2,-1 之后是1,a 的引用仍然为 2 del a # 这里同上 # 现在 a,b 已经被删了,但之前它们指向的对象的引用计数值仍为 1,不为 0, # 因此引用计数算法仍然认为这两个对象不是垃圾对象,这就是循环引用带来的问题。 python 为了解决循环引用的问题,引入了标记清除和分代回收。标记清除标记清除也是著名的垃圾回收算法之一,最典型的就是 java 采用了这个算法。 原理: 标记阶段:对所有存活对象进行一次全局遍历来进行对象的标记,所有可达对象标记为可达,其它不可达的对象就是可以被回收的垃圾对象。 清除阶段:清除所有垃圾对象。 标记清除的优点: 没有环形引用的问题(相对与引用计数); 无需操作引用计数值的开销(相对与引用计数)。 标记清除的缺点: 垃圾回收进行时,程序必须暂停。 标记阶段的花销较大 清除对象后会造成内存碎片的问题(解决方法是采用标记缩进算法,这里不再详述) 在 python 中,标记清除主要是为了解决循环引用的问题。 python 会用链表连接可能产生循环引用的对象(如 list,dict,class 等容器类,int,string这类不会产生循环引用),如,a=[],b=[],c={},将会产生:head <----> a <----> b <----> c 双向链表。然后从这些链表里的元素出发,标记每个可到达的对象,然后那些没有被标记的对象将会被清除。流程: 寻找根集合,如上面的链表,里面的元素一般为全局引用或函数栈上的引用 从根出发,可到达对象会被标记 清除所有没有被标记的对象 分代回收分代回收在我看来,是为了提高垃圾回收效率和程序性能的的机制。它作用的地方并不是垃圾回收的内容,而是垃圾回收这个动作。分代收集的思想就是活的越久的对象,就越不是垃圾,回收的频率就应该越低 --《Python垃圾回收机制及gc模块详解》这个分代回收非常重要的原因是:一部分对象的生存周期比较短,一部分对象的生存周期很长,甚至会持续到程序结束。 这样的话,采用标记清除时,如果都一视同仁的话,会有效率的问题。比如说,在某个对象的集合中,标记清除对象是 1s 进行一次,在进行了 10 次(共10s)的标记清除后,它发现一部分对象存在了 10 次,因此它把这部分对象移入另一个对象的集合中,对这些对象进行 10s 一次的标记清除,这样的话会比之前不区分的时候效率高,占用的资源少。python 的分代回收分三个代。(三个代其实是三个链表) 当各个代中的对象数量达到阈值的时候就会触发 python 的垃圾回收。(具体可用 gc 模块的 get_threshold()查看) python 首先从第三代开始检查,如果三代中的对象大于阈值则同时回收三个代的对象,如果二代的的对象大于阈值, 则回收二代和一代的对象。
2017年08月07日
788 阅读
0 评论
0 点赞
2017-08-07
Python的闭包
作用域作用域是程序运行时变量可被访问的范围,定义在函数内的变量是局部变量,局部变量的作用范围只能是函数内部范围内,它不能在函数外引用。定义在模块最外层的变量是全局变量,它是全局范围内可见的,当然在函数里面也可以读取到全局变量的。例如:num = 10 # 全局作用域变量 def foo(): print(num) # 10 而在函数外部则不可以访问局部变量。例如:def foo(): num = 10 print(num) # NameError: name 'num' is not defined 嵌套函数函数不仅可以定义在模块的最外层,还可以定义在另外一个函数的内部,像这种定义在函数里面的函数称之为嵌套函数(nested function)例如:def print_msg(): # print_msg 是外围函数 msg = "zen of python" def printer(): # printer是嵌套函数 print(msg) printer() # 输出 zen of python print_msg() 对于嵌套函数,它可以访问到其外层作用域中声明的非局部(non-local)变量,比如代码示例中的变量 msg 可以被嵌套函数 printer 正常访问。那么有没有一种可能即使脱离了函数本身的作用范围,局部变量还可以被访问得到呢?答案是闭包什么是闭包函数身为第一类对象,它可以作为函数的返回值返回,现在我们来考虑如下的例子:def print_msg(): # print_msg 是外围函数 msg = "zen of python" def printer(): # printer 是嵌套函数 print(msg) return printer another = print_msg() # 输出 zen of python another() 这段代码和前面例子的效果完全一样,同样输出 "zen of python"。不同的地方在于内部函数 printer 直接作为返回值返回了。一般情况下,函数中的局部变量仅在函数的执行期间可用,一旦 print_msg() 执行过后,我们会认为 msg变量将不再可用。然而,在这里我们发现 print_msg 执行完之后,在调用 another 的时候 msg 变量的值正常输出了,这就是闭包的作用,闭包使得局部变量在函数外被访问成为可能。看完这个例子,我们再来定义闭包,维基百科上的解释是:在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。这里的 another 就是一个闭包,闭包本质上是一个函数,它有两部分组成,printer 函数和变量 msg。闭包使得这些变量的值始终保存在内存中。闭包,顾名思义,就是一个封闭的包裹,里面包裹着自由变量,就像在类里面定义的属性值一样,自由变量的可见范围随同包裹,哪里可以访问到这个包裹,哪里就可以访问到这个自由变量。为什么要使用闭包闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。一般来说,当对象中只有一个方法时,这时使用闭包是更好的选择。来看一个例子:def adder(x): def wrapper(y): return x + y return wrapper adder5 = adder(5) # 输出 15 adder5(10) # 输出 11 adder5(6) 这比用类来实现更优雅,此外装饰器也是基于闭包的一中应用场景。所有函数都有一个 __closure__属性,如果这个函数是一个闭包的话,那么它返回的是一个由 cell 对象 组成的元组对象。cell 对象的cell_contents 属性就是闭包中的自由变量。>>> adder.__closure__ >>> adder5.__closure__ (<cell at 0x103075910: int object at 0x7fd251604518>,) >>> adder5.__closure__[0].cell_contents 5 这解释了为什么局部变量脱离函数之后,还可以在函数之外被访问的原因的,因为它存储在了闭包的 cell_contents中了。
2017年08月07日
1,619 阅读
0 评论
0 点赞
2017-08-07
Queue队列中join()与task_done()的关系
理解Queue队列中join()与task_done()的关系在网上大多关于join()与task_done()的结束原话是这样的:Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号Queue.join() 实际上意味着等到队列为空,再执行别的操作但是可能很多人还是不太理解,这里以我自己的理解来阐述这两者的关联。理解如果线程里每从队列里取一次,但没有执行task_done(),则join无法判断队列到底有没有结束,在最后执行个join()是等不到结果的,会一直挂起。可以理解为,每task_done一次 就从队列里删掉一个元素,这样在最后join的时候根据队列长度是否为零来判断队列是否结束,从而执行主线程。下面看个自己写的例子:下面这个例子,会在join()的地方无限挂起,因为join在等队列清空,但是由于没有task_done,它认为队列还没有清空,还在一直等。'''threading test''' import threading import queue from time import sleep #之所以为什么要用线程,因为线程可以start后继续执行后面的主线程,可以put数据,如果不是线程直接在get阻塞。 class Mythread(threading.Thread): def __init__(self,que): threading.Thread.__init__(self) self.queue = que def run(self): while True: sleep(1) if self.queue.empty(): #判断放到get前面,这样可以,否则队列最后一个取完后就空了,直接break,走不到print break item = self.queue.get() print(item,'!') #self.queue.task_done() return que = queue.Queue() tasks = [Mythread(que) for x in range(1)] for x in range(10): que.put(x) #快速生产 for x in tasks: t = Mythread(que) #把同一个队列传入2个线程 t.start() que.join() print('---success---') 如果把self.queue.task_done() 注释去掉,就会顺利执行完主程序。这就是“Queue.task_done()函数向任务已经完成的队列发送一个信号”这句话的意义,能够让join()函数能判断出队列还剩多少,是否清空了。而事实上我们看下queue的源码可以看出确实是执行一次未完成队列减一: def task_done(self): '''Indicate that a formerly enqueued task is complete. Used by Queue consumer threads. For each get() used to fetch a task, a subsequent call to task_done() tells the queue that the processing on the task is complete. If a join() is currently blocking, it will resume when all items have been processed (meaning that a task_done() call was received for every item that had been put() into the queue). Raises a ValueError if called more times than there were items placed in the queue. ''' with self.all_tasks_done: unfinished = self.unfinished_tasks - 1 if unfinished <= 0: if unfinished < 0: raise ValueError('task_done() called too many times') self.all_tasks_done.notify_all() self.unfinished_tasks = unfinished 快速生产-快速消费上面的演示代码是快速生产-慢速消费的场景,我们可以直接用task_done()与join()配合,来让empty()判断出队列是否已经结束。 当然,queue我们可以正确判断是否已经清空,但是线程里的get队列是不知道,如果没有东西告诉它,队列空了,因此get还会继续阻塞,那么我们就需要在get程序中加一个判断,如果empty()成立,break退出循环,否则get()还是会一直阻塞。慢速生产-快速消费但是如果生产者速度与消费者速度相当,或者生产速度小于消费速度,则靠task_done()来实现队列减一则不靠谱,队列会时常处于供不应求的状态,常为empty,所以用empty来判断则不靠谱。 那么这种情况会导致 join可以判断出队列结束了,但是线程里不能依靠empty()来判断线程是否可以结束。 我们可以在消费队列的每个线程最后塞入一个特定的“标记”,在消费的时候判断,如果get到了这么一个“标记”,则可以判定队列结束了,因为生产队列都结束了,也不会再新增了。 代码如下:'''threading test''' import threading import queue from time import sleep #之所以为什么要用线程,因为线程可以start后继续执行后面的主线程,可以put数据,如果不是线程直接在get阻塞。 class Mythread(threading.Thread): def __init__(self,que): threading.Thread.__init__(self) self.queue = que def run(self): while True: item = self.queue.get() self.queue.task_done() #这里要放到判断前,否则取最后最后一个的时候已经为空,直接break,task_done执行不了,join()判断队列一直没结束 if item == None: break print(item,'!') return que = queue.Queue() tasks = [Mythread(que) for x in range(1)] #快速生产 for x in tasks: t = Mythread(que) #把同一个队列传入2个线程 t.start() for x in range(10): sleep(1) que.put(x) for x in tasks: que.put(None) que.join() print('---success---') 注意点:put队列完成的时候千万不能用task_done(),否则会报错:task_done() called too many times 因为该方法仅仅表示get成功后,执行的一个标记。
2017年08月07日
1,347 阅读
0 评论
0 点赞
2017-08-07
Python yield 与 yield from
Python yield 与 yield from yield使用 1)函数中使用yield,可以使函数变成生成器。一个函数如果是生成一个数组,就必须把数据存储在内存中,如果使用生成器,则在调用的时候才生成数据,可以节省内存。 2)生成器方法调用时,不会立即执行。需要调用next()或者使用for循环来执行。使用for循环不需要自己捕获StopIteration异常。使用next()方法,当生产器方法执行结束会抛出StopIteration异常(只要不是使用yield返回数据,都会抛出StopIteration异常)。 示例:def fib(max): n,a,b = 0,0,1 while n < max: yield b a, b = b, a+b n = n + 1 return 'done' n = fib(10) for n1 in n: print(n1) 123456789101112 3)yield不仅可以返回值,也可以接收值。下面面示例为生产消费模式。生产者生产一条记录,消费者消费一条记录。 4)调用生成器send方法传递数据时,必须先调用next(c)或者c.send(None)方法,执行到yield语句,等待接收数据。否则会报错。 以下代码为廖雪峰网站的示例https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432090171191d05dae6e129940518d1d6cf6eeaaa969000def consumer(): r = '' while True: n = yield r if not n: return print('[CONSUMER] Consuming %s...' % n) r = '200 OK' def produce(c): c.send(None) # 和next方法一样 获取下一个值,必须先使用None参数调用一次, 执行到yield n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) # 先发送值给yield语句,再执行到yield语句时返回 print('[PRODUCER] Consumer return:%s' % r) c.close() c = consumer() produce(c)12345678910111213141516171819202122 2、yield from的使用 1)为了让生成器(带yield函数),能简易的在其他函数中直接调用,就产生了yield from。 2)以下代码,htest为生成器,itest通过yield from 直接调用htest。这样itest也变成了一个生成器。创建itest实例不断的去获取数据,当生成器执行结束时,会抛出StopIteration异常。那这个异常是htest抛出的,还是itest抛出的。通过捕获异常,会发现其实是itest抛出异常,htest并不会抛出StopIteration异常。 3)yield from 也可以返回值,通过变量接收。变量接收的值,即htest使用return返回的值。示例代码中,当i==3时,会直接使用return返回,这时val的值就是100;因为htest函数中不是使用yield返回值,所以itest会继续执行print(val)语句。itest代码执行完,然而并没有使用yield返回数据(htest中没有,itest中也没有),所以马上会抛出StopIteration异常)(如果在itest函数最后使用yield返回一个数据,就不会抛出异常)。def htest(): i = 1 while i < 4: n = yield i if i == 3: return 100 i += 1 def itest(): val = yield from htest() print(val) t = itest() t.send(None) j = 0 while j < 3: j += 1 try: t.send(j) except StopIteration as e: print('异常了')12345678910111213141516171819202122
2017年08月07日
1,247 阅读
0 评论
0 点赞
2017-08-07
Python的多任务 03 协程
什么是协程协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。通俗的讲:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定协程和线程的差异在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住协程其实就是一个可以暂停执行的函数,并且可以恢复继续执行。那么yield已经可以暂停执行了,如果在暂停后有办法把一些 value 发回到暂停执行的函数中,那么 Python 就有了『协程』。从技术的角度来说,“协程就是你可以暂停执行的函数”与生成器类似,但yield 出现在表达式的右边,且产出一个表达式值作为返回值,如果yield后没有表达式,则返回None。协程可以从调用方接收数据,caller.send(params)。1. 例子>>> def simple(a): print "start:a = ", (a) b = yield a print "received b= ",(b) c = yield a + b print "received :d ", (c) >>> m1 = simple(2) >>> m1 <generator object simple at 0x0000000003D830D8> >>> next(m1) # 激活协程, 并产出a,然后暂停 start:a = 2 2 >>> m1.send(3) received b= 3 5 >>> m1.send(1000) # b 接收数据,并产出 a+b 的结果,然后暂停 received :d 1000 Traceback (most recent call last): File "<pyshell#11>", line 1, in <module> m1.send(1000) StopIteration 把yield作为控制流程的方式来理解。上图中 第一阶段 yield a结束,第二阶段是给b 赋值开始再看一个例子:def averager(): total = 0 count = 0 avg = None while True: term = yield avg total += term count +=1 avg = total/count ag = averager() next(ag) # 运行到 yield avg 就停止,并返回avg值 None ag.send(100) # item 接收到100,并运行,直到下一个yield 并停止 2. 与协程相关的方法我们知道了怎么创建协程,但是当执行到最后,如果不处理就会和生成器一样抛出一个stopInteration异常来终止该协程,从2.5版本开始添加了两个方法throw 和close来终止协程如果generator.thow(exception)的异常被捕获,则继续下一个yield,否则终止3. 协程返回值在定义体中 return valuefrom collections import namedTuple Result = namedTuple("Result","count average") def average(): total = 0 count = 0 avg = None while True: term = yield if term is None: break # 终止符 total +=term count +=1 avg = total/count return Result(count,avg) 当send(None) 就会break, 返回。其中Result 会作为异常的value属性返回try: m2 .send(None) exception StopInteration as exc: print exc.value 应用# BEGIN YIELD_FROM_AVERAGER from collections import namedtuple Result = namedtuple('Result', 'count average') # the subgenerator def averager(): # <1> total = 0.0 count = 0 average = None while True: term = yield # <2> if term is None: # <3> break total += term count += 1 average = total/count return Result(count, average) # <4> # the delegating generator def grouper(results, key): # <5> while True: # <6> results[key] = yield from averager() #生成一个使用协程的生成器,在此处暂停,等 将一个Result 赋值给对应的key # the client code, a.k.a. the caller def main(data): # <8> results = {} for key, values in data.items(): group = grouper(results, key) # group是grouper函数生成的生成器对象 next(group) # 预激活协程 for value in values: # 把各个 value 传给 grouper。传入的值最终到达 averager 函数中 term = yield 那一行; grouper 永远不知道传入的值是什么 group.send(value) # 内层循环结束后, group 实例依旧在 yield from 表达式处暂停,因此, grouper函数定义体中为 results[key] 赋值的语句还没有执行 #把 None 传入 grouper,导致当前的 averager 实例终止,也让 grouper 继续运行,再创建一个 averager 实例,处理下一组值 group.send(None) # print(results) # uncomment to debug report(results) # output report def report(results): for key, result in sorted(results.items()): group, unit = key.split(';') print('{:2} {:5} averaging {:.2f}{}'.format( result.count, group, result.average, unit)) data = { 'girls;kg': [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5], 'girls;m': [1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43], 'boys;kg': [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3], 'boys;m': [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46], } if __name__ == '__main__': main(data) 上述例子,如果子生成器不停止,委派生成器永远在yield from 处停止。yield from iterable本质上等于for item in iterable: yield item的缩写yield from的意义把迭代器当作生成器使用,相当于把子生成器的定义体内联在 yield from 表达式 中。此外,子生成器可以执行 return 语句,返回一个值,而返回的值会成为 yield from 表达式的值 子生成器产出的值都直接传给委派生成器的调用方(即客户端代码将上述例子的averager 直接给了main中的group)。 使用 send() 方法发给委派生成器的值都直接传给子生成器。如果发送的值是 None,那么会调用子生成器的 __next__()方法。如果发送的值不是None,那么会 调用子生成器的 send()方法。如果调用的方法抛出 StopIteration 异常,那么委 派生成器恢复运行。任何其他异常都会向上冒泡,传给委派生成器。 生成器退出时,生成器(或子生成器)中的return expr表达式会触发 StopIteration(expr)异常抛出。 yield from 表达式的值是子生成器终止时传给 StopIteration 异常的第一个参 数。 yield from 结构的另外两个特性与异常和终止有关。 传入委派生成器的异常,除了GeneratorExit之外都传给子生成器的throw() 方 法。如果调用 throw()方法时抛出StopIteration 异常,委派生成器恢复运 行。 StopIteration 之外的异常会向上冒泡,传给委派生成器。 如果把GeneratorExit 异常传入委派生成器,或者在委派生成器上调用close()方 法,那么在子生成器上调用close()方法,如果它有的话。如果调用close() 方法 导致异常抛出,那么异常会向上冒泡,传给委派生成器;否则,委派生成器抛出 GeneratorExit异常。
2017年08月07日
3,724 阅读
0 评论
0 点赞
2017-08-07
Python的多任务 02
线程概念程序中一个可以执行的分支程序默认只有一个执行分支, 就是主线程想要完成多任务,可以再开辟一个线程,好比再有一个可以执行代码的分支。可以就可以完成多个任务同时在执行。线程是cpu调度的基本单位 在python里,使用threading模块来进行程序的多线程操作t = threading.Thread(target=saySorry) t.start() #启动线程,即让线程开始执行 使用threading.Thread创建线程 length = len(threading.enumerate()) #查看进程的数量 # threading.enumerate()是当前程序所有进行中的线程的列表,通过统计其长度,就可以得出当前有多少个线程在进行 threading.current_thread() #查看当前任务执行的线程 # 放在代码中的任意地方即可知道当前代码执行的是哪个线程,如果是放在函数里,则显示是执行子线程 将子线程设置成为守护主线程,主线程退出了,那么子线程直接销毁不执行代码了, 以后线程的销毁要依赖主线程调用setDaemon(True) 子线程名.setDaemon(True) join() 等待子线运行结束后再开启下一个子线程t1 = threading.Thread(target=sing, args=(5,), kwargs={"name": "insmoin", "age": 18}) 创建线程,此处sing后面不要带有小括号,只要有函数名即可1.target是线程执行函数的名字,函数的名字后面不要带有小括号,注意与函数调用的方法区别开来2.args:执行函数所需要的参数,这个参数要以元组的形式去传,如果只有一个元素,后面不要忘了逗号3.kwargs:执行函数所需要的参数, 这个参数要以字典方式去传注意: 调用完start方法以后线程才会放入到线程活动列表中线程注意点过使用threading模块能完成多任务的程序开发,为了让每个线程的封装性更完美,所以使用threading模块时,往往会定义一个新的子类class,只要继承threading.Thread就可以了,然后重写run方法当定义新的子类时,创建好实例对象后,不是通过调用run方法开启线程,而是通过对象.start()开启线程python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程。 主线程会等待所有的子线程结束后才结束 线程之间执行顺序是无序, 主线程会等待所有的子线程任务执行完成以后程序再退出 多线程共享全局变量的优缺点 优点: 在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据 缺点: 线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确 互斥锁当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性死锁在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。进程概念一个程序运行起来后, 代码+用到的资源, 就称为进程, 是操作系统分配资源的基本单位 Python进程的使用导入模块import multiprocessing获取当前进程编号导入模块import osOs.getpid() 获取当前的进程号在子进程里面获取当前子进程的父进程的编号用的是os.getppid(),注意与os.getpid的区别multiprocessing.current_process().pid也可以获取当前的进程编号os.kill() 根据指定的进程的编号杀死指定的进程查看当前任务由哪个进程执行multiprocessing.current_process() 创建进程实例名 = multiprocessing.Process 进程之间的通讯Queue导入模块import multiprocessing初始化一个Queue对象q=multiprocessing.Queue(5) # 括号内的数字代表能够接收的消息数量 # 消息可以是任意的数据类型,字符串,数字,列表,元组,字典,集合等 # 若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头) Queue.qsize() # 返回当前队列包含的消息数量 Queue.empty() # 如果队列为空,返回True,反之False Queue.full() # 如果队列满了,返回True,反之False Queue.get([block[, timeout]]) # 获取队列中的一条消息,然后将其从列队中移除,block默认值为True # 如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常; # 如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常 Queue.get_nowait() # 相当于 Queue.get(False) Queue.put_nowait(item) # 相当 Queue.put(item, False) 进程池进程池执行任务的本质: 从进程池中找一个空闲的进程去执行指定的任务进程池使用同步方式和异步方式执行的区别进程池有两种执行方式,即同步执行和异步执行,用同步执行的话,主进程会等待进程池里面的任务执行完毕后才开始执行主进程的任务,如果是异步执行的话,则,主进程不会理会进程池里面执行任务的情况,而是直接执行主进程里面的任务简单来说,同步执行的话,主进程会等待进程池里面的任务执行完毕,而异步执行的话,主进程是不会等待进程池里面执行任务完毕的 使用import multiprocessing # 导入模块 multiprocessing.Pool() #创建进程池, 括号内可以放上数字表示该进程池拥有的进程数量 close() # 关闭Pool,使其不再接受新的任务 terminate() # 不管任务是否完成,立即终止 join() # 主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用 apply(copy_work) # 进程池使用同步方式执行这个任务,进程池用的进程会按照一定顺序等待其它进程执行完成以后再依次执行 迭代器概念迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。我们把可以通过for...in...这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(Iterable) 可迭代对象和不可迭代对象我们把可以通过for...in...这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(Iterable) 可迭代对象: 列表,元组,字符串,字典,集合,range等 不可迭代对象: 整型,自定义的类等 判断可迭代对象from collections import Iterable isinstance([], Iterable) # 结果为True则是可迭代对象 # isinstance要传入两个参数,第一个是要判断的对象,第二个是Iterable,首字母是大写的i 判断迭代器from collections import Iterator isinstance([], Iterator) isinstance(iter([]), Iterator) # 要用iter()函数获取可迭代对象的迭代器,可迭代对象本身不是迭代器来的 可迭代对象的本质就是可以向我们提供一个 中间人即迭代器帮助我们对其进行迭代遍历使用生成器概念只要在def中有yield关键字的 就称为 生成器使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)yield有两点作用 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用 可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数) 唤醒生成器# 使用next()函数可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数) f = gen() next(f) # 使用send()函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。 f = gen() f.send('haha') # 使用__next__()方法 f = gen() f.__next__() 可迭代对象,迭代器,生成器可迭代对象:一个具备了iter方法的对象,就是一个可迭代对象迭代器:任何具有__next__()方法的对象都是迭代器, 对迭代器调用next()方法可以获取下一个值迭代器本质上是一个产生值的工厂,每次向迭代器请求下一个值,迭代器都会进行计算出相应的值并返回。生成器生成器是一个返回迭代器的函数,其实就是定义一个迭代算法,可以理解为一个特殊的迭代器。调用这个函数就得到一个迭代器,生成器中的yield相当于一个断点,执行到此返回一个值后暂停,从而实现next取值。生成器是Python中一种非常强大的特性,它让我们能够编写更加简洁的代码,同时也更加节省内存,使用CPU也更加高效总结:1.迭代器一定是迭代对象,迭代对象不一定是迭代器2.生成器一定是迭代器,迭代器不一定是生成器
2017年08月07日
834 阅读
0 评论
0 点赞
1
...
10
11
12