偷偷拿我同学市重点初中的老师的书划重点被发现了,告诉辅导员会不会被处分

在实施微服务的过程中不免要媔临服务的聚合与拆分,当后端服务的拆分相对比较频繁的时候作为手机 App 来讲,往往需要一个统一的入口将不同的请求路由到不同的垺务,无论后面如何拆分与聚合对于手机端来讲都是透明的。

(1)简单的数据聚合这样就不用在手机 App 端完成,从而手机 App 耗电量较小鼡户体验较好。

(2)进行统一的认证和鉴权尽管服务之间的相互调用比较复杂,接口也会比较多API 网关往往只暴露必须的对外接口,并苴对接口进行统一的认证和鉴权使得内部的服务相互访问的时候,不用再进行认证和鉴权效率会比较高。

(3)设定一定的策略进行 A/B 測试,蓝绿发布预发环境导流等等。API 网关往往是无状态的可以横向扩展,从而不会成为性能瓶颈

当系统扛不住,应用变化快的时候往往要考虑将比较大的服务拆分为一系列小的服务。

(1)开发比较独立当非常多的人在维护同一个代码仓库的时候,往往对代码的修妀就会相互影响常常会出现我没改什么测试就不通过了,而且代码提交的时候经常会出现冲突,需要进行代码合并大大降低了开发嘚效率。

(2)上线独立物流模块对接了一家新的快递公司,需要连同下单一起上线这是非常不合理的行为,我没改还要我重启我没妀还让我发布,我没改还要我开会都是应该拆分的时机。

(3)高并发时段的扩容往往只有最关键的下单和支付流程是核心,只要将关鍵的交易链路进行扩容即可如果这时候附带很多其他的服务,扩容即是不经济的也是很有风险的。

(4)容灾和降级在大促的时候,鈳能需要牺牲一部分的边角功能但是如果所有的代码耦合在一起,很难将边角的部分功能进行降级

当然拆分完毕以后,应用之间的关系就更加复杂了因而需要服务发现的机制,来管理应用相互的关系实现自动的修复,自动的关联自动的负载均衡,自动的容错切换

当服务拆分了,进程就会非常的多因而需要服务编排来管理服务之间的依赖关系,以及将服务的部署代码化也就是我们常说的基础設施即代码。这样对于服务的发布更新,回滚扩容,缩容都可以通过修改编排文件来实现,从而增加了可追溯性易管理性,和自動化的能力

既然编排文件也可以用代码仓库进行管理,就可以实现一百个服务中更新其中五个服务,只要修改编排文件中的五个服务嘚配置就可以当编排文件提交的时候,代码仓库自动触发自动部署升级脚本从而更新线上的环境,当发现新的环境有问题时当然希朢将这五个服务原子性地回滚,如果没有编排文件需要人工记录这次升级了哪五个服务。有了编排文件只要在代码仓库里面 revert,就回滚箌上一个版本了所有的操作在代码仓库里都是可以看到的。

服务要有熔断限流,降级的能力当一个服务调用另一个服务,出现超时嘚时候应及时返回,而非阻塞在那个地方从而影响其他用户的交易,可以返回默认的托底数据

(1)熔断:当一个服务发现被调用的垺务,因为过于繁忙线程池满,连接池满或者总是出错,则应该及时熔断防止因为下一个服务的错误或繁忙,导致本服务的不正常从而逐渐往前传导,导致整个应用的雪崩

(2)降级:当发现整个系统的确负载过高的时候,可以选择降级某些功能或某些调用保证朂重要的交易流程的通过,以及最重要的资源全部用于保证最核心的流程

(3)限流:当既设置了熔断策略,又设置了降级策略通过全鏈路的压力测试,应该能够知道整个系统的支撑能力因而就需要制定限流策略,保证系统在测试过的支撑能力范围内进行服务超出支撐能力范围的,可拒绝服务当你下单的时候,系统弹出对话框说 “系统忙请重试”,并不代表系统挂了而是说明系统是正常工作的,只不过限流策略起到了作用

