首页 文章 精选 留言 我的

精选列表

搜索[Harness工程],共10000篇文章
优秀的个人博客,低调大师

高德APP全链路源码依赖分析工程

一、背景 高德 App 经过多年的发展,其代码量已达到数百万行级别,支撑了高德地图复杂的业务功能。但与此同时,随着团队的扩张和业务的复杂化,越来越碎片化的代码以及代码之间复杂的依赖关系带来诸多维护性问题,较为突出的问题包括: 不敢轻易修改或下线对外暴露的接口或组件,因为不知道有什么地方对自己有依赖、会受到影响,于是代码变得臃肿,包大小也变得越来越大; 模块在没有变动的情况下,发布到新版本的客户端时,需要全量回归测试整个功能,因为不知道所依赖的模块是否有变动; 难以判断 Native 从业务实现转变为底层支撑的趋势是否合理,治理是否有效; 这些问题已经达到了我们必须开始治理的程度了,而解决此类问题的关键在于需要了解代码间的依赖关系。 二、高德 APP 平台架构 为了消除一些疑惑,在讨论依赖分析的实现前,先简单说明一下高德 APP 的平台架构,以便

优秀的个人博客,低调大师

PHP工程师学Python数据类型

一、背景 继上篇文章比较了PHP与Python语法之后,这周又学习了Python数据类型,准备从通过这篇文章给自己进行一些总结,也给其他读者一些参考。 二、内容概要 字符串(str) 列表(list) 元组(tup) 字典(dict) 数据操作 三、字符串(str) Python中字符串操作基本和PHP类似,下面介绍一下Python中字符串的常规操作方法 3.1 索引下标取值 在PHP中可以通过索引下标的方式获取到字符串中的某一个字符,在Python中也同样可以获取到,如下代码所示 #定义字符串 testStr = 'tangqingsong' #通过索引下标获取字符 print(testStr[1]) #打印结果 a 3.2 切片 在Python中有一个非常好用的功能叫做切片,比如当你想获取字符串中第n个字符到第m个字符中的区间字符,使用Python的切片实现非常简单,如下代码所示 #定义字符串 testStr = 'tangqingsong' #通过索引下标获取字符 print(testStr[0:4]) #打印结果 tang 3.3 循环 在Python中for不仅仅可以循环类似于PHP中的数组,还可以循环字符串,如下代码所示 testStr = 'tangqingsong' for value in testStr[0:4]: print(value) #打印结果 tang 3.4 字母大小写转换 在Python中实现字母大小写转换和PHP的写法稍有不同,Python中操作有点类似于PHP操作对象的感觉,如下代码所示 #定义字符串 testStr = 'tQs' #大写转换 aStr = testStr.upper() #小写转换 bStr = testStr.lower() print(aStr,bStr) #打印结果 TQS tqs 3.4 分割和合并 接着我们再来看一下怎么把字符串切割与合并,如下代码所示 s = 'tang|qing|song' l = s.split('|') print(l) #打印结果 ['tang', 'qing', 'song'] s2 = '|'.join(['tang', 'qing', 'song']) print(s2) #打印结果 tang|qing|song 3.5 字符串首尾过滤 在PHP中字符串首尾过滤通常使用trim()函数过滤,而Python中字符串首尾过滤的语法有点类似于PHP操作对象的方式,代码如下所示 # 去掉边界上的内容 strip s1 = ' tang qing song ' print(s1.strip()) #打印结果 ‘tang qing song’ 如果你想指定删除某一个字符,代码如下所示 s2 = '<汤青松>' print(s2.strip('>')) #打印结果 '<汤青松' 四、列表(list) 在Python中有一种叫做list的数据类型,在PHP中我们通常称之为索引数组 4.1 数据定义 定义list数据方式如下代码所示 #定义一个list数据 lst = ['张三','李四','王五','马六','田七'] 取数据方式和PHP基本一致,比如想获取lst里面的李四,可以这样获取 $name = lst[1] 4.2 切片 除了正向取数据还可以反着顺序取数据,比如你要获取马六,你可以这样写 $name = lst[-2] 在Python中有一种获取数据非常简便的方法,叫做切片,比如你想获取lst中的李四到马六区间的数据,在PHP中你得用array_slice函数去截取,但在Python则非常方便,如下代码所示 print(lst[1:4]) # 打印结果 ['李四','王五','马六'] 如果你想隔一个数据取一个数据,切片还支持设置步长,步长默认为1,也就是说连续取数据,当你设置步长后,会按照指定的步长,如下代码所示 print(lst[1:4:2]) # 打印结果 ['李四','马六'] 同样切片也支持反着取数据,比如你想获取田七到王五区间的数据,参考代码如下 print(lst[-1:-3:-1]) # 打印结果 ['田七','马六','王五'] 4.3 修改数据 在Python中如果你想向一个list数据中追加一个数据可以使用append方法向末尾增加,如下代码所示 lst = lst.append('王八') 也可以使用pop方法弹出最末尾一个数据,如下代码所示 value = lst.pop() 如果你想吧数据清空,也可以使用clear方法,当然你也可以直接将值重新赋值一个空list,如下代码所示 lst.clear() #或者 lst = [] 4.4 值的引用 在Python中需要注意一种引用内存地址的特殊情况,如下代码所示 # 定义两个变量 aList = ['张三', '李四', '王五'] bList = [] # 在bList中追加aList,此时bList为二维list bList.append(aList) #修改aList变量里面的值 aList[0] = '张三丰' #打印bList print(bList) # 打印结果 [['张三丰', '李四', '王五']] 在上面代码中可以看到,已经将一个变量赋给另外一个变量,按照常规理解来说,他们是相互独立的,但实际上并不是;在Python中如果存在二维的list,一维里面往往是记录一个内存地址,并不是把值完整的复制一份,这种引用操作Python中也称之为浅拷贝; 五、元组(tup) 在Python中有一种数据类型和list非常相似,称之为元组(tuple);它们最明显区别就是list定义之后可以修改结构,而元组定义之后不能再次修改,其次是在定义的时候有一点点不同,如下代码所示 #定义list数据 lst = ['张三', '李四', '王五'] #定义元组数据 tple ('张三', '李四', '王五') 在取数据的时候同样支持切片,也同样支持用索引(下标)方式来取值,唯一的区别就是不能再更改里面的值,比如说追加数据或者里面的某一个数据重新赋值。 六、字典 (dict ) 在PHP中我们知道数组有两种类型,索引数组和关联数组,而关联数组在Python中称之为字典,定义方式和lst区别不大,如下代码所示 6.1 数据定义 demo = { 'k1':'v1', 'k2':'v2', 'k3':'v3', } 在Python中定义字典相对PHP来说比较严格,对key有要求,不像PHP中可以只输入值而不输入可以,在Python中必须同时输入key和value。 6.2 增删改查 Python中的字典增删改查和PHP基本类似,获取字典数据参考代码如下所示 #明确存在某一个key可以这样取值,如果值不存在会报错 d['存在的key'] #不知道是否存在的情况 d.get('不知道存不存在的key') 增加数据的方式比较常规,这里不再特别说明,示例代码如下所示 #增加一项数据 data['不存在的key'] = '值' 删除数据的方式有两种形式,第一种是弹出指定数据,第二种是通过方法删除,和PHP基本类似,如下代码所示 #弹出数据 data.pop('key') #删除数据 del data['key'] 修改数据直接赋值即可,如下代码所示 # 修改数据 data['存在的key'] = 新的值 七、杂项 在Python中对数据会经常处理,这里记录三个常用的操作方法; 7,1 range 函数 有时需要定义一个列表,里面包含1~100的所有数值,在PHP中可能需要通过for循环来实现,但在Python中有一个函数range()可以创建一个整数列表,一般用在 for 循环中,如下代码所示 #range(start, stop[, step]) for i in range(0,5,1): print(i) # 打印结果 0 1 2 3 4 5 start参数代表计数从 start 开始,stop是代表计数停止的数值,step则代表一次递增几个数值 7.2 布尔型说明 在Python中的布尔值中,数字 0为 False,其他数字都为true,字符串除了''是false以外,其他非空的字符串都是true,tuple类型中除()和{}是false,其他都是true,还有Python中表示空的none也是false 7.3 数据操作 在Python中如果你想判断一个列表是否包含某一个值可以使用in方式,如下代码所示 #定义一个列表 lst = ['tang','qing','song'] #判断lst是否包含某一个值 result = 'tang' in lst print(result) #打印结果 True 如果你想知道一个list中是否不包含可以使用not in方式,如下代码所示 #定义一个列表 lst = ['tang','qing','song'] #判断lst是否不包含某一个值 result2 = 'tang' not in lst print(result2) #打印结果 False 在Python中如果你想查看一个列表的长度,可以使用len(lstt)方法 查看列表的长度 lst = ['tang','qing','song'] print(len(lst)) #打印结果 3 作者:汤青松 微信:songboy8888 更新日期:2019-07-21