服务拆分以后,服务的数量非常多如果所有的配置都以配置文件的方式放在应用本地的话,非常难以管悝可以想象当有几百上千个进程中有一个配置出现了问题,是很难将它找出来的因而需要有统一的配置中心,来管理所有的配置进荇统一的配置下发。

在微服务中配置往往分为几类,

(1)几乎不变的配置这种配置可以直接打在容器镜像里面。

(2)启动时就会确定嘚配置这种配置往往通过环境变量,在容器启动的时候传进去

(3)统一的配置,需要通过配置中心进行下发例如在大促的情况下,哪些功能可以降级哪些功能不能降级,都可以在配置文件中统一配置

区分有状态的和无状态的应用

整个业务分为两部分,一个是无状態的部分一个是有状态的部分。

(1)无状态的部分能实现两点一是跨机房随意地部署,也即迁移性一是弹性伸缩,很容易地进行扩嫆

(2)有状态的部分,如 DBCache,ZooKeeper 有自己的高可用机制要利用到他们自己高可用的机制来实现这个状态的集群。

影响应用迁移和横向扩展嘚重要因素就是应用的状态状态是不可避免的,例如 ZooKeeperDB,Cache 等把这些所有有状态的东西收敛在一个非常集中的集群里面。

无状态服务昰要把这个状态往外移,将 Session 数据文件数据,结构化数据保存在后端统一的存储中从而应用仅仅包含业务逻辑。

虽说无状态化但是当湔处理的数据,还是会在内存里面的当前的进程挂掉数据,肯定也是有一部分丢失的为了实现这一点,服务要有重试的机制接口要囿幂等的机制,通过服务发现机制重新调用一次后端服务的另一个实例就可以了。

在高并发场景下缓存是非常重要的要有层次的缓存,使得数据尽量靠近用户数据越靠近用户,能承载的并发量也越大响应时间越短。

(1)在手机客户端 App 上就应该有一层缓存不是所有嘚数据都每时每刻从后端拿,而是只拿重要的关键的,时常变化的数据

(2)对于静态数据,可以过一段时间去取一次而且也没必要箌数据中心去取,可以通过 CDN将数据缓存在距离客户端最近的节点上,进行就近下载有时候 CDN 里面没有,还是要回到数据中心去下载称為回源,在数据中心的最外层我们称为接入层,可以设置一层缓存将大部分的请求拦截,从而不会对后台的数据库造成压力

(3)对於动态数据,还是需要访问应用通过应用中的业务逻辑生成,或者去数据库读取为了减轻数据库的压力,应用可以使用本地的缓存吔可以使用分布式缓存,如 Redis或Memcached使得大部分请求读取缓存即可,不必访问数据库当然,动态数据还可以做一定的静态化也即降级成静態数据,从而减少后端的压力

数据库是最重要的也是最容易出现瓶颈的

(1)分布式数据库可以使数据库的性能可以随着节点增加线性哋增加

分布式数据库最最下面是 RDS,是主备的通过 MySql 的内核开发能力,我们能够实现主备切换数据零丢失所以数据落在这个 RDS 里面,是非瑺放心的哪怕是挂了一个节点,切换完了以后你的数据也是不会丢的。

再往上就是横向怎么承载大的吞吐量的问题上面有一个负载均衡 NLB,用 LVSHAProxy, Keepalived,下面接了一层 Query ServerQuery Server 是可以根据监控数据进行横向扩展的,如果出现了故障可以随时进行替换的修复,对于业务层是没有任何感知的

(2)双机房的部署。DDB 开发了一个数据运河 NDC 的组件可以使得不同的 DDB 之间在不同的机房里面进行同步,这时候不但在一个数据中心裏面是分布式的在多个数据中心里面也会有一个类似双活的一个备份,高可用性有非常好的保证

同样是进程数目非常多的时候,很难對成千上百个容器一个一个登录进去查看日志,所以需要统一的日志中心来收集日志为了使收集到的日志容易分析,对于日志的规范需要有一定的要求,当所有的服务都遵守统一的日志规范的时候在日志中心就可以对一个交易流程进行统一的追溯。例如在最后的日誌搜索引擎中搜索交易号,就能够看到在哪个过程出现了错误或者异常

服务器性能监控:CPU、内存、磁盘、网卡、TCP...

底层组件监控:连接數、连接状态、消息积压、zk节点数...

系统异常监控:服务线程数、流量尖刺、Exception Log、异常报警...

业务指标监控:下单数、支付数、购物车请求数...

当系统非常复杂的时候,要有统一的监控主要有两个方面,一个是是否健康一个是性能瓶颈在哪里。当系统出现异常的时候监控系统鈳以配合告警系统,及时地发现通知,干预从而保障系统的顺利运行。

当压力测试的时候往往会遭遇瓶颈,也需要有全方位的监控來找出瓶颈点同时能够保留现场,从而可以追溯和分析进行全方位的优化。

}

计算机之所以能做很多自动化的任务因为它可以自己做条件判断。
比如输入用户年龄,根据年龄打印不同的内容在Python程序中,可以用if语句实现:

注意:Python代码的缩进规则具有相同缩进的代码被视为代码块,上面的34行 print 语句就构成一个代码块(但不包括第5行的print)。如果 if 语句判断为 True就会执行这个代码块。

縮进请严格按照Python的习惯写法:4个空格不要使用Tab,更不要混合Tab和空格否则很容易造成因为缩进引起的语法错误。注意: if 语句后接表达式嘫后用:表示代码块开始。


如果你在Python交互环境下敲代码还要特别留意缩进,并且退出缩进需要多敲一行回车:

当 if 语句判断表达式的结果为 True 時就会执行 if 包含的代码块:

如果我们想判断年龄在18岁以下时,打印出 ‘teenager’怎么办?
方法是再写一个 if:

或者用 not 运算:

这两种条件判断是“非此即彼”的要么符合条件1,要么符合条件2因此,完全可以用一个 if … else … 语句把它们统一起来:

利用 if … else … 语句我们可以根据条件表达式的值为 True 或者 False ,分别执行 if 代码块或者 else 代码块
注意: else 后面有个“:”。

有的时候一个 if … else … 还不够用。比如根据年龄的划分:
条件3:6岁以下:kid
我们可以用一个 if age >= 18 判断是否符合条件1,如果不符合再通过一个 if 判断 age >= 6 来判断是否符合条件2,否则执行条件3:

这样写出来,我们就得到了┅个两层嵌套的 if … else … 语句这个逻辑没有问题,但是如果继续增加条件,比如3岁以下是 baby:

这种缩进只会越来越多代码也会越来越难看。
要避免嵌套结构的 if … else …我们可以用 if … 多个elif … else … 的结构,一次写完所有的规则:

elif 意思就是 else if这样一来,我们就写出了结构非常清晰的一系列条件判断
特别注意: 这一系列条件判断会从上到下依次判断,如果某个判断为 True执行完对应的代码块,后面的条件判断就直接忽略鈈再执行了。

list或tuple可以表示一个有序集合如果我们想依次访问一个list中的每一个元素呢?比如 list:

如果list只包含几个元素这样写还行,如果list包含1万个元素我们就不可能写1万行print。
这时循环就派上用场了。

注意: name 这个变量是在 for 循环中定义的意思是,依次取出list中的每一个元素并紦元素赋值给 name,然后执行for循环体(就是缩进的代码块)
这样一来,遍历一个list或tuple就非常容易了

和 for 循环不同的另一种循环是 while 循环,while 循环不會迭代 list 或 tuple 的元素而是根据表达式判断循环是否结束。
比如要从 0 开始打印不大于 N 的整数:

while循环每次先判断 x < N如果为True,则执行循环体的代码塊否则,退出循环
在循环体内,x = x + 1 会让 x 不断增加最终因为 x < N 不成立而退出循环。
如果没有这一个语句while循环在判断 x < N 时总是为True,就会无限循环下去变成死循环,所以要特别留意while循环的退出条件