优秀的个人博客,低调大师

阿里开源混沌工程工具 ChaosBlade

阿里妹导读:减少故障的最好方法就是让故障经常性的发生。通过不断重复失败过程,持续提升系统的容错和弹性能力。今天,阿里巴巴把六年来在故障演练领域的创意和实践汇浓缩而成的工具进行开源,它就是 “ChaosBlade”。如果你想要提升开发效率,不妨来了解一下。 高可用架构是保障服务稳定性的核心。 阿里巴巴在海量互联网服务以及历年双11场景的实践过程中,沉淀出了包括全链路压测、线上流量管控、故障演练等高可用核心技术,并通过开源和云上服务的形式对外输出,以帮助企业用户和开发者享受阿里巴巴的技术红利,提高开发效率,缩短业务的构建流程。 例如,借助阿里云性能测试 PTS,高效率构建全链路压测体系,通过开源组件 Sentinel 实现限流和降级功能。这一次,经历了 6 年时间的改进和实践,累计在线上执行演练场景达数万次,我们将阿里巴巴在故障演练领域的创

优秀的个人博客,低调大师

写给前端工程师的10条实用原则

译者按: 牛人都说自己是站在巨人的肩膀上,我们也要善于学习他人的经验。 原文: 10 Things You Will Eventually Learn About JavaScript Projects 译者: Fundebug 为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。 小编推荐:Fundebug专注于JavaScript、微信小程序、微信小游戏,Node.js和Java线上bug实时监控。真的是一个很好用的bug监控服务,众多大佬公司都在使用。 JavaScript编程简直就是一项冒险。当回顾工业界这10年来经过不成熟到专业的开发历程,我想每个人都会认同这个观点。 js-adventure.jpeg 前端开发有很多丰富的选择性,充分的灵活性,以及大量发挥创造力的空间。不过,同时也要求我们自己需要有足够的知识,有一定的规划和自我约束。 一路走来,我们经历了jQuery,require.js,Angularjs,React,ExtJs等等。2018年的前端开发可以说是遍地开花。 在开发过程中,你会发现有一些通用的范式可以适用于各种复杂的项目。接下来我会介绍10个重要的范式,这些都是我多年来的个人经验。虽然都是个人的观点,我相信很多有经验的开发者都会认同。这一套规则适用于任何项目、任何框架、任何大小的团队。它可以减少开发者花在文档和重构的时间、甚至开发中的争吵。 1. 分而治之(Divide and conquer) divide-and-conquer.jpeg 这个词大家并不陌生,但是很多人低估了这条规则的适用场景和能力。CommonJS,Webpack,和Node都支持我们把代码拆分到多个文件,我们为什么还需要分而治之的理念? 一致性:当代码量越来越大,将项目拆分成一个个小的文件可以让查找和以来管理变得十分容易。并且文件命名要足够直观,反应了文件中代码做的相关工作。这样可以减少耗费脑力去查找代码结构的负担。 管理便捷:代码足够模块化的拆分使得文件的移动和进一步拆分变得简单。如果你发现一个帮助函数在应用中另一个地方也需要用到,你可以创建一个名为/shared的目录,将代码放进去。这样方便共用,也方便查找。 2. 任何东西都要超级直观易懂 ** 每一个变量、函数、文件名 -- 就如同给你的孩子取名字一样认真去给他们取名字。** bad_naming.png 也许你今天通过把它命名为x节省了0.3秒的时间,但是在接下来的一个月你将会花2天的时间来搞清楚x到底指代什么,然后再花4天做重构。好好想想,不要担心命名太长。 避免使用一些奇淫技巧(即使已经足以让你申请MIT) 你的方案也许很聪明但是负责,导致的后果就是在将来,你或则团队里面的其他成员将会浪费大量时间去理解你写的那段代码兜里是如何运作的。专注于用最直观简单的方法把事情搞定,甚至不需要文档或则评论 3. 不要使用魔法数字和字符串 magic_naming.jpg 和命名的原则一样,要直观易懂!不管你觉得可能多么简单的值,也要用一个有意义的变量名来声明。 在大多数情况下,任何你声明的值很有可能在其他地方复用。因此,通过声明变量的形式,可以减少代码重复,并且易于维护。 4. 避免嵌套太深 如果你写的代码一行超过120个字符,超过500行,或则if语句超过3层,最好做拆分。 nested-if.jpeg 你可以把嵌套的if语句拆分成函数,Promises,Observables。如果你使用了很多异步调用,使用async/await也可以极大简化你的代码。 5. 早点做好配置工作 如果你的应用中使用了全局变量,API接口,第三方认证等等,把它们放到单独的配置文件中去。 不管是网页(web)还是Node,都有很多可用的包(package)来管理配置,比如config。 某种程度上说,你的应用的配置应该做到可以支持运行在生产服务器和本地开发。早点创建配置文件比后面再来做要容易很多,特别是相应的环境配置,安全配置,功能配置等等。 6. 选用合适的框架 all-frameworks.png 花时间想清楚你是否需要框架,以及使用哪个框架。终端用户不会关心你的网站或者应用使用了一个在Github上超过10w stars的框架。 根据我的个人经验,我把它们简单的做了如下分类: React: 如果你需要对整体的架构和构建有充分的控制权,React是一个很好的选择。你需要花时间去熟悉React的整个生态系统,事先做好规划。而这些都是值得的,如果你很清楚你要什么。 Angular / VueJS / Ember: 如果你想要快速实现一个可靠的Web App,就选它们吧。虽然你可能对整个架构有一些不了解。这些框架帮你做了很多事情,所以在规划的时候要想清楚使用它的优点和缺点。它们严格的目录结构虽然少了自由,但是可以让你少犯错误。 jQuery / lodash / 或则类似的: 如果你想快速实现一个网页,并且没有多少的带宽可用,那么选用它们能节省你很多时间。不过你需要小心,因为你可能写出难以维护的代码。你要注意把它们当做辅助,而不是基础。 Vanilla / 不用框架: 如果你有很多的时间来计划和开发,那么使用纯JavaScript来写是个很好的选择。你可以做一些实验性的功能,比如引入WebGL,Workers,深度优化,或则动画等等。最终,你可能甚至做出了自己的一个框架。 把这些当做建议,你需要花时间慢慢去选择使用哪个框架最适合你的项目。 7. 除非是原型,否则一定要写测试 单元测试、冒烟测试、端到端测试、合理性(Sanity)检验。除非你的项目只是一个原型用来演示,否则赶紧写测试。当你的代码库越来越复杂后,将会变得难以维护和控制。这个时候,你需要测试来帮你做检查。 test.gif 在不远的将来,当你遇到bug的时候,你会仰望蓝天,谢天谢地的感慨好在当初写了测试。你永远无法预料新引入的功能是否会默默地把你之前的代码搞挂掉。 8. 使用版本控制 git.png 不管是一个原型、大型企业项目、或则是一个个人的小项目,使用git或则其它版本管理工具,从一开始就要管理起来。每天保持提交(commit),使用分支(branch),学会合并代码(merge),解决冲突,和回退到之前提交的版本。记得提交代码的消息要认真写,不能随意乱写。 版本控制可以让你更好地管理代码,如果今天这篇文章我介绍的其它点你都忘记了,这一点一定要记住。为什么呢?因为如果你没记住其它要点,这一点可以帮你很好的管理代码,辅助解决其它问题。 9. 状态管理 使用状态管理库,并且完全利用起来。 作为一个前端开发,我们往往只需要面对两个挑战- 展示数据和存储数据。而存储数据随着项目的复杂变得越来越难,因为你很容易忽略掉。 使用状态管理,很微妙。我们的应用往往需要在客户端和服务端保持一致。我们的目标是不要在中间加上复杂性,在我们使用JavaScript处理数据的时候。组件应该展示相同的数据、将用户的更新同步,对服务的的变动做出反馈。如何做到? React有着非常丰富的选择,对于Flux的架构使用Redux,Observable-based的架构则使用Mobx。每一种都有各自的优缺点,确保在使用前充分理解。 Angular, Ember, and VueJS 各自本身就是基于状态管理设计的,不过你还是可以使用额外的库,比如ngRx, Akita和Vuex。 对于其它的框架或则Vanilla JavaScript,你可以使用Redux、Mobx,或则你自己的状态管理方案。使用状态管理的目的是保证整个应用在全局层面数据保持一致。 10. 拥抱最新并质疑 最后,积极加入社区并从中学习 -- 不过要注意每一条评论、每一篇文章、每一个对你代码的反馈,你都要认真思考并适当质疑,而不是全盘接受。积极拥抱新的想法,前端的生态演化总是很快。但是,也不要仅仅为了追逐最新的事物而追,有些东西终究会被抛弃。 question.jpg ** 一个使用老一点、成熟的框架搭建的项目会更好、更稳定,胜过同时使用两个框架,仅仅因为另一个是新的。** 我们不得不承认新的框架可能会性能更好,不过我建议可维护性排在第一位,只有当你认为真的需要迁移的时候再做迁移。 关于Fundebug Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,得到了Google、360、金山软件等众多知名用户的认可。欢迎免费试用! 版权声明: 转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2018/08/27/code-interview-data-structure/ 屏幕快照 2018-08-29 上午8.29.58.png