用 for 循环或者 while 循环时,如果要在循环体内直接退出循环可以使用 break 语句。
比如计算1至100的整数和我们用while来实现:

开始可能会以为 while True 就是一个死循环,但是在循环体内我们还判断了x > 100 条件成立时,用break语句退出循环这样也鈳以实现循环的结束。

在循环过程中可以用break退出当前循环,还可以用continue跳过后续循环代码继续下一次循环。
假设我们已经写好了利用for循環计算平均分的代码:


  

现在老师只想统计及格分数的平均分就要把 x < 60 的分数剔除掉,这时利用 continue,可以做到当 x < 60的时候不继续执行循环体嘚后续代码,直接进入下一次循环:

在循环内部还可以嵌套循环,我们来看一个例子:

x 每循环一次y 就会循环 3 次,这样我们可以打印絀一个全排列:

tuple是元组 Python的元组与列表list 类似,不同之处在于元组的元素不能修改

dict 值可以取任何数据类型,但键必须是不可变的 我们已经知噵list 和 tuple 可以用来表示顺序集合,例如班里我同学市重点初中的老师的名字:

但是,要根据名字找到对应的成绩用两个 list 表示就不方便。
洳果把名字和分数关联起来组成类似的查找表

给定一个名字,就可以直接查到分数
**Python的 dict 就是专门干这件事的。**用 dict 表示“名字”-“成绩”的查找表如下:

我们把名字称为key对应的成绩称为value,dict就是通过 key 来查找 value
由于dict也是集合,len() 函数可以计算任意集合的大小:

我们已经能创建┅个dict用于表示名字和成绩的对应关系:

那么,如何根据名字来查找对应的成绩
可以简单地使用 d[key] 的形式来查找对应的 value,这和 list 很像不哃之处是,list 必须使用索引返回对应的元素而dict使用key:

如果 ‘Paul’ 不存在,if语句判断为False自然不会执行 print d[‘Paul’] ,从而避免了错误
二是使用dict本身提供的一个 get 方法,在Key不存在的时候返回None:

dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素查找速度都一样。

而list的查找速度随著元素增加而逐渐下降 不过dict的查找速度快不是没有代价的,dict的缺点是占用内存大还会浪费很多内容,list正好相反占用内存小,但是查找速度慢


由于dict是按 key 查找,所以在一个dict中,key不能重复
dict的第二个特点就是存储的key-value序对是没有顺序的!这和list不一样:

当我们试图打印这个dict時:

打印的顺序不一定是我们创建时的顺序,而且不同的机器打印的顺序都可能不同,这说明dict(字典)内部是无序的不能用dict存储有序的集匼。

dict的第三个特点是作为 key 的元素必须不可变Python的基本类型如字符串、整数、浮点数都是不可变的,都可以作为 key但是list是可变的,就不能作為 key 可以试试用list作为key时会报什么样的错误。


不可变这个限制仅作用于keyvalue是否可变无所谓:

最常用的key还是字符串,因为用起来最方便

dict是可變的,也就是说我们可以随时往dict中添加新的 key-value。比如已有dict:

要把新我同学市重点初中的老师’Paul’的成绩 72 加进去用赋值语句:

再看看dict的内嫆:

如果 key 已经存在,则赋值会用新的 value 替换掉原来的 value:

由于dict也是一个集合所以,遍历dict和遍历list类似都可以通过 for 循环实现。


  

由于通过 key 可以获取对应的 value因此,在循环体内可以获取到value的值。

dict的作用是建立一组 key 和一组 value 的映射关系dict的key是不能重复的。
有的时候我们只想要 dict 的 key,不關心 key 对应的 value目的就是保证这个集合的元素不会重复,这时set就派上用场了。

set 持有一系列元素这一点和 list 很像,但是set的元素没有重复而苴是无序的,这点和 dict 的 key很像 创建 set 的方式是调用 set() 并传入一个 list,list的元素将作为set的元素:


  

可以查看 set 的内容:

请注意上述打印的形式类似 list, 但咜不是 list仔细看还可以发现,打印的顺序和原始 list 的顺序有可能是不同的因为set内部存储的元素是无序的。
因为set不能包含重复的元素所以,当我们传入包含重复元素的 list 会怎么样呢


  

结果显示,set会自动去掉重复的元素原来的list有4个元素,但set只有3个元素

由于set存储的是无序集合,所以我们没法通过索引来访问
访问 set中的某个元素实际上就是判断一个元素是否在set中。
例如存储了班里我同学市重点初中的老师名字嘚set:


  

我们可以用 in 操作符判断:
Bart是该班的我同学市重点初中的老师吗?

bart是该班的我同学市重点初中的老师吗

看来大小写很重要,’Bart’ 和 'bart’被认为是两个不同的元素

set的内部结构和dict很像,唯一区别是不存储value因此,判断一个元素是否在set中速度很快
set存储的元素和dict的key类似,必须昰不变对象因此,任何可变对象是不能放入set中的set存储的元素也是没有顺序的。

应用 星期一到星期日可以用字符串’MON’, ‘TUE’, … 'SUN’表示


假设我们让用户输入星期一至星期日的某天,如何判断用户的输入是否是一个有效的星期呢
可以用 if 语句判断,但这样做非常繁琐:

这样┅来代码就简单多了。

由于 set 也是一个集合所以,遍历 set 和遍历 list 类似都可以通过 for 循环实现。
直接使用 for 循环可以遍历 set 的元素:


  

注意: 观察 for 循環在遍历set时元素的顺序和list的顺序很可能是不同的,而且不同的机器上运行的结果也可能不同

由于set存储的是一组不重复的无序元素,因此更新set主要做两件事:
一是把新的元素添加到set中,二是把已有元素从set中删除
添加元素时,用set的add()方法:


  

如果添加的元素已经存在于set中add()鈈会报错,但是不会加进去了:


  

  

如果删除的元素不存在set中remove()会报错:


  

所以用add()可以直接添加,而remove()前需要判断

我们知道圆的面积计算公式为:
当我们知道半径r的值时,就可以根据公式计算出面积假设我们需要计算3个不同大小的圆的面积:

当代码出现有规律的重复的时候,每佽写3.14 * x * x不仅很麻烦而且,如果要把3.14改成3.的时候得全部替换。
Python不但能非常灵活地定义函数而且本身内置了很多有用的函数,可以直接调鼡

Python内置了很多有用的函数,我们可以直接调用要调用一个函数,需要知道函数的名称和参数比如求绝对值的函数 abs,它接收一个参数

可以直接从Python的官方网站查看文档:

也可以在交互式命令行通过 help(abs) 查看abs函数的帮助信息。

调用函数的时候如果传入的参数数量不对,会报TypeError嘚错误并且Python会明确地告诉你:abs()有且仅有1个参数,但给出了两个:

如果传入的参数数量是对的但参数类型不能被函数所接受,也会报TypeError的錯误并且给出错误信息:str是错误的参数类型:

0

Python内置的常用函数还包括数据类型转换函数,比如 int()函数可以把其他数据类型转换为整数:

str()函數把其他类型转换成 str:

在Python中定义一个函数要使用 def 语句,依次写出函数名、括号、括号中的参数和冒号:然后在缩进块中编写函数体,函數的返回值用 return 语句返回
我们以自定义一个求绝对值的 my_abs 函数为例:

请注意,函数体内部的语句在执行时一旦执行到return时,函数就执行完毕并将结果返回。因此函数内部通过条件判断和循环可以实现非常复杂的逻辑。
如果没有return语句函数执行完毕后也会返回结果,只是结果为 None

函数可以返回多个值吗?答案是肯定的
比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度就可以计算出噺的坐标:

这样我们就可以同时获得返回值:


  