优秀的个人博客,低调大师

Python全栈工程师(多继承、函数重写)

ParisGabriel 每天坚持手写一天一篇 决定坚持几年 为了梦想为了信仰 开局一张图 Python人工智能从入门到精通 补充: 对象 -------------------------> 类实例变量(属性) 类变量实例方法 类方法( @classmethond) 静态方法( @staticmethond)(类内普通函数) 继承/派生 单继承: 一个子类只有一个父类 一个父类可以有多个子类 -------------------------------------------------------------------------------------------- 用于类的函数: issublclass(cls, cls_or_tuple) 判断这个类是否继承自其他类, 如果此cls是class 或tuple中的一个派生子类, 返回True 否则返回False示例: class A: pass class B(A): pass class C(B): pass issublclass(C, B) # Trueissublclass(B, C) # Falseissublclass(C, (int, str)) # Falseissublclass(C, (int, B, str)) # True 封装 enclosure 封装是指隐藏类的实现细节,让使用者不关心这些细节 封装的目的是让使用者通过尽可能少的方法(或属性)操作对象私有属性和私有方法: python类中以双下划线(__)开头, 不以双下划线结尾的标识符为私有成员,私有成员或只能用类的方法进行访问和修改 以__开头的实例变量有私有属性 以__开头的方法有私有方法 示例: class A: def __init__(self): self.__p1 = 100 # 私有属性 def show_A(self): print("self.__p1", self.__p1) self.__m1() # 可以调用自己的方法 def __m1(self): # 私有方法 print("__m1(self)方法被调用") a = A() a.show_A() # 100 # print(a.__p1) # 出错 不能在类外部访问a.__p1私有属性 也不能在子类中访问 # a.__m1() # 出错 不能在类外部访问a.__p1私有方法 也不能在子类中访问 class B(A): pass b = B() print(b.__p1) # 出错,子类不能访问父类的私有成员 b.__m1() # 出错 b._A__p1 = 200 # python的假封装可以用此方法访问 print(b.__p1) # 200 多态polymorphic: 什么是多态 就是多种状态 多态是指在继承/派生关系的类中,调用基类对象的方法, 实际能够调用子类的覆盖方法的现象叫多态 状态: 静态(编译时状态)执行速度快 动态(运行时状态)执行速度慢说明: 多态调用方法与对象相关,不与类相关 Python的全部对象只有“运行时状态(动态)” 没有C++语言里的“编译时状态(静态)” 由于Python是解释执行的 是动态 没有静态 是在运行时编译(解释执行) 示例: # Pytgon中的运行时状态 class Shape: def draw(self): print("Shape的 draw 方法被调用") class Point(Shape): def draw(self): print("画车") class Circle(Shape): def draw(self): print("画圈") # python无法实现静态 除非不出现任何覆盖 def my_draw(s): # 其他静态语言 def my_draw(Circle s) 指定调用者 无法进行改变 s.draw() # 此处显示出"动态" s1 = Circle() s2 = Point() my_draw(s1) # 只有在调用时才能能确定调用哪一个 my_draw(s2) 面向对象不是编程而是一种思想面向对象的语言的特征: 继承 封装 多态 多继承:multiple inheritance 多继承是指一个子类继承自两个或两个以上的基类 语法: class 类名(基类名1, 基类名2, ...) 说明: 1.一个子类同时继承自多个父类,父类中的方法可以同时被继承下来 2.如果两个父类中同时有同名方法,而在子类中又没有覆盖此方法时, 调用结果难以确定 (也可以确定 C3算法)示例: class Car: def run(self, speed): print("汽车", speed, "Km/h 的速度行驶") class Plane: def fly(self, height): print("飞机以海拔", height, "米高度飞行") class PlaneCar(Plane, Car): '''同时继承Plane,Car的方法''' p1 = PlaneCar() p1.fly(10000) p1.run(300) 多继承的问题(缺陷): 标识符冲突的问题 要谨慎使用继承示例: # 多继承名字冲突问题 class A: def m(self): print("A.m被调用") class B: def m(self): print("B.m被调用") class AB(A, B): # 优先调用先出现的父类 有先后顺序 pass ab = AB() ab.m() # A.m被调用 class BA(B, A): pass ba = BA() ba.m() # B.m被调用 多继承的MRO(Method Resolution Order): 类的__mro__属性 __mro__ 是一个元组 里面存放类 此属性用来记录方法查找顺序示例: class A: def go(self): print("A") class B(A): def go(self): print("B") class C(A): def go(self): print("C") class D(B, C): def go(self): print("D") super().go() d = D() d.go() # B # 多继承的super调用关系一定是mro元组内的下一个类 和子父类没关系 # 如果没有方法则报错 调用算法(C3算法) # 正常调用也是mro顺序 函数重写: 在自定义类内添加相应的方法,让自定义类创建的实例 能像内建对象一样进行内建函数操作对象转字符串函数: repr(obj) 返回一个能代表此对象的表达式字符串,通常eval(repr(obj))== obj (这个字符串通常给Python解释执行器运行用的) str(obj) 返回的字符串(这个字符串通常给人阅读用的) 对象转字符串函数的重写方法: repr(obj) 函数的重写方法: def __repr__(self): pass str(obj) 函数的重写方法: def __str__(self): pass 说明: 1.str(obj)函数先查找, obj.str()方法 调用此方法并返回结果 2.如果没有obj.__str__方法时,返回obj.__repr__() 方法的结果并返回 3.如果obj.__repr__方法不存在,则调用obj类的__repr__ 实例方法显示:<__main__.XXXX object at 0x7f4b1c36fa90>示例: class MyNumber: def __init__(self, value): '构造函数,初始化MyNumber' self.data = value def __str__(self): '''转换为人能够识别的字符串''' print("__str__方法被调用") return "自定义数字类型对象:%d" % self.data def __repr__(self): '''转换为eval能够识别的字符串''' return 'MyNumber(%d)' % self.data n1 = MyNumber(100) n2 = MyNumber(200) print("repr(n1):--->", repr(n1)) print("strr(n2):--->", str(n2)) print("strr(n2):--->", n2.__str__()) 其他内建函数的重写方法:__abs__ abs(obj) 函数__len__ len(obj) 函数(必须返回整数)__reversed__ reversed(obj) 函数(必须返回可迭代对象)__round__ round(obj) 函数 示例: # 函数重写 class MyNumber: def __init__(self, v): self.data = v def __repr__(self): return 'MyNumber(%d)' % self.data def __abs__(self): '''__abs__函数重写 求绝对值函数''' # return -self.data v = abs(self.data) return MyNumber(v) # 创建一个新的MyNumber对象 def __len__(self): '''__len__函数重写 求长度函数''' # return len(self.data) i = 0 for x in self.data: i += 1 return i i1 = MyNumber(-10) print(i1) i2 = abs(i1) print(i2) i3 = MyNumber("123d5sa") print(len(i3)) 数据转换函数的重写:__complex__ complex(obj) 函数__int__ int(obj) 函数__float__ float(obj) 函数__bool__ bool(obj) 函数 示例: 数据转换构造函数重写 class MyNumber: def __init__(self, v): self.data = v def __repr__(self): return 'MyNumber(%d)' % self.data def __int__(self): # return 999999 # 可以自定义返回规则 return self.data n1 = MyNumber(100) x = int(n1) print(type(x)) # <class 'int'> print(bool(n1)) # True n2 = MyNumber(0) print(bool(n2)) # True # 默认返回 # True 布尔测试函数重写: 格式: __bool__ 作用: 用于bool(obj)函数取值 用于if语句的真值表达式中 说明: 1.当自定义的类内有__bool__(self) 方法时,此方法的返回值为bool(obj)的返回值 2.当不存在__bool__(self),bool(x) 返回__len__(self)方法的返回值是否为零来测试布尔值 3.当不存在__len__方法时,则直接返回True示例: # bool(x)函数重写 class MyList: '''自定义类型的列表,用来保存数据,内部用列表来储存数据''' def __init__(self, iterable): self.data = [x for x in iterable] def __repr__(self): return " MyList(%s)" % self.data def __len__(self): '''返回长度''' print("__bool__方法被调用") return len(self.data) # def __bool__(self): # print("__bool__方法被调用") # return False # 此处定义所有对象返回False def __bool__(self): print("__bool__方法被调用") for x in self.data: if not x: return False return True # 自定义返回规则(这就是函数重写) myl = MyList((1, 2, -3, 4, -5, 5)) print(myl) print(bool(myl)) if myl: print("myl是真值") else: print("myl是假值") 迭代器(高级): 什么是迭代器: 可以通过next(it)函数取值的对象就是迭代器 迭代器协议: 迭代器是指对象能够使用next函数获取下一项数据, 在没有下一项数据时触发一个StopIteration异常来终止迭代的重写 迭代器协议实现方法: __next__(self) 方法来实现迭代协议 语法形式: class MyIterator: def __next__(self): 迭代器协议 return 数据什么是可迭代对象: 是指用iter(obj) 函数返回迭代对象(实例) 可迭代对象内部需要定义__iter__(self)方法来返回迭代器对象 # 此示例示意让自定义的作为可迭代对象能让 for 语句迭代访问 class MyList: '''创建MyList类''' def __init__(self, iterable=()): '''初始化self iterable:可迭代对象 ''' # 用iterable生成列表 self.data = [x for x in iterable] def __repr__(self): '''返回一个MyList字符串''' return 'MyList(%s)' % self.data def __iter__(self): '''此方法必须返回一个迭代器对象 此方法创建一个迭代器对象并返回 ''' return MyListIterator(self.data) class MyListIterator: '''此类用来创建迭代器,此类型的迭代器可以迭代访问 MyList类型的对象''' def __init__(self, lst): self.data = lst self.cur_index = 0 # 初始化迭代器的起始位置 def __next__(self): '''此方法用于实现迭代器协议''' if self.cur_index >= len(self.data): # 如果索引越界就发终止迭代通知 raise StopIteration value = self.data[self.cur_index] # 要返回的值 self.cur_index += 1 return value myl = MyList([0, -1, 2, -3]) print(myl) # it = iter(myl) # print(next(it)) for x in myl: # 迭代访问自定义类型的可迭代对象 print(x) 练习: 写一个类Bicycle类 ,有 run方法.调用时显示骑行里程km class Bicycle: def run(self, km): print('自行车骑行了', km, '公里') 再写一个类EBicycle(电动自行车类), 在Bicycle类的基础上添加了电池电量 volume 属性, 有两个方法: 1. fill_charge(self, vol) 用来充电, vol为电量 2. run(self, km) 方法每骑行10km消耗电量1度,同时显示当前电量,当电量耗尽时调用 父类的run方法继续骑行 b = EBicycle(5) # 新买的电动有内有5度电 b.run(10) # 电动骑行了10km还剩 4 度电 b.run(100) #电动骑行了40km,还剩0度电,其余60用脚登骑行 b.fill_charge(10) # 又充了10度电 b.run(50) # 骑行了50公里剩5度电 答案: class Bycycle: def run(self, km): '''自行车''' print("自行车骑行了", km, "公里") class EBycyle(Bycycle): def __init__(self, volume=0): '''初始化电动车''' self.volume = volume print("新买的电动车有", volume, "度电") def fill_charge(self, vol): '''冲电''' self.volume += vol print("又冲了", vol, "度电") def run(self, km): self.volume -= (km / 10) # 减去使用的电量 x = abs(self.volume) * 10 # 计算超出的公里 if self.volume < 0: # 判断是否超出电量 self.volume = 0 print("电动车骑行了", km, "千米 还剩", self.volume, "度电 其余", x, "千米用脚蹬") else: print("电动车骑行了", km, "千米 还剩", self.volume, "度电") b = EBycyle(10) b.run(10) b.run(100) b.fill_charge(10) b.run(50) # 新买的电动车有 10 度电 # 电动车骑行了 10 千米 还剩 9.0 度电 # 电动车骑行了 100 千米 还剩 0 度电 其余 10.0 千米用脚蹬 # 又冲了 10 度电 # 电动车骑行了 50 千米 还剩 5.0 度电 b = EBycyle(50) b.run(10) b.run(100) b.fill_charge(10) b.run(50) # 新买的电动车有 50 度电 # 电动车骑行了 10 千米 还剩 49.0 度电 # 电动车骑行了 100 千米 还剩 39.0 度电 # 又冲了 10 度电 # 电动车骑行了 50 千米 还剩 44.0 度电 练习: 1. 修改原有的学生信息管理系统, 将学生对象的,全部属性 都变为私有属性,不让外部直接访问来实现封装 源码: https://pan.baidu.com/s/1szQDS5cfzVHLlZrrJcCs8A 2. 写一个列表类MyList实现存储整数列表,写类的定义如下: class MyList: def __init__(self, iterator): self.data = ... 让此类的对象能用for语句进行迭代访问 L = MyList(range(5)) print(L) L2 = [x ** 2 for x in L] print(L2) # [0, 1, 4, 9, 16] 答案: class MyList: def __init__(self, iterable=()): self.lst = [x for x in iterable] def __repr__(self): return "%s" % self.lst def __iter__(self): return MyIterable(self.lst) class MyIterable: def __init__(self, lst): self.lst = lst self.myindex = 0 def __next__(self): if self.myindex >= len(self.lst): raise StopIteration value = self.lst[self.myindex] self.myindex += 1 return value L = MyList(range(5)) print(L) for x in L: print(x) L2 = [x ** 2 for x in L] print(L2) 3. 写一个类Fibonacci 实现迭代器协议 ,此类的对象可以作为可迭代对象生成相应的斐波那契数 1 1 2 3 5 class Fibonacci: def __init__(self, n) # n代表数据的个数 ... ... 实现如下操作: for x in Fibonacci(10): print(x) # 1 1 3 5 8 .... L = [x for x in Fibonacii(50)] print(L) F = fibonicci(30) print(sum(F)) 答案: 直接继承第二题的类 class Fibonicci(MyList): def __init__(self, n): L = [1, 1] for _ in range(n - 2): L.append(L[-1] + L[-2]) self.lst = L for x in Fibonicci(10): print(x) # 1 1 3 5 8 .... L = [x for x in Fibonicci(50)] print(L) F = Fibonicci(30) print(F) print(sum(F))