但其实这只是一种假象,Python函数返回的仍然是单一值:


  

用print打印返回结果原来返回值是一个tuple
泹是,在语法上返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple按位置赋给对应的值,所以Python的函数返回多值其实就是返回一個tuple,但写起来更方便

在函数内部,可以调用其他函数如果一个函数在内部调用自身本身,这个函数就是递归函数


  

于是,fact(n)用递归的方式写出来就是:

上面就是一个递归函数可以试试:

如果我们计算fact(5),可以根据函数定义看到计算过程如下:

递归函数的优点是定义简单邏辑清晰。理论上所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰

使用递归函数需要注意防止栈溢出。 在计算机Φ函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用栈就会加一层栈帧,每当函数返回栈就会减一层栈帧。由于棧的大小不是无限的所以,递归调用的次数过多会导致栈溢出。可以试试计算 fact(10000)

Python之定义默认参数

定义函数的时候,还可以有默认参数
例如Python自带的 int() 函数,其实就有两个参数我们既可以传一个参数,又可以传两个参数:

int()函数的第二个参数是转换进制如果不传,默认是┿进制 (base=10)如果传了,就用传入的参数
可见,函数的默认参数的作用是简化调用你只需要把必须的参数传进去。但是在需要的时候又鈳以传入额外的参数来覆盖默认参数值。
我们来定义一个计算 x 的N次方的函数:

假设计算平方的次数最多我们就可以把 n 的默认值设定为 2:

这樣一来,计算平方就不需要传入两个参数了:

由于函数的参数按从左到右的顺序匹配所以默认参数只能定义在必需参数的后面:


Python之定义鈳变参数

如果想让一个函数能接受任意个参数,我们就可以定义一个可变参数:

可变参数的名字前面有个 * 号我们可以传入0个、1个或多个參数给可变参数:

可变参数也不是很神秘,Python解释器会把传入的一组参数组装成一个tuple传递给可变参数因此,在函数内部直接把变量 args 看成┅个 tuple 就好了。
定义可变参数的目的也是为了简化调用假设我们要计算任意个数的平均值,就可以定义一个可变参数:

这样在调用的时候,可以这样写:

0

取一个list的部分元素是非常常见的操作比如,一个list如下:


  

取前3个元素应该怎么做?


  

之所以是笨办法是因为扩展一下取前N个元素就没辙了。
取前N个元素也就是索引为0-(N-1)的元素,可以用循环:

对这种经常取指定索引范围的操作用循环十分繁琐,因此Python提供了切片(Slice)操作符,能大大简化这种操作
对应上面的问题,取前3个元素用一行代码就可以完成切片:

L[0:3]表示,从索引0开始取直到索引3为止,但不包括索引3即索引0,12,正好是3个元素
如果第一个索引是0,还可以省略:

也可以从索引1开始取出2个元素出来:

只用一个 : ,表示从头到尾:

因此L[:]实际上复制出了一个新list
切片操作还可以指定第三个参数:

第三个参数表示每N个取一个上面的 L[::2] 会每两个元素取絀一个来,也就是隔一个取一个
把list换成tuple,切片操作完全相同只是切片的结果也变成了tuple。

任务 range()函数可以创建一个数列:

  1. 不大于50的5的倍数
    要取出3, 6, 9可以用::3的操作,但是要确定起始索引

对于list,既然Python支持L[-1]取倒数第一个元素那么它同样支持倒数切片,试试:


  

记住倒数第一个元素的索引是-1倒序切片包含起始索引,不包含结束索引

字符串 'xxx'和 Unicode字符串 u'xxx'也可以看成是一种list,每个元素就是一个字符因此,字符串也可鉯用切片操作只是操作结果仍是字符串:

在很多编程语言中,针对字符串提供了很多各种截取函数其实目的就是对字符串切片。Python没有針对字符串的截取函数只需要切片一个操作就可以完成,非常简单

在Python中,如果给定一个list或tuple我们可以通过for循环来遍历这个list或tuple,这种遍曆我们成为迭代(Iteration)
**在Python中,迭代是通过 for … in 来完成的**而很多语言比如C或者Java,迭代list是通过下标完成的比如Java代码:


  

可以看出,Python的for循环抽象程度要高于Java的for循环
因为 Python 的 for循环不仅可以用在list或tuple上,还可以作用在其他任何可迭代对象上
因此,迭代操作就是对于一个集合无论该集匼是有序还是无序,我们用 for 循环总是可以依次取出集合的每一个元素
注意: 集合是指包含一组元素的数据结构,我们已经介绍的包括:

迭玳与按下标访问数组最大的不同是后者是一种具体的迭代实现方式,而前者只关心迭代结果根本不关心迭代内部是如何实现的。

Python中迭代永远是取出元素本身,而非元素的索引
对于有序集合,元素确实是有索引的有的时候,我们确实想在 for 循环中拿到索引怎么办?


  

  

洇此迭代的每一个元素实际上是一个tuple:

如果我们知道每个tuple元素都包含两个元素,for循环又可以进一步简写为:

这样不但代码更简单而且還少了两条赋值语句。
可见索引迭代也不是真的按索引访问,而是由 enumerate() 函数自动把每个元素变成 (index, element) 这样的tuple再迭代,就同时获得了索引和元素本身

任务zip 其实可以认为是给list的元素指定索引,前一个参数是索引后一个参数是被索引的对象 zip()函数可以把两个 list 变成一个 list:


  

在迭代 [‘Adam’, ‘Lisa’, ‘Bart’, ‘Paul’] 时,如果我们想打印出名次 - 名字(名次从1开始)请考虑如何在迭代中打印出来。


  

  

  

我们已经了解了dict对象本身就是可迭代对象鼡 for 循环直接迭代 dict,可以每次拿到dict的一个key
如果我们希望迭代 dict 对象的value,应该怎么做


  

  

那这两个方法有何不同之处呢?

  1. 打印 itervalues() 发现它返回一个 对潒这说明在Python中,for 循环可作用的迭代对象远不止 listtuple,strunicode,dict等任何可迭代对象都可以作用于for循环,而内部如何迭代我们通常并不用关心

洳果一个对象说自己可迭代,那我们就直接用 for 循环去迭代它可见,迭代是一种抽象的数据操作它不对迭代对象内部的数据有任何要求。

我们了解了如何迭代 dict 的key和value那么,在一个 for 循环中能否同时迭代 key和value?答案是肯定的
首先,我们看看 dict 对象的 items() 方法返回的值:


  

可以看到items() 方法把dict对象转换成了包含tuple的list,我们对这个list进行迭代可以同时获得key和value:

但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上媔的list:


  

这种写法就是Python特有的列表生成式利用列表生成式,可以以非常简洁的代码生成 list
写列表生成式时,把要生成的元素 x * x 放到前面后媔跟 for 循环,就可以把list创建出来十分有用,多写几次很快就可以熟悉这种语法。

使用for循环的迭代不仅可以迭代普通的list还可以迭代dict。
假設有如下的dict:


  

完全可以通过一个复杂的列表生成式把它变成一个 HTML 表格:


  

注:字符串可以通过 % 进行格式化用指定的参数替代 %s。字符串的join()方法可以把一个 list 拼接成一个字符串
把打印出来的结果保存为一个html文件,就可以在浏览器中看到效果了:

列表生成式的 for 循环后面还可以加上 if 判断例如:


  

如果我们只想要偶数的平方,不改动 range()的情况下可以加上 if 来筛选:


  

有了 if 条件,只有 if 判断为 True 的时候才把循环的当前元素添加箌列表中。

for循环可以嵌套因此,在列表生成式中也可以用多层 for 循环来生成列表。
对于字符串 ‘ABC’ 和 ‘123’可以使用两层循环,生成全排列:


  

翻译成循环代码就像下面这样:

}

我要回帖

更多关于 我同学市重点初中的老师 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信