优秀的个人博客,低调大师

Python全栈工程师(迭代器、字节串)

ParisGabriel 每天坚持手写一天一篇 决定坚持几年 为了梦想为了信仰 Python人工智能从入门到精通 迭代器 Iterator: 用<>括号表示的一定是对象 什么是迭代器? 迭代器是访问可迭代对象的工具 迭代器是指用iter(obj) 函数返回的对象(实例) 迭代器可以用next(it) 函数获取可迭代对象的数据 迭代器函数iter和next iter(iterable) 从可迭代对象中返回一个迭代器,iterable 必须是能提供一个迭代器的对象 next(iterator) 从迭代器iterator中获取下一个记录,如果无法获取下一条记录,则触发StopIteration异常说明: 迭代器只能向前取值,不会后退 用iter函数可以返回一个可迭代对象的迭代器作用: 迭代器对象能用next函数获取下一个元素. 示例: L = [2, 3, 5, 7] it = iter(L) # 用L对象返回能访问L的迭代器, it绑定迭代器 next(it) # 2 next(it) # 3 next(it) # 5 next(it) # 7 next(it) # StopIteration 通知(没有数据) it = iter(range(1, 10, 30)) next(it) # 1 next(it) # 4 next(it) # 7 next(it) # StopIteration 用迭代器访问可迭代对象: L = [2, 3, 5, 7] for x in L: print(x) else: print('循环结束') it = iter(L) # 从L中获取一个迭代器 while True: try: x = next(it) print(x) except StopIteration: print("循环结束") break 生成器 Generator (python 2.5及之后)什么是生成器? 生成器是能够动态提供数据的对象,生成器对象也是可迭代对象(实例) 动态就是现用现生成数据 生成器有两种: 1. 生成器函数 2. 生成器表达式 生成器函数的定义 含有yield语句的函数是生成器函数,此函数被调用将返回一个生成器对象 yield 翻译为(产生或生成) yield 语句 语法: yield 表达式 说明: yield 用于 def 函数中,目的是将此函数作用生成器函数使用 yield 用来生成数据,供迭代器的next(it) 函数使用 yield 单步生成数据 在函数内可以一个或多少 实例: # 此示例示意用生成器函数生成一定范围内的自然数 def myinteger(n): i = 0 # 自然数从0开始 while i < n: yield i i += 1 for x in myinteger(3): print(x) 生成器函数说明: 生成器函数的调用将返回一个生成器对象,生成器对象是一个可迭代对象 在生成器函数调用return 会触发一个StopIteration异常生成器表达式: 语法: (表达式 for 变量 in 可迭代对象 [if 真值表达式 ]) 说明: if 子句可以省略 作用: 用推导式的形式创建一个新的生成器 示例: gen = (x ** 2 for x in range(1, 5)) it = iter(gen) next(it) # 1 next(it) # 4 next(it) # 9 next(it) # 16 next(it) # StopIteration迭代工具函数 迭代工具函数的作用是生成一个个性化的可迭代对象 函数:zip(iter1[, iter2[, ...]]) 返回一个zip对象,此对象用于生成元组,此元组的个数由最小的可迭代对象决定 enumerate(iterable[, start]) 生成带索引的枚举对象,返回迭代类型为索引-值对(index-value对),默认索引从零开始,也可以用start指定 示例: numbers = [10086, 10000, 10010, 9558] names = ['中国移动', '中国电信', '中国联通'] for t in zip(numbers, names): print(t) for x, y in zip(numbers, names): print(y, '的客服电话是:', x) x, y = (10086, '中国移动') # 序列赋值 zip函数的实现示例2: def myzip(iter1, iter2): it1 = iter(iter1) # 拿出一个迭代器 it2 = iter(iter2) while True: a = next(it1) b = next(it2) yield (a, b) for t in myzip(numbers, names): #能实现与zip同样的功能 print(t) enumerate 示例: names = ['中国移动', '中国电信', '中国联通'] for t in enumerate(names): print(t) enumerate 实现方法示意: def myenum(iterable): it = iter(iterable) i = 0 while True: a = next(it) yield (i, a) i += 1 字节串和字节数组 字节串bytes (也叫字节序列) 作用: 存储以字节为单位的数据 字节串是不可变的字节序列 字节: 字节是由8个位(bit)组成的数据单位,是计算机进行数据管理的单位 字节是用 0 ~ 255 范围内的整数表示的 创建空字节串的字面值 B = b'' B = b"" B = b'''''' B = b"""""" 创建非空字节串的字面值 B = b'ABCD' B = b"ABCD" B = b'\x41\x42' 字节串的构造函数 bytes bytes() 生成一个空的字节串 等同于 b'' bytes(整数可迭代对象) # 用可迭代对象初始化一个字节串 bytes(整数n) 生成n个值为0的字节串 bytes(字符串, encoding='utf-8') 用字符串转为编码生成一个字节串 示例: b = bytes() # b = b'' b = bytes(range(65, 69)) # b = b'ABCD' b = bytes(5) # b = b'\x00\x00\x00\x00\x00' b = bytes('abc中文') # b=b'ABC\xe4\xb8\xad\xe6\x96\x87' bytes 的运算: + += * *= < <= > >= == != in / not in 索引和切片 len(x) max(x) min(x) sum(x) any(x) all(x) bytes 和 str 的区别: bytes 存储字节( 通常值在 range(0, 256)) str 存储unicode字符( 通常值在0~65535) bytes 与 str 的转换 编码(encode) str ------------> bytes b = s.encode(encoding='utf-8') 解码(decode) bytes ----------> str s = b.decode(encoding='utf-8') 字节数组 bytearray可变的字节序列 字节数组的构造函数: bytearray bytearray() 创建空的字节数组 bytearray(整数) 用可迭代对象初始化一个字节数组 bytearray(整型可迭代对象) 生成n个值为0的字节数组 bytearray(字符串, encoding='utf-8') 用字符串的转换编码生成一个字节数组 bytearray 的运算: + += * *= < <= > >= == != in / not in 索引和切片 (字节数组支持索引和切片的赋值操作,规则同列表的索引和切片赋值规则) 例: ba = bytearray(b'aBCDEfG') ba[0] = 65 ba[-2] = 70 bytearray的方法: BA.clear() 清空 BA.append(n) 追加一个字节(n为0~255的整数) BA.remove(value) 删除第一个出现的字节,如果没有出现,则触发ValueError错误 BA.reverse() 字节顺序反转 BA.decode(encoding='utf-8') # 解码为字符串 BA.find(sub[, start[,end]]) # 查找 sub 练习: 有一个集合: s = {'唐僧', '悟空', '八戒', '沙僧'} 用 for语句来遍历所有元素如下: for x in s: print(x) else: print('遍历结束') 请将上面的for语句改写为 用while语句和迭代器实现 练习: 写一个生成器函数 myeven(start, stop) 此函数用来生成从 start开始到stop结束(不包含)区间内的一系列偶数 def myeven(start, stop): .... evens = list(myeven(10, 20)) print(evens) # [10, 12, 14, 16, 18] for x in myeven(21, 30): print(x) # 22, 24, 26, 28 L = [x**2 for x in myeven(3, 10)] print(L) # 16 36 64 练习: 已知有一个列表L L = [2, 3, 5, 7] 用生成器表达式从此列表中拿到数,生成 列表中数据的平方 gen = ...... # 此处用生成器表达式实现 L2 = list(gen) # L2 = [4, 9, 25, 49] 练习: 写一个程序,读入任意行的文字,当输入空行时结束输入 打印带有行号的输入结果: 如: 请输入: hello<回车> 请输入: world<回车> 请输入: tarena<回车> 请输入: <回车> # 直接回车结束输入 输出如下: 第1行: hello 第2行: world 第3行: tarena 练习: 写一个程序,从键盘输入一段字符串存入s变量 1. 将此字符串转为字节串用变量b绑定,并打印出b 2. 打印字符串s的长度和字节串b的长度 3. 将b字节串再转换为字符串用变量s2 绑定,判断 s2 和 s是否相同? s = input("please input string:") b = s.encode("utf-8") print(s) print(b) print(len(s)) print(len(b)) s2 = b.decode("utf-8") if s2 == s: print("相等") 练习: 1. 写一个生成器函数primes生成素数, 此生成器函数为 primes(begin, end) 如: [x for x in primes(10, 20)] 将得到列表 [11, 13, 17, 19] 答案: def get_ss(x): if x <= 0: return False for i in range(2, x): if x % i == 0: return False return True def primes(begin, end): if begin <= 2or end <= 2: pass for x in range(begin, end): if get_ss(x): yield x L = [x for x in primes(10, 20)] print(L) 2. 写一个生成器函数,生成斐波那契数列的前n个数 1 1 2 3 5 8 13 def fibonacci(n): ... yield... 1) 输出前20个数: for x in fibonacci(20): print(x) 2) 打印前40个数的和: print(sum(fibonacci(40))) 答案: def fibonacci(n): L = [1, 1] for x in range(n): s = L[x] + L[x + 1] L.append(s) return L print(fibonacci(20)) print(sum(fibonacci(40))) 3. 写 程序打印杨辉三角(只打印6层) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 答案: def yh_sj(): L = [1] while True: yield L L.append(0) L = [L[x - 1] + L[x] for x in range(len(L))] def lst(): i = 0 for x in yh_sj(): print(str(x).center(50)) if i == 10: break i += 1 思考: L = [2, 3, 5, 7] L2 = [x ** 2 for x in L] # 列表推导式 it = iter(L2) print(next(it)) # 4 L[1] = 10 print(next(it)) # 9 L = [2, 3, 5, 7] G3 = (x ** 2 for x in L) # 生成器表达式 it = iter(G3) print(next(it)) # 4 L[1] = 10 print(next(it)) # 100 生成器是动态的现用现去 跟着数据变化所变化

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册