用python asyncio推导思维逻辑题,哪位小姐养蛇?

大家好我是木语老师,新年新气象,在这里祝大家新年愉快,虎虎生威,虎年大吉!数据分析人人都有必要掌握一点,哪怕只是思维也行。下面探讨Python数据分析需要学习的知识范畴,结合自己的经历和理解,总结的学习大纲,有些章节带有解释,有些没有。当然,关于学习范畴,可能每个人的理解都不太一样,以下仅供参考。1 数据分析思维数据分析属于分析思维的一个子类,有专门的数据方法论。只有先养成正确的分析思维,才能使用好数据。大多数人的思维方式都依赖于生活和经验做出直觉性的判断,最直观的体现是,在数据和业务分析中有时无从下手。什么是好的分析思维?用两张在网络上流传甚广的图片说明思维模式(图片来源网络)对应以下两种思维:我们12月的销售额度下降,我想是因为年终的影响,我问了几个销售员,他们都说年终生意不太好做,各家都收紧了财务预算,谈下的几家费用也比以前有缩水。我对他们进行了电话拜访,厂家都说经济不景气,希望我们价格方面再放宽点。我们12月的销售额度下降,低于去年同期和今年平均值,可以排除掉大环境的因素。其中A地区下降幅度最大,间接影响了整体销售额。通过调查发现,A地区的市场因为竞争对手涌入,进行了低价销售策略。除此之外,B地区的经济发展低于预期发展,企业缩减投入。第一个分析思维是依赖经验和直觉的线性思维,第二个分析思维则注重逻辑推导,属于结构化的思维。两种思维往往会导致不同的结果。1.1 金子塔原理麦肯锡思维中很重要的一条原理叫做金字塔原理,它的核心是层次化思考、逻辑化思考、结构化思考。1.1.1 什么是金字塔?任何一件事情都有一个中心论点,中心论点可以划分成3~7个分论点,分论点又可以由3~7个论据支撑。层层拓展,这个结构由上至下呈金字塔状。1.1.2 结构化思维金字塔(图片来源网络)1.1.3 核心法则:MECE金字塔原理有一个核心法则MECE,全称 Mutually Exclusive Collectively Exhaustive,论点相互独立,尽可能多的列举。1.1.4 假设先行首先得有一个思考作为开始。这是什么意思?因为金字塔是从上而下,需要有一个中心论点,也就是塔尖。我们可以先提出一个问题,比如此产品的核心功能是某某功能吗?1.2 二八法则1.2.1 20%的分析过程决定80%的分析结果1.2.2 抓住关键因素以上节选的两个分析思维,都能在麦肯锡问题分析与解决技巧中找到原型,感兴趣的可查看下面这本书。2 数据获取2.1 大数据平台提取各个公司都可能有自己专属的大数据平台,进入公司要首先掌握如何从这上面拿去我们需要的业务数据2.2 第三方服务接口合作企业或公司购买的服务接口,我们可以直接调用拿到数据。2.3 开源公开数据集推荐一些数据集2.4 爬虫爬取网站数据python的常用包:requestsjsonBeautifulSouprequests库就是用来进行网络请求的,说白了就是模拟浏览器来获取资源。由于我们采集的是api接口,它的格式为json,所以要用到json库来解析。BeautifulSoup是用来解析html文档的,可以很方便的帮我们获取指定div的内容。3 数据存储3.1 SQL分组,聚合,多表join操作groupby, aggregate,join操作join操作可参考 Python与算法社区 公众号3.2 大数据平台Hadoop大数据架构,分布式存储,详细自行查阅3.3 Mysql这个大家应该都不陌生3.4 hive 拉链表拉链表的知识大家需要好好理解体会,dp 的状态 active 和 history4 数据清理知识4.1 理解数据背后的业务,千万不要忽视!我们在拿到需要分析的数据后,千万不要急于立刻开始做回归、分类、聚类分析。第一步应该是认真理解业务数据,可以试着理解去每个特征,观察每个特征,理解它们对结果的影响程度。然后,慢慢研究多个特征组合后,它们对结果的影响。4.2 明确各个特征的类型如果这些数据类型不是算法部分期望的数据类型,你还得想办法编码成想要的。比如常见的数据自增列 id 这类数据,是否有必要放到你的算法模型中,因为这类数字很可能被当作数字读入。某些列的取值类型,虽然已经是数字了,它们的取值大小表示什么含义你也要仔细捉摸。因为,数字的相近相邻,并不一定代表另一种层面的相邻。4.3 找出异常数据统计中国家庭人均收入时,如果源数据里面,有王建林,马云等这种富豪,那么,人均收入的均值就会受到极大的影响,这个时候最好,绘制箱形图,看一看百分位数。4.4 处理缺失值现实生产环境中,拿到的数据恰好完整无损、没有任何缺失数据的概率,和买彩票中将的概率差不多。数据缺失的原因太多了,业务系统版本迭代, 之前的某些字段不再使用了,自然它们的取值就变为 null 了;再或者,压根某些数据字段在抽样周期里,就是没有写入数据……4.5 头疼的数据不均衡问题理论和实际总是有差距的,理论上很多算法都存在一个基本假设,即数据分布总是均匀的。这个美好的假设,在实际中,真的存在吗?很可能不是!算法基于不均衡的数据学习出来的模型,在实际的预测集上,效果往往差于训练集上的效果,这是因为实际数据往往分布得很不均匀,这时候就要考虑怎么解决这些问题。下面是一本数据清洗不错的书籍:5 Python核心知识5.1 理解Python的解释性Python 是解释型语言,对于 Python 刚刚入门的小伙伴,可能对解释性有些疑惑。不过,没关系,我们可以通过大家已经熟悉的编译型语言,来帮助我们理解 Python 的解释性。编译型语言,如 C++、Java,它们会在编译阶段做类型匹配检查等,因此,数据类型不匹配导致的编译错误,在编译阶段就会被检查出来,例如:Intger a = 0;Double b = 0.0;a = b; // Double类型的变量 b 试图赋值给 Integer 型的变量 a, 编译报错// 因为 Integer 类型 和 Double 类型 不存在继承关系,// 类型不能互转但是,Python 就不会在编译阶段做类型匹配检查,比如,Python 实现上面的几行语句,会这样写:a = 0 # 不做任何类型声明b = 0.a = b # 这种赋值,Python 会有问题吗?答案是不会的。此处就体现了 Python 的解释特性,当我们把 0 赋值给 a 时,Python 解释器会把它 a 解释为 int 型,可以使用内置函数 type(variable) 显示地检查 variable 的类型:In [70]: type(a)Out[70]: intIn [69]: type(b)Out[69]: floatIn [71]: a = b # 在把 float 型 b 赋值给 a 后, # a 就被解释为floatIn [72]: type(a)Out[72]: float在把 float 型 b 赋值给 a 后, a 就被解释为 float.5.2 list,dict,tuple,set深拷贝和浅拷贝的区别5.3 Python列表生成式如何灵活使用5.4 Python函数式编程闭包问题5.5 位置参数和关键字参数如果介绍 Python 入门,不介绍函数的位置参数 ( positional argument ) 和关键字参数( keyword argument ) ,总是感觉缺少点什么,它们在 Python 函数中到处可见,理解和使用它们,为我们日后深入 Python 打下坚实的根基。6 Excel数据分析6.1 Excel处理10万条以内数据6.2 以SUM函数为首的求和家族6.3 以VLOOKUP函数为首的查找家族6.4 以IF函数为首的逻辑函数家族大家自行查阅学习7 Pandas数据预处理7.1 基于Python的向量化增强7.2 必须掌握的传播机制广播发生的条件7.3 一维Series和二维DataFrame7.4 Pandas中的20个统计学函数20个统计学函数7.5 Pandas三个函数搞定缺失值7.6 1个函数搞定数据透视8 数据建模分析8.1 统计学基础知识首先,入门数据分析需要必备一些统计学的基本知识,在这里我们简单列举几个入门级的重要概念。概率,平均值,中位数,众数,四分位数,期望,标准差,方差。在这些基本概念上,又衍生出的很多重要概念,比如协方差,相关系数等。这一些列常用的统计指标,都在强大的数据分析包 Pandas 中实现了,非常方便。8.2 统计量描述说统计学是一种基于事实的演绎学问,它是严谨的,可以给出确切解释的。不过,机器学习就不一样了,它是一门归纳思想的学问,比如深度学习得出的模型,你就很难解释其中的具体参数为什么取值为某某某。它的应用在于可以提供一种预测,给我们未来提供一种建设性的指导。数据分析师需要了解机器学习的基本理论、常见的那十几种算法,这样对于我们做回归、分类、聚类分析,都是不可缺少的。8.3 机器学习回归分析三 个假定是?如何建立线性回归模型?最大似然估计求参数?梯度下降求解优化问题?手写不调包实现的 5 个算子手写不调包实现的整体算法框架8.4 基本的分类、聚类算法高斯混合模型:聚类原理分析高斯混合模型:聚类求解高斯混合模型:求解完整代码高斯混合模型:不调包多维数据聚类分析K-Means算法8.5 特征工程提高分析精度一般来说,特征工程大体上可以分为三个方面,一是特征构造,二是特征选择,三是特征生成。9 数据可视化9.1 必备的绘图原理知识拿使用较多的 matplotlib 为列,整个图像为一个Figure 对象,在 Figure 对象中可以包含一个或多个 Axes对象,每个Axes对象都是一个拥有自己坐标系统的绘图区域。Axes 由 xaxis, yaxis, title, data 构成,xaxis 由坐标轴的线 ,tick以及label构成。9.2 matplotlib绘图9.3 绘图必备100行代码参考:关于数据分析的学习路线,我准备写一篇 2 万+的 chat10 数据挖掘分析10.1 正则表达式学习正则表达式语法,主要就是学习元字符以及它们在正则表达式上下文中的行为。常见的元字符比如普通字符、标准字符、特殊字符、限定字符(又叫量词)、定位字符(也叫边界字符)。10.2 决策树决策树对决策树剪枝sklearn分类和回归提炼出分类器算法10.3 贝叶斯方法朴素贝叶斯分类器:例子解释朴素贝叶斯分类:拉普拉斯修正单词拼写纠正器python实现半朴素贝叶斯分类器10.4 集成学习方法XGBoost思想XGBoost模型构造XGBoost 安装及实战应用 10.5 NLP一文了解自然语言处理的每个范畴用到的核心技术,难点和热点(1)NLP入门:CNN,RNN应用文本分类,个性化搜索,苹果和乔布斯关系抽取(2)
题目001: 在Python中如何实现单例模式。点评:单例模式是指让一个类只能创建出唯一的实例,这个题目在面试中出现的频率极高,因为它考察的不仅仅是单例模式,更是对Python语言到底掌握到何种程度,建议大家用装饰器和元类这两种方式来实现单例模式,因为这两种方式的通用性最强,而且也可以顺便展示自己对装饰器和元类中两个关键知识点的理解。方法一:使用装饰器实现单例模式。from functools import wraps
def singleton(cls):
"""单例类装饰器"""
instances = {}
@wraps(cls)
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class President:
pass
扩展:装饰器是Python中非常有特色的语法,用一个函数去装饰另一个函数或类,为其添加额外的能力。通常通过装饰来实现的功能都属横切关注功能,也就是跟正常的业务逻辑没有必然联系,可以动态添加或移除的功能。装饰器可以为代码提供缓存、代理、上下文环境等服务,它是对设计模式中代理模式的践行。在写装饰器的时候,带装饰功能的函数(上面代码中的wrapper函数)通常都会用functools模块中的wraps再加以装饰,这个装饰器最重要的作用是给被装饰的类或函数动态添加一个__wrapped__属性,这个属性会将被装饰之前的类或函数保留下来,这样在我们不需要装饰功能的时候,可以通过它来取消装饰器,例如可以使用President = President.__wrapped__来取消对President类做的单例处理。需要提醒大家的是:上面的单例并不是线程安全的,如果要做到线程安全,需要对创建对象的代码进行加锁的处理。在Python中可以使用threading模块的RLock对象来提供锁,可以使用锁对象的acquire和release方法来实现加锁和解锁的操作。当然,更为简便的做法是使用锁对象的with上下文语法来进行隐式的加锁和解锁操作。方法二:使用元类实现单例模式。class SingletonMeta(type):
"""自定义单例元类"""
def __init__(cls, *args, **kwargs):
cls.__instance = None
super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__call__(*args, **kwargs)
return cls.__instance
class President(metaclass=SingletonMeta):
pass
扩展:Python是面向对象的编程语言,在面向对象的世界中,一切皆为对象。对象是通过类来创建的,而类本身也是对象,类这样的对象是通过元类来创建的。我们在定义类时,如果没有给一个类指定父类,那么默认的父类是object,如果没有给一个类指定元类,那么默认的元类是type。通过自定义的元类,我们可以改变一个类默认的行为,就如同上面的代码中,我们通过元类的__call__魔术方法,改变了President类的构造器那样。补充:关于单例模式,在面试中还有可能被问到它的应用场景。通常一个对象的状态是被其他对象共享的,就可以将其设计为单例,例如项目中使用的数据库连接池对象和配置对象通常都是单例,这样才能保证所有地方获取到的数据库连接和配置信息是完全一致的;而且由于对象只有唯一的实例,因此从根本上避免了重复创建对象造成的时间和空间上的开销,也避免了对资源的多重占用。再举个例子,项目中的日志操作通常也会使用单例模式,这是因为共享的日志文件一直处于打开状态,只能有一个实例去操作它,否则在写入日志的时候会产生混乱。题目002:不使用中间变量,交换两个变量`a`和`b`的值。点评:典型的送人头的题目,通常交换两个变量需要借助一个中间变量,如果不允许使用中间变量,在其他编程语言中可以使用异或运算的方式来实现交换两个变量的值,但是Python中有更为简单明了的做法。方法一:a = a ^ b
b = a ^ b
a = a ^ b
方法二:a, b = b, a
扩展:需要注意,a, b = b, a这种做法其实并不是元组解包,虽然很多人都这样认为。Python字节码指令中有ROT_TWO指令来支持这个操作,类似的还有ROT_THREE,对于3个以上的元素,如a, b, c, d = b, c, d, a,才会用到创建元组和元组解包。想知道你的代码对应的字节码指令,可以使用Python标准库中dis模块的dis函数来反汇编你的Python代码。题目003:写一个删除列表中重复元素的函数,要求去重后元素相对位置保持不变。点评:这个题目在初中级Python岗位面试的时候经常出现,题目源于《Python Cookbook》这本书第一章的第10个问题,有很多面试题其实都是这本书上的原题,所以建议大家有时间好好研读一下这本书。def dedup(items):
no_dup_items = []
seen = set()
for item in items:
if item not in seen:
no_dup_items.append(item)
seen.add(item)
return no_dup_items
如果愿意也可以把上面的函数改造成一个生成器,代码如下所示。def dedup(items):
seen = set()
for item in items:
if item not in seen:
yield item
seen.add(item)
扩展:由于Python中的集合底层使用哈希存储,所以集合的in和not in成员运算在性能上远远优于列表,所以上面的代码我们使用了集合来保存已经出现过的元素。集合中的元素必须是hashable对象,因此上面的代码在列表元素不是hashable对象时会失效,要解决这个问题可以给函数增加一个参数,该参数可以设计为返回哈希码或hashable对象的函数。题目004:假设你使用的是官方的CPython,说出下面代码的运行结果。点评:下面的程序对实际开发并没有什么意义,但却是CPython中的一个大坑,这道题旨在考察面试者对官方的Python解释器到底了解到什么程度。a, b, c, d = 1, 1, 1000, 1000
print(a is b, c is d)
def foo():
e = 1000
f = 1000
print(e is f, e is d)
g = 1
print(g is a)
foo()
运行结果:True False
True False
True
上面代码中a is b的结果是True但c is d的结果是False,这一点的确让人费解。CPython解释器出于性能优化的考虑,把频繁使用的整数对象用一个叫small_ints的对象池缓存起来造成的。small_ints缓存的整数值被设定为[-5, 256]这个区间,也就是说,在任何引用这些整数的地方,都不需要重新创建int对象,而是直接引用缓存池中的对象。如果整数不在该范围内,那么即便两个整数的值相同,它们也是不同的对象。CPython底层为了进一步提升性能还做了另一个设定,对于同一个代码块中值不在small_ints缓存范围内的整数,如果同一个代码块中已经存在一个值与其相同的整数对象,那么就直接引用该对象,否则创建新的int对象。需要大家注意的是,这条规则对数值型适用,但对字符串则需要考虑字符串的长度,这一点大家可以自行证明。扩展:如果你用PyPy(另一种Python解释器实现,支持JIT,对CPython的缺点进行了改良,在性能上优于CPython,但对三方库的支持略差)来运行上面的代码,你会发现所有的输出都是True。题目005:Lambda函数是什么,举例说明的它的应用场景。点评:这个题目主要想考察的是Lambda函数的应用场景,潜台词是问你在项目中有没有使用过Lambda函数,具体在什么场景下会用到Lambda函数,借此来判断你写代码的能力。因为Lambda函数通常用在高阶函数中,主要的作用是通过向函数传入函数或让函数返回函数最终实现代码的解耦合。Lambda函数也叫匿名函数,它是功能简单用一行代码就能实现的小型函数。Python中的Lambda函数只能写一个表达式,这个表达式的执行结果就是函数的返回值,不用写return关键字。Lambda函数因为没有名字,所以也不会跟其他函数发生命名冲突的问题。扩展:面试的时候有可能还会考你用Lambda函数来实现一些功能,也就是用一行代码来实现题目要求的功能,例如:用一行代码实现求阶乘的函数,用一行代码实现求最大公约数的函数等。fac = lambda x: __import__('functools').reduce(int.__mul__, range(1, x + 1), 1)gcd = lambda x, y: y % x and gcd(y % x, x) or xLambda函数其实最为主要的用途是把一个函数传入另一个高阶函数(如Python内置的filter、map等)中来为函数做解耦合,增强函数的灵活性和通用性。下面的例子通过使用filter和map函数,实现了从列表中筛选出奇数并求平方构成新列表的操作,因为用到了高阶函数,过滤和映射数据的规则都是函数的调用者通过另外一个函数传入的,因此这filter和map函数没有跟特定的过滤和映射数据的规则耦合在一起。items = [12, 5, 7, 10, 8, 19]
items = list(map(lambda x: x ** 2, filter(lambda x: x % 2, items)))
print(items)
# [25, 49, 361]
扩展:用列表的生成式来实现上面的代码会更加简单明了,代码如下所示。items = [12, 5, 7, 10, 8, 19]items = [x ** 2 for x in items if x % 2]print(items)
# [25, 49, 361]题目006:说说Python中的浅拷贝和深拷贝。点评:这个题目本身出现的频率非常高,但是就题论题而言没有什么技术含量。对于这种面试题,在回答的时候一定要让你的答案能够超出面试官的预期,这样才能获得更好的印象分。所以回答这个题目的要点不仅仅是能够说出浅拷贝和深拷贝的区别,深拷贝的时候可能遇到的两大问题,还要说出Python标准库对浅拷贝和深拷贝的支持,然后可以说说列表、字典如何实现拷贝操作以及如何通过序列化和反序列的方式实现深拷贝,最后还可以提到设计模式中的原型模式以及它在项目中的应用。浅拷贝通常只复制对象本身,而深拷贝不仅会复制对象,还会递归的复制对象所关联的对象。深拷贝可能会遇到两个问题:一是一个对象如果直接或间接的引用了自身,会导致无休止的递归拷贝;二是深拷贝可能对原本设计为多个对象共享的数据也进行拷贝。Python通过copy模块中的copy和deepcopy函数来实现浅拷贝和深拷贝操作,其中deepcopy可以通过memo字典来保存已经拷贝过的对象,从而避免刚才所说的自引用递归问题;此外,可以通过copyreg模块的pickle函数来定制指定类型对象的拷贝行为。deepcopy函数的本质其实就是对象的一次序列化和一次返回序列化,面试题中还考过用自定义函数实现对象的深拷贝操作,显然我们可以使用pickle模块的dumps和loads来做到,代码如下所示。import pickle
my_deep_copy = lambda obj: pickle.loads(pickle.dumps(obj))
列表的切片操作[:]相当于实现了列表对象的浅拷贝,而字典的copy方法可以实现字典对象的浅拷贝。对象拷贝其实是更为快捷的创建对象的方式。在Python中,通过构造器创建对象属于两阶段构造,首先是分配内存空间,然后是初始化。在创建对象时,我们也可以基于“原型”对象来创建新对象,通过对原型对象的拷贝(复制内存)就完成了对象的创建和初始化,这种做法更加高效,这也就是设计模式中的原型模式。在Python中,我们可以通过元类的方式来实现原型模式,代码如下所示。import copy
class PrototypeMeta(type):
"""实现原型模式的元类"""
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
# 为对象绑定clone方法来实现对象拷贝
cls.clone = lambda self, is_deep=True: \
copy.deepcopy(self) if is_deep else copy.copy(self)
class Person(metaclass=PrototypeMeta):
pass
p1 = Person()
p2 = p1.clone()
# 深拷贝
p3 = p1.clone(is_deep=False)
# 浅拷贝
题目007:Python是如何实现内存管理的?点评:当面试官问到这个问题的时候,一个展示自己的机会就摆在面前了。你要先反问面试官:“你说的是官方的CPython解释器吗?”。这个反问可以展示出你了解过Python解释器的不同的实现版本,而且你也知道面试官想问的是CPython。当然,很多面试官对不同的Python解释器底层实现到底有什么差别也没有概念。所以,千万不要觉得面试官一定比你强,怀揣着这份自信可以让你更好的完成面试。Python提供了自动化的内存管理,也就是说内存空间的分配与释放都是由Python解释器在运行时自动进行的,自动管理内存功能极大的减轻程序员的工作负担,也能够帮助程序员在一定程度上解决内存泄露的问题。以CPython解释器为例,它的内存管理有三个关键点:引用计数、标记清理、分代收集。引用计数:对于CPython解释器来说,Python中的每一个对象其实就是PyObject结构体,它的内部有一个名为ob_refcnt 的引用计数器成员变量。程序在运行的过程中ob_refcnt的值会被更新并藉此来反映引用有多少个变量引用到该对象。当对象的引用计数值为0时,它的内存就会被释放掉。typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
以下情况会导致引用计数加1:对象被创建对象被引用对象作为参数传入到一个函数中对象作为元素存储到一个容器中以下情况会导致引用计数减1:用del语句显示删除对象引用对象引用被重新赋值其他对象一个对象离开它所在的作用域持有该对象的容器自身被销毁持有该对象的容器删除该对象可以通过sys模块的getrefcount函数来获得对象的引用计数。引用计数的内存管理方式在遇到循环引用的时候就会出现致命伤,因此需要其他的垃圾回收算法对其进行补充。标记清理:CPython使用了“标记-清理”(Mark and Sweep)算法解决容器类型可能产生的循环引用问题。该算法在垃圾回收时分为两个阶段:标记阶段,遍历所有的对象,如果对象是可达的(被其他对象引用),那么就标记该对象为可达;清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收。CPython底层维护了两个双端链表,一个链表存放着需要被扫描的容器对象(姑且称之为链表A),另一个链表存放着临时不可达对象(姑且称之为链表B)。为了实现“标记-清理”算法,链表中的每个节点除了有记录当前引用计数的ref_count变量外,还有一个gc_ref变量,这个gc_ref是ref_count的一个副本,所以初始值为ref_count的大小。执行垃圾回收时,首先遍历链表A中的节点,并且将当前对象所引用的所有对象的gc_ref减1,这一步主要作用是解除循环引用对引用计数的影响。再次遍历链表A中的节点,如果节点的gc_ref值为0,那么这个对象就被标记为“暂时不可达”(GC_TENTATIVELY_UNREACHABLE)并被移动到链表B中;如果节点的gc_ref不为0,那么这个对象就会被标记为“可达“(GC_REACHABLE),对于”可达“对象,还要递归的将该节点可以到达的节点标记为”可达“;链表B中被标记为”可达“的节点要重新放回到链表A中。在两次遍历之后,链表B中的节点就是需要释放内存的节点。分代回收:在循环引用对象的回收中,整个应用程序会被暂停,为了减少应用程序暂停的时间,Python 通过分代回收(空间换时间)的方法提高垃圾回收效率。分代回收的基本思想是:对象存在的时间越长,是垃圾的可能性就越小,应该尽量不对这样的对象进行垃圾回收。CPython将对象分为三种世代分别记为0、1、2,每一个新生对象都在第0代中,如果该对象在一轮垃圾回收扫描中存活下来,那么它将被移到第1代中,存在于第1代的对象将较少的被垃圾回收扫描到;如果在对第1代进行垃圾回收扫描时,这个对象又存活下来,那么它将被移至第2代中,在那里它被垃圾回收扫描的次数将会更少。分代回收扫描的门限值可以通过gc模块的get_threshold函数来获得,该函数返回一个三元组,分别表示多少次内存分配操作后会执行0代垃圾回收,多少次0代垃圾回收后会执行1代垃圾回收,多少次1代垃圾回收后会执行2代垃圾回收。需要说明的是,如果执行一次2代垃圾回收,那么比它年轻的代都要执行垃圾回收。如果想修改这几个门限值,可以通过gc模块的set_threshold函数来做到。题目008:说一下你对Python中迭代器和生成器的理解。点评:很多人面试者都会写迭代器和生成器,但是却无法准确的解释什么是迭代器和生成器。如果你也有同样的困惑,可以参考下面的回答。迭代器是实现了迭代器协议的对象。跟其他编程语言不通,Python中没有用于定义协议或表示约定的关键字,像interface、protocol这些单词并不在Python语言的关键字列表中。Python语言通过魔法方法来表示约定,也就是我们所说的协议,而__next__和__iter__这两个魔法方法就代表了迭代器协议。可以通过for-in循环从迭代器对象中取出值,也可以使用next函数取出迭代器对象中的下一个值。生成器是迭代器的语法升级版本,可以用更为简单的代码来实现一个迭代器。扩展:面试中经常让写生成斐波那契数列的迭代器,大家可以参考下面的代码。class Fib(object):def __init__(self, num):self.num = numself.a, self.b = 0, 1self.idx = 0def __iter__(self):return selfdef __next__(self):if self.idx < self.num:self.a, self.b = self.b, self.a + self.bself.idx += 1return self.araise StopIteration()如果用生成器的语法来改写上面的代码,代码会简单优雅很多。def fib(num):a, b = 0, 1for _ in range(num):a, b = b, a + byield a题目009:正则表达式的match方法和search方法有什么区别?点评:正则表达式是字符串处理的重要工具,所以也是面试中经常考察的知识点。在Python中,使用正则表达式有两种方式,一种是直接调用re模块中的函数,传入正则表达式和需要处理的字符串;一种是先通过re模块的compile函数创建正则表达式对象,然后再通过对象调用方法并传入需要处理的字符串。如果一个正则表达式被频繁的使用,我们推荐用re.compile函数创建正则表达式对象,这样会减少频繁编译同一个正则表达式所造成的开销。match方法是从字符串的起始位置进行正则表达式匹配,返回Match对象或None。search方法会扫描整个字符串来找寻匹配的模式,同样也是返回Match对象或None。题目010:下面这段代码的执行结果是什么。def multiply():
return [lambda x: i * x for i in range(4)]
print([m(100) for m in multiply()])
运行结果:[300, 300, 300, 300]
上面代码的运行结果很容易被误判为[0, 100, 200, 300]。首先需要注意的是multiply函数用生成式语法返回了一个列表,列表中保存了4个Lambda函数,这4个Lambda函数会返回传入的参数乘以i的结果。需要注意的是这里有闭包(closure)现象,multiply函数中的局部变量i的生命周期被延展了,由于i最终的值是3,所以通过m(100)调列表中的Lambda函数时会返回300,而且4个调用都是如此。如果想得到[0, 100, 200, 300]这个结果,可以按照下面几种方式来修改multiply函数。方法一:使用生成器,让函数获得i的当前值。def multiply():
return (lambda x: i * x for i in range(4))
print([m(100) for m in multiply()])
或者def multiply():
for i in range(4):
yield lambda x: x * i
print([m(100) for m in multiply()])
方法二:使用偏函数,彻底避开闭包。from functools import partial
from operator import __mul__
def multiply():
return [partial(__mul__, i) for i in range(4)]
print([m(100) for m in multiply()])
题目011:Python中为什么没有函数重载?点评:C++、Java、C#等诸多编程语言都支持函数重载,所谓函数重载指的是在同一个作用域中有多个同名函数,它们拥有不同的参数列表(参数个数不同或参数类型不同或二者皆不同),可以相互区分。重载也是一种多态性,因为通常是在编译时通过参数的个数和类型来确定到底调用哪个重载函数,所以也被称为编译时多态性或者叫前绑定。这个问题的潜台词其实是问面试者是否有其他编程语言的经验,是否理解Python是动态类型语言,是否知道Python中函数的可变参数、关键字参数这些概念。首先Python是解释型语言,函数重载现象通常出现在编译型语言中。其次Python是动态类型语言,函数的参数没有类型约束,也就无法根据参数类型来区分重载。再者Python中函数的参数可以有默认值,可以使用可变参数和关键字参数,因此即便没有函数重载,也要可以让一个函数根据调用者传入的参数产生不同的行为。题目012:用Python代码实现Python内置函数max。点评:这个题目看似简单,但实际上还是比较考察面试者的功底。因为Python内置的max函数既可以传入可迭代对象找出最大,又可以传入两个或多个参数找出最大;最为关键的是还可以通过命名关键字参数key来指定一个用于元素比较的函数,还可以通过default命名关键字参数来指定当可迭代对象为空时返回的默认值。下面的代码仅供参考:def my_max(*args, key=None, default=None):
"""
获取可迭代对象中最大的元素或两个及以上实参中最大的元素
:param args: 一个可迭代对象或多个元素
:param key: 提取用于元素比较的特征值的函数,默认为None
:param default: 如果可迭代对象为空则返回该默认值,如果没有给默认值则引发ValueError异常
:return: 返回可迭代对象或多个元素中的最大元素
"""
if len(args) == 1 and len(args[0]) == 0:
if default:
return default
else:
raise ValueError('max() arg is an empty sequence')
items = args[0] if len(args) == 1 else args
max_elem, max_value = items[0], items[0]
if key:
max_value = key(max_value)
for item in items:
value = item
if key:
value = key(item)
if value > max_value:
max_elem, max_value = item, value
return max_elem
题目013:写一个函数统计传入的列表中每个数字出现的次数并返回对应的字典。点评:送人头的题目,不解释。def count_letters(items):
result = {}
for item in items:
if isinstance(item, (int, float)):
result[item] = result.get(item, 0) + 1
return result
也可以直接使用Python标准库中collections模块的Counter类来解决这个问题,Counter是dict的子类,它会将传入的序列中的每个元素作为键,元素出现的次数作为值来构造字典。from collections import Counter
def count_letters(items):
counter = Counter(items)
return {key: value for key, value in counter.items() \
if isinstance(key, (int, float))}
题目014:使用Python代码实现遍历一个文件夹的操作。点评:基本也是送人头的题目,只要用过os模块就应该知道怎么做。Python标准库os模块的walk函数提供了遍历一个文件夹的功能,它返回一个生成器。import os
g = os.walk('/Users/Hao/Downloads/')
for path, dir_list, file_list in g:
for dir_name in dir_list:
print(os.path.join(path, dir_name))
for file_name in file_list:
print(os.path.join(path, file_name))
说明:os.path模块提供了很多进行路径操作的工具函数,在项目开发中也是经常会用到的。如果题目明确要求不能使用os.walk函数,那么可以使用os.listdir函数来获取指定目录下的文件和文件夹,然后再通过循环遍历用os.isdir函数判断哪些是文件夹,对于文件夹可以通过递归调用进行遍历,这样也可以实现遍历一个文件夹的操作。题目015:现有2元、3元、5元共三种面额的货币,如果需要找零99元,一共有多少种找零的方式?点评:还有一个非常类似的题目:“一个小朋友走楼梯,一次可以走1个台阶、2个台阶或3个台阶,问走完10个台阶一共有多少种走法?”,这两个题目的思路是一样,如果用递归函数来写的话非常简单。from functools import lru_cache
@lru_cache()
def change_money(total):
if total == 0:
return 1
if total < 0:
return 0
return change_money(total - 2) + change_money(total - 3) + \
change_money(total - 5)
说明:在上面的代码中,我们用lru_cache装饰器装饰了递归函数change_money,如果不做这个优化,上面代码的渐近时间复杂度将会是,而如果参数total的值是99,这个运算量是非常巨大的。lru_cache装饰器会缓存函数的执行结果,这样就可以减少重复运算所造成的开销,这是空间换时间的策略,也是动态规划的编程思想。题目016:写一个函数,给定矩阵的阶数`n`,输出一个螺旋式数字矩阵。例如:n = 2,返回:1 24 3例如:n = 3,返回:1 2 38 9 47 6 5这个题目本身并不复杂,下面的代码仅供参考。def show_spiral_matrix(n):
matrix = [[0] * n for _ in range(n)]
row, col = 0, 0
num, direction = 1, 0
while num <= n ** 2:
if matrix[row][col] == 0:
matrix[row][col] = num
num += 1
if direction == 0:
if col < n - 1 and matrix[row][col + 1] == 0:
col += 1
else:
direction += 1
elif direction == 1:
if row < n - 1 and matrix[row + 1][col] == 0:
row += 1
else:
direction += 1
elif direction == 2:
if col > 0 and matrix[row][col - 1] == 0:
col -= 1
else:
direction += 1
else:
if row > 0 and matrix[row - 1][col] == 0:
row -= 1
else:
direction += 1
direction %= 4
for x in matrix:
for y in x:
print(y, end='\t')
print()
题目017:阅读下面的代码,写出程序的运行结果。items = [1, 2, 3, 4]
print([i for i in items if i > 2])
print([i for i in items if i % 2])
print([(x, y) for x, y in zip('abcd', (1, 2, 3, 4, 5))])
print({x: f'item{x ** 2}' for x in (2, 4, 6)})
print(len({x for x in 'hello world' if x not in 'abcdefg'}))
点评:生成式(推导式)属于Python的特色语法之一,几乎是面试必考内容。Python中通过生成式字面量语法,可以创建出列表、集合、字典。[3, 4]
[1, 3]
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
{2: 'item4', 4: 'item16', 6: 'item36'}
6
题目018:说出下面代码的运行结果。class Parent:
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
点评:运行上面的代码首先输出1 1 1,这一点大家应该没有什么疑问。接下来,通过Child1.x = 2给类Child1重新绑定了属性x并赋值为2,所以Child1.x会输出2,而Parent和Child2并不受影响。执行Parent.x = 3会重新给Parent类的x属性赋值为3,由于Child2的x属性继承自Parent,所以Child2.x的值也是3;而之前我们为Child1重新绑定了x属性,那么它的x属性值不会受到Parent.x = 3的影响,还是之前的值2。1 1 1
1 2 1
3 2 3
题目19:说说你用过Python标准库中的哪些模块。点评:Python标准库中的模块非常多,建议大家根据自己过往的项目经历来介绍你用过的标准库和三方库,因为这些是你最为熟悉的,经得起面试官深挖的。模块名介绍sys跟Python解释器相关的变量和函数,例如:sys.version、sys.exit()os和操作系统相关的功能,例如:os.listdir()、os.remove()re和正则表达式相关的功能,例如:re.compile()、re.search()math和数学运算相关的功能,例如:math.pi、math.e、math.coslogging和日志系统相关的类和函数,例如:logging.Logger、logging.Handlerjson / pickle实现对象序列化和反序列的模块,例如:json.loads、json.dumpshashlib封装了多种哈希摘要算法的模块,例如:hashlib.md5、hashlib.sha1urllib包含了和URL相关的子模块,例如:urllib.request、urllib.parseitertools提供各种迭代器的模块,例如:itertools.cycle、itertools.productfunctools函数相关工具模块,例如:functools.partial、functools.lru_cachecollections / heapq封装了常用数据结构和算法的模块,例如:collections.dequethreading / multiprocessing多线程/多进程相关类和函数的模块,例如:threading.Threadconcurrent.futures / asyncio并发编程/异步编程相关的类和函数的模块,例如:ThreadPoolExecutorbase64提供BASE-64编码相关函数的模块,例如:bas64.encodecsv和读写CSV文件相关的模块,例如:csv.reader、csv.writerprofile / cProfile / pstats和代码性能剖析相关的模块,例如:cProfile.run、pstats.Statsunittest和单元测试相关的模块,例如:unittest.TestCase题目20:`init__`和`__new`方法有什么区别?Python中调用构造器创建对象属于两阶段构造过程,首先执行__new__方法获得保存对象所需的内存空间,再通过__init__执行对内存空间数据的填充(对象属性的初始化)。__new__方法的返回值是创建好的Python对象(的引用),而__init__方法的第一个参数就是这个对象(的引用),所以在__init__中可以完成对对象的初始化操作。__new__是类方法,它的第一个参数是类,__init__是对象方法,它的第一个参数是对象。题目21:输入年月日,判断这个日期是这一年的第几天。方法一:不使用标准库中的模块和函数。def is_leap_year(year):
"""判断指定的年份是不是闰年,平年返回False,闰年返回True"""
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
def which_day(year, month, date):
"""计算传入的日期是这一年的第几天"""
# 用嵌套的列表保存平年和闰年每个月的天数
days_of_month = [
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
]
days = days_of_month[is_leap_year(year)][:month - 1]
return sum(days) + date
方法二:使用标准库中的datetime模块。import datetime
def which_day(year, month, date):
end = datetime.date(year, month, date)
start = datetime.date(year, 1, 1)
return (end - start).days + 1
题目22:平常工作中用什么工具进行静态代码分析。点评:静态代码分析工具可以从代码中提炼出各种静态属性,这使得开发者可以对代码的复杂性、可维护性和可读性有更好的了解,这里所说的静态属性包括:代码是否符合编码规范,例如:PEP-8。代码中潜在的问题,包括:语法错误、缩进问题、导入缺失、变量覆盖等。代码中的坏味道。代码的复杂度。代码的逻辑问题。工作中静态代码分析主要用到的是Pylint和Flake8。Pylint可以检查出代码错误、坏味道、不规范的代码等问题,较新的版本中还提供了代码复杂度统计数据,可以生成检查报告。Flake8封装了Pyflakes(检查代码逻辑错误)、McCabe(检查代码复杂性)和Pycodestyle(检查代码是否符合PEP-8规范)工具,它可以执行这三个工具提供的检查。题目23:说一下你知道的Python中的魔术方法。点评:魔术方法也称为魔法方法,是Python中的特色语法,也是面试中的高频问题。魔术方法作用__new__、__init__、__del__创建和销毁对象相关__add__、__sub__、__mul__、__div__、__floordiv__、__mod__算术运算符相关__eq__、__ne__、__lt__、__gt__、__le__、__ge__关系运算符相关__pos__、__neg__、__invert__一元运算符相关__lshift__、__rshift__、__and__、__or__、__xor__位运算相关__enter__、__exit__上下文管理器协议__iter__、__next__、__reversed__迭代器协议__int__、__long__、__float__、__oct__、__hex__类型/进制转换相关__str__、__repr__、__hash__、__dir__对象表述相关__len__、__getitem__、__setitem__、__contains__、__missing__序列相关__copy__、__deepcopy__对象拷贝相关__call__、__setattr__、__getattr__、__delattr__其他魔术方法题目24:函数参数`arg`和`*kwargs`分别代表什么?Python中,函数的参数分为位置参数、可变参数、关键字参数、命名关键字参数。*args代表可变参数,可以接收0个或任意多个参数,当不确定调用者会传入多少个位置参数时,就可以使用可变参数,它会将传入的参数打包成一个元组。**kwargs代表关键字参数,可以接收用参数名=参数值的方式传入的参数,传入的参数的会打包成一个字典。定义函数时如果同时使用*args和**kwargs,那么函数可以接收任意参数。题目25:写一个记录函数执行时间的装饰器。点评:高频面试题,也是最简单的装饰器,面试者必须要掌握的内容。方法一:用函数实现装饰器。from functools import wraps
from time import time
def record_time(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time()
result = func(*args, **kwargs)
print(f'{func.__name__}执行时间: {time() - start}秒')
return result
return wrapper
方法二:用类实现装饰器。类有__call__魔术方法,该类对象就是可调用对象,可以当做装饰器来使用。from functools import wraps
from time import time
class Record:
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time()
result = func(*args, **kwargs)
print(f'{func.__name__}执行时间: {time() - start}秒')
return result
return wrapper
说明:装饰器可以用来装饰类或函数,为其提供额外的能力,属于设计模式中的代理模式。扩展:装饰器本身也可以参数化,例如上面的例子中,如果不希望在终端中显示函数的执行时间而是希望由调用者来决定如何输出函数的执行时间,可以通过参数化装饰器的方式来做到,代码如下所示。from functools import wraps
from time import time
def record_time(output):
"""可以参数化的装饰器"""
def decorate(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time()
result = func(*args, **kwargs)
output(func.__name__, time() - start)
return result
return wrapper
return decorate
题目26:什么是鸭子类型(duck typing)?鸭子类型是动态类型语言判断一个对象是不是某种类型时使用的方法,也叫做鸭子判定法。简单的说,鸭子类型是指判断一只鸟是不是鸭子,我们只关心它游泳像不像鸭子、叫起来像不像鸭子、走路像不像鸭子就足够了。换言之,如果对象的行为跟我们的预期是一致的(能够接受某些消息),我们就认定它是某种类型的对象。在Python语言中,有很多bytes-like对象(如:bytes、bytearray、array.array、memoryview)、file-like对象(如:StringIO、BytesIO、GzipFile、socket)、path-like对象(如:str、bytes),其中file-like对象都能支持read和write操作,可以像文件一样读写,这就是所谓的对象有鸭子的行为就可以判定为鸭子的判定方法。再比如Python中列表的extend方法,它需要的参数并不一定要是列表,只要是可迭代对象就没有问题。说明:动态语言的鸭子类型使得设计模式的应用被大大简化。题目27:说一下Python中变量的作用域。Python中有四种作用域,分别是局部作用域(Local)、嵌套作用域(Embedded)、全局作用域(Global)、内置作用域(Built-in),搜索一个标识符时,会按照LEGB的顺序进行搜索,如果所有的作用域中都没有找到这个标识符,就会引发NameError异常。题目28:说一下你对闭包的理解。闭包是支持一等函数的编程语言(Python、JavaScript等)中实现词法绑定的一种技术。当捕捉闭包的时候,它的自由变量(在函数外部定义但在函数内部使用的变量)会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。简单的说,可以将闭包理解为能够读取其他函数内部变量的函数。正在情况下,函数的局部变量在函数调用结束之后就结束了生命周期,但是闭包使得局部变量的生命周期得到了延展。使用闭包的时候需要注意,闭包会使得函数中创建的对象不会被垃圾回收,可能会导致很大的内存开销,所以闭包一定不能滥用。题目29:说一下Python中的多线程和多进程的应用场景和优缺点。线程是操作系统分配CPU的基本单位,进程是操作系统分配内存的基本单位。通常我们运行的程序会包含一个或多个进程,而每个进程中又包含一个或多个线程。多线程的优点在于多个线程可以共享进程的内存空间,所以进程间的通信非常容易实现;但是如果使用官方的CPython解释器,多线程受制于GIL(全局解释器锁),并不能利用CPU的多核特性,这是一个很大的问题。使用多进程可以充分利用CPU的多核特性,但是进程间通信相对比较麻烦,需要使用IPC机制(管道、套接字等)。多线程适合那些会花费大量时间在I/O操作上,但没有太多并行计算需求且不需占用太多内存的I/O密集型应用。多进程适合执行计算密集型任务(如:视频编码解码、数据处理、科学计算等)、可以分解为多个并行子任务并能合并子任务执行结果的任务以及在内存使用方面没有任何限制且不强依赖于I/O操作的任务。扩展:Python中实现并发编程通常有多线程、多进程和异步编程三种选择。异步编程实现了协作式并发,通过多个相互协作的子程序的用户态切换,实现对CPU的高效利用,这种方式也是非常适合I/O密集型应用的。题目30:说一下Python 2和Python 3的区别。点评:这种问题千万不要背所谓的参考答案,说一些自己最熟悉的就足够了。Python 2中的print和exec都是关键字,在Python 3中变成了函数。Python 3中没有long类型,整数都是int类型。Python 2中的不等号&lt;&gt;在Python 3中被废弃,统一使用!=。Python 2中的xrange函数在Python 3中被range函数取代。Python 3对Python 2中不安全的input函数做出了改进,废弃了raw_input函数。Python 2中的file函数被Python 3中的open函数取代。Python 2中的/运算对于int类型是整除,在Python 3中要用//来做整除除法。Python 3中改进了Python 2捕获异常的代码,很明显Python 3的写法更合理。Python 3生成式中循环变量的作用域得到了更好的控制,不会影响到生成式之外的同名变量。Python 3中的round函数可以返回int或float类型,Python 2中的round函数返回float类型。Python 3的str类型是Unicode字符串,Python 2的str类型是字节串,相当于Python 3中的bytes。Python 3中的比较运算符必须比较同类对象。Python 3中定义类的都是新式类,Python 2中定义的类有新式类(显式继承自object的类)和旧式类(经典类)之分,新式类和旧式类在MRO问题上有非常显著的区别,新式类可以使用class__`属性获取自身类型,新式类可以使用`__slots魔法。Python 3对代码缩进的要求更加严格,如果混用空格和制表键会引发TabError。Python 3中字典的keys、values、items方法都不再返回list对象,而是返回view object,内置的map、filter等函数也不再返回list对象,而是返回迭代器对象。Python 3标准库中某些模块的名字跟Python 2是有区别的;而在三方库方面,有些三方库只支持Python 2,有些只能支持Python 3。题目31:谈谈你对“猴子补丁”(monkey patching)的理解。“猴子补丁”是动态类型语言的一个特性,代码运行时在不修改源代码的前提下改变代码中的方法、属性、函数等以达到热补丁(hot patch)的效果。很多系统的安全补丁也是通过猴子补丁的方式来实现的,但实际开发中应该避免对猴子补丁的使用,以免造成代码行为不一致的问题。在使用gevent库的时候,我们会在代码开头的地方执行gevent.monkey.patch_all(),这行代码的作用是把标准库中的socket模块给替换掉,这样我们在使用socket的时候,不用修改任何代码就可以实现对代码的协程化,达到提升性能的目的,这就是对猴子补丁的应用。另外,如果希望用ujson三方库替换掉标准库中的json,也可以使用猴子补丁的方式,代码如下所示。import json, ujson
json.__name__ = 'ujson'
json.dumps = ujson.dumps
json.loads = ujson.loads
单元测试中的Mock技术也是对猴子补丁的应用,Python中的unittest.mock模块就是解决单元测试中用Mock对象替代被测对象所依赖的对象的模块。题目32:阅读下面的代码说出运行结果。class A:
def who(self):
print('A', end='')
class B(A):
def who(self):
super(B, self).who()
print('B', end='')
class C(A):
def who(self):
super(C, self).who()
print('C', end='')
class D(B, C):
def who(self):
super(D, self).who()
print('D', end='')
item = D()
item.who()
点评:这道题考查到了两个知识点:Python中的MRO(方法解析顺序)。在没有多重继承的情况下,向对象发出一个消息,如果对象没有对应的方法,那么向上(父类)搜索的顺序是非常清晰的。如果向上追溯到object类(所有类的父类)都没有找到对应的方法,那么将会引发AttributeError异常。但是有多重继承尤其是出现菱形继承(钻石继承)的时候,向上追溯到底应该找到那个方法就得确定MRO。Python 3中的类以及Python 2中的新式类使用C3算法来确定MRO,它是一种类似于广度优先搜索的方法;Python 2中的旧式类(经典类)使用深度优先搜索来确定MRO。在搞不清楚MRO的情况下,可以使用类的mro方法或mro属性来获得类的MRO列表。super()函数的使用。在使用super函数时,可以通过super(类型, 对象)来指定对哪个对象以哪个类为起点向上搜索父类方法。所以上面B类代码中的super(B, self).who()表示以B类为起点,向上搜索self(D类对象)的who方法,所以会找到C类中的who方法,因为D类对象的MRO列表是D --&gt; B --&gt; C --&gt; A --&gt; object。题目33:编写一个函数实现对逆波兰表达式求值,不能使用Python的内置函数。点评:逆波兰表达式也称为“后缀表达式”,相较于平常我们使用的“中缀表达式”,逆波兰表达式不需要括号来确定运算的优先级,例如5 * (2 + 3)对应的逆波兰表达式是5 2 3 + *。逆波兰表达式求值需要借助栈结构,扫描表达式遇到运算数就入栈,遇到运算符就出栈两个元素做运算,将运算结果入栈。表达式扫描结束后,栈中只有一个数,这个数就是最终的运算结果,直接出栈即可。import operator
class Stack:
"""栈(FILO)"""
def __init__(self):
self.elems = []
def push(self, elem):
"""入栈"""
self.elems.append(elem)
def pop(self):
"""出栈"""
return self.elems.pop()
@property
def is_empty(self):
"""检查栈是否为空"""
return len(self.elems) == 0
def eval_suffix(expr):
"""逆波兰表达式求值"""
operators = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv
}
stack = Stack()
for item in expr.split():
if item.isdigit():
stack.push(float(item))
else:
num2 = stack.pop()
num1 = stack.pop()
stack.push(operators[item](num1, num2))
return stack.pop()
题目34:Python中如何实现字符串替换操作?Python中实现字符串替换大致有两类方法:字符串的replace方法和正则表达式的sub方法。方法一:使用字符串的replace方法。message = 'hello, world!'
print(message.replace('o', 'O').replace('l', 'L').replace('he', 'HE'))
方法二:使用正则表达式的sub方法。import re
message = 'hello, world!'
pattern = re.compile('[aeiou]')
print(pattern.sub('#', message))
扩展:还有一个相关的面试题,对保存文件名的列表排序,要求文件名按照字母表和数字大小进行排序,例如对于列表filenames = ['a12.txt', 'a8.txt', 'b10.txt', 'b2.txt', 'b19.txt', 'a3.txt'],排序的结果是['a3.txt', 'a8.txt', 'a12.txt', 'b2.txt', 'b10.txt', 'b19.txt']。提示一下,可以通过字符串替换的方式为文件名补位,根据补位后的文件名用sorted函数来排序,大家可以思考下这个问题如何解决。题目35:如何剖析Python代码的执行性能?剖析代码性能可以使用Python标准库中的cProfile和pstats模块,cProfile的run函数可以执行代码并收集统计信息,创建出Stats对象并打印简单的剖析报告。Stats是pstats模块中的类,它是一个统计对象。当然,也可以使用三方工具line_profiler和memory_profiler来剖析每一行代码耗费的时间和内存,这两个三方工具都会用非常友好的方式输出剖析结构。如果使用PyCharm,可以利用“Run”菜单的“Profile”菜单项对代码进行性能分析,PyCharm中可以用表格或者调用图(Call Graph)的方式来显示性能剖析的结果。下面是使用cProfile剖析代码性能的例子。example.pyimport cProfile
def is_prime(num):
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True
class PrimeIter:
def __init__(self, total):
self.counter = 0
self.current = 1
self.total = total
def __iter__(self):
return self
def __next__(self):
if self.counter < self.total:
self.current += 1
while not is_prime(self.current):
self.current += 1
self.counter += 1
return self.current
raise StopIteration()
cProfile.run('list(PrimeIter(10000))')
如果使用line_profiler三方工具,可以直接剖析is_prime函数每行代码的性能,需要给is_prime函数添加一个profiler装饰器,代码如下所示。@profiler
def is_prime(num):
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True
安装line_profiler。pip install line_profiler
使用line_profiler。kernprof -lv example.py
运行结果如下所示。Line #
Hits
Time
Per Hit
% Time
Line Contents
==============================================================
1
@profile
2
def is_prime(num):
3
86624
48420.0
0.6
50.5
for factor in range(2, int(num ** 0.5) + 1):
4
85624
44000.0
0.5
45.9
if num % factor == 0:
5
6918
3080.0
0.4
3.2
return False
6
1000
430.0
0.4
0.4
return True
题目36:如何使用`random`模块生成随机数、实现随机乱序和随机抽样?点评:送人头的题目,因为Python标准库中的常用模块应该是Python开发者都比较熟悉的内容,这个问题回如果答不上来,整个面试基本也就砸锅了。random.random()函数可以生成[0.0, 1.0)之间的随机浮点数。random.uniform(a, b)函数可以生成[a, b]或[b, a]之间的随机浮点数。random.randint(a, b)函数可以生成[a, b]或[b, a]之间的随机整数。random.shuffle(x)函数可以实现对序列x的原地随机乱序。random.choice(seq)函数可以从非空序列中取出一个随机元素。random.choices(population, weights=None, *, cum_weights=None, k=1)函数可以从总体中随机抽取(有放回抽样)出容量为k的样本并返回样本的列表,可以通过参数指定个体的权重,如果没有指定权重,个体被选中的概率均等。random.sample(population, k)函数可以从总体中随机抽取(无放回抽样)出容量为k的样本并返回样本的列表。扩展:random模块提供的函数除了生成均匀分布的随机数外,还可以生成其他分布的随机数,例如random.gauss(mu, sigma)函数可以生成高斯分布(正态分布)的随机数;random.paretovariate(alpha)函数会生成帕累托分布的随机数;random.gammavariate(alpha, beta)函数会生成伽马分布的随机数。题目37:解释一下线程池的工作原理。点评:池化技术就是一种典型空间换时间的策略,我们使用的数据库连接池、线程池等都是池化技术的应用,Python标准库currrent.futures模块的ThreadPoolExecutor就是线程池的实现,如果要弄清楚它的工作原理,可以参考下面的内容。线程池是一种用于减少线程本身创建和销毁造成的开销的技术,属于典型的空间换时间操作。如果应用程序需要频繁的将任务派发到线程中执行,线程池就是必选项,因为创建和释放线程涉及到大量的系统底层操作,开销较大,如果能够在应用程序工作期间,将创建和释放线程的操作变成预创建和借还操作,将大大减少底层开销。线程池在应用程序启动后,立即创建一定数量的线程,放入空闲队列中。这些线程最开始都处于阻塞状态,不会消耗CPU资源,但会占用少量的内存空间。当任务到来后,从队列中取出一个空闲线程,把任务派发到这个线程中运行,并将该线程标记为已占用。当线程池中所有的线程都被占用后,可以选择自动创建一定数量的新线程,用于处理更多的任务,也可以选择让任务排队等待直到有空闲的线程可用。在任务执行完毕后,线程并不退出结束,而是继续保持在池中等待下一次的任务。当系统比较空闲时,大部分线程长时间处于闲置状态时,线程池可以自动销毁一部分线程,回收系统资源。基于这种预创建技术,线程池将线程创建和销毁本身所带来的开销分摊到了各个具体的任务上,执行次数越多,每个任务所分担到的线程本身开销则越小。一般线程池都必须具备下面几个组成部分:线程池管理器:用于创建并管理线程池。工作线程和线程队列:线程池中实际执行的线程以及保存这些线程的容器。任务接口:将线程执行的任务抽象出来,形成任务接口,确保线程池与具体的任务无关。任务队列:线程池中保存等待被执行的任务的容器。题目38:举例说明什么情况下会出现`KeyError`、`TypeError`、`ValueError`。举一个简单的例子,变量a是一个字典,执行int(a['x'])这个操作就有可能引发上述三种类型的异常。如果字典中没有键x,会引发KeyError;如果键x对应的值不是str、float、int、bool以及bytes-like类型,在调用int函数构造int类型的对象时,会引发TypeError;如果a[x]是一个字符串或者字节串,而对应的内容又无法处理成int时,将引发ValueError。题目39:说出下面代码的运行结果。def extend_list(val, items=[]):
items.append(val)
return items
list1 = extend_list(10)
list2 = extend_list(123, [])
list3 = extend_list('a')
print(list1)
print(list2)
print(list3)
点评:Python函数在定义的时候,默认参数items的值就被计算出来了,即[]。因为默认参数items引用了对象[],每次调用该函数,如果对items引用的列表进行了操作,下次调用时,默认参数还是引用之前的那个列表而不是重新赋值为[],所以列表中会有之前添加的元素。如果通过传参的方式为items重新赋值,那么items将引用到新的列表对象,而不再引用默认的那个列表对象。这个题在面试中经常被问到,通常不建议使用容器类型的默认参数,像PyLint这样的代码检查工具也会对这种代码提出质疑和警告。[10, 'a']
[123]
[10, 'a']
题目40:如何读取大文件,例如内存只有4G,如何读取一个大小为8G的文件?很显然4G内存要一次性的加载大小为8G的文件是不现实的,遇到这种情况必须要考虑多次读取和分批次处理。在Python中读取文件可以先通过open函数获取文件对象,在读取文件时,可以通过read方法的size参数指定读取的大小,也可以通过seek方法的offset参数指定读取的位置,这样就可以控制单次读取数据的字节数和总字节数。除此之外,可以使用内置函数iter将文件对象处理成迭代器对象,每次只读取少量的数据进行处理,代码大致写法如下所示。with open('...', 'rb') as file:
for data in iter(lambda: file.read(2097152), b''):
pass
在Linux系统上,可以通过split命令将大文件切割为小片,然后通过读取切割后的小文件对数据进行处理。例如下面的命令将名为filename的大文件切割为大小为512M的多个文件。split -b 512m filename
如果愿意, 也可以将名为filename的文件切割为10个文件,命令如下所示。split -n 10 filename
扩展:外部排序跟上述的情况非常类似,由于处理的数据不能一次装入内存,只能放在读写较慢的外存储器(通常是硬盘)上。“排序-归并算法”就是一种常用的外部排序策略。在排序阶段,先读入能放在内存中的数据量,将其排序输出到一个临时文件,依此进行,将待排序数据组织为多个有序的临时文件,然后在归并阶段将这些临时文件组合为一个大的有序文件,这个大的有序文件就是排序的结果。题目41:说一下你对Python中模块和包的理解。每个Python文件就是一个模块,而保存这些文件的文件夹就是一个包,但是这个作为Python包的文件夹必须要有一个名为__init__.py的文件,否则无法导入这个包。通常一个文件夹下还可以有子文件夹,这也就意味着一个包下还可以有子包,子包中的__init__.py并不是必须的。模块和包解决了Python中命名冲突的问题,不同的包下可以有同名的模块,不同的模块下可以有同名的变量、函数或类。在Python中可以使用import或from ... import ...来导入包和模块,在导入的时候还可以使用as关键字对包、模块、类、函数、变量等进行别名,从而彻底解决编程中尤其是多人协作团队开发时的命名冲突问题。题目42:说一下你知道的Python编码规范。点评:企业的Python编码规范基本上是参照PEP-8或谷歌开源项目风格指南来制定的,后者还提到了可以使用Lint工具来检查代码的规范程度,面试的时候遇到这类问题,可以先说下这两个参照标准,然后挑重点说一下Python编码的注意事项。空格的使用使用空格来表示缩进而不要用制表符(Tab)。和语法相关的每一层缩进都用4个空格来表示。每行的字符数不要超过79个字符,如果表达式因太长而占据了多行,除了首行之外的其余各行都应该在正常的缩进宽度上再加上4个空格。函数和类的定义,代码前后都要用两个空行进行分隔。在同一个类中,各个方法之间应该用一个空行进行分隔。二元运算符的左右两侧应该保留一个空格,而且只要一个空格就好。标识符命名变量、函数和属性应该使用小写字母来拼写,如果有多个单词就使用下划线进行连接。类中受保护的实例属性,应该以一个下划线开头。类中私有的实例属性,应该以两个下划线开头。类和异常的命名,应该每个单词首字母大写。模块级别的常量,应该采用全大写字母,如果有多个单词就用下划线进行连接。类的实例方法,应该把第一个参数命名为self以表示对象自身。类的类方法,应该把第一个参数命名为cls以表示该类自身。表达式和语句采用内联形式的否定词,而不要把否定词放在整个表达式的前面。例如:if a is not b就比if not a is b更容易让人理解。不要用检查长度的方式来判断字符串、列表等是否为None或者没有元素,应该用if not x这样的写法来检查它。就算if分支、for循环、except异常捕获等中只有一行代码,也不要将代码和if、for、except等写在一起,分开写才会让代码更清晰。import语句总是放在文件开头的地方。引入模块的时候,from math import sqrt比import math更好。如果有多个import语句,应该将其分为三部分,从上到下分别是Python标准模块、第三方模块和自定义模块,每个部分内部应该按照模块名称的字母表顺序来排列。题目43:运行下面的代码是否会报错,如果报错请说明哪里有什么样的错,如果不报错请说出代码的执行结果。class A:
def __init__(self, value):
self.__value = value
@property
def value(self):
return self.__value
obj = A(1)
obj.__value = 2
print(obj.value)
print(obj.__value)
点评:这道题有两个考察点,一个考察点是对_和__开头的对象属性访问权限以及@property装饰器的了解,另外一个考察的点是对动态语言的理解,不需要过多的解释。扩展:如果不希望代码运行时动态的给对象添加新属性,可以在定义类时使用__slots__魔法。例如,我们可以在上面的A中添加一行__slots__ = ('__value', ),再次运行上面的代码,将会在原来的第10行处产生AttributeError错误。题目44:对下面给出的字典按值从大到小对键进行排序。prices = {
'AAPL': 191.88,
'GOOG': 1186.96,
'IBM': 149.24,
'ORCL': 48.44,
'ACN': 166.89,
'FB': 208.09,
'SYMC': 21.29
}
点评:sorted函数的高阶用法在面试的时候经常出现,key参数可以传入一个函数名或一个Lambda函数,该函数的返回值代表了在排序时比较元素的依据。sorted(prices, key=lambda x: prices[x], reverse=True)
题目45:说一下`namedtuple`的用法和作用。点评:Python标准库的collections模块提供了很多有用的数据结构,这些内容并不是每个开发者都清楚,就比如题目问到的namedtuple,在我参加过的面试中,90%的面试者都不能准确的说出它的作用和应用场景。此外,deque也是一个非常有用但又经常被忽视的类,还有Counter、OrderedDict 、defaultdict 、UserDict等类,大家清楚它们的用法吗?在使用面向对象编程语言的时候,定义类是最常见的一件事情,有的时候,我们会用到只有属性没有方法的类,这种类的对象通常只用于组织数据,并不能接收消息,所以我们把这种类称为数据类或者退化的类,就像C语言中的结构体那样。我们并不建议使用这种退化的类,在Python中可以用namedtuple(命名元组)来替代这种类。from collections import namedtuple
Card = namedtuple('Card', ('suite', 'face'))
card1 = Card('红桃', 13)
card2 = Card('草花', 5)
print(f'{card1.suite}{card1.face}')
print(f'{card2.suite}{card2.face}')
命名元组与普通元组一样是不可变容器,一旦将数据存储在namedtuple的顶层属性中,数据就不能再修改了,也就意味着对象上的所有属性都遵循“一次写入,多次读取”的原则。和普通元组不同的是,命名元组中的数据有访问名称,可以通过名称而不是索引来获取保存的数据,不仅在操作上更加简单,代码的可读性也会更好。命名元组的本质就是一个类,所以它还可以作为父类创建子类。除此之外,命名元组内置了一系列的方法,例如,可以通过_asdict方法将命名元组处理成字典,也可以通过_replace方法创建命名元组对象的浅拷贝。class MyCard(Card):
def show(self):
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
return f'{self.suite}{faces[self.face]}'
print(Card)
# <class '__main__.Card'>
card3 = MyCard('方块', 12)
print(card3.show())
# 方块Q
print(dict(card1._asdict()))
# {'suite': '红桃', 'face': 13}
print(card2._replace(suite='方块'))
# Card(suite='方块', face=5)
总而言之,命名元组能更好的组织数据结构,让代码更加清晰和可读,在很多场景下是元组、字典和数据类的替代品。在需要创建占用空间更少的不可变类时,命名元组就是很好的选择。题目46:按照题目要求写出对应的函数。要求:写一个函数,传入一个有若干个整数的列表,该列表中某个元素出现的次数超过了50%,返回这个元素。def more_than_half(items):
temp, times = None, 0
for item in items:
if times == 0:
temp = item
times += 1
else:
if item == temp:
times += 1
else:
times -= 1
return temp
点评:LeetCode上的题目,在Python面试中出现过,利用元素出现次数超过了50%这一特征,出现和temp相同的元素就将计数值加1,出现和temp不同的元素就将计数值减1。如果计数值为0,说明之前出现的元素已经对最终的结果没有影响,用temp记下当前元素并将计数值置为1。最终,出现次数超过了50%的这个元素一定会被赋值给变量temp。题目47:按照题目要求写出对应的函数。要求:写一个函数,传入的参数是一个列表(列表中的元素可能也是一个列表),返回该列表最大的嵌套深度。例如:列表[1, 2, 3]的嵌套深度为1,列表[[1], [2, [3]]]的嵌套深度为3。def list_depth(items):
if isinstance(items, list):
max_depth = 1
for item in items:
max_depth = max(list_depth(item) + 1, max_depth)
return max_depth
return 0
点评:看到题目应该能够比较自然的想到使用递归的方式检查列表中的每个元素。题目48:按照题目要求写出对应的装饰器。要求:有一个通过网络获取数据的函数(可能会因为网络原因出现异常),写一个装饰器让这个函数在出现指定异常时可以重试指定的次数,并在每次重试之前随机延迟一段时间,最长延迟时间可以通过参数进行控制。方法一:from functools import wraps
from random import random
from time import sleep
def retry(*, retry_times=3, max_wait_secs=5, errors=(Exception, )):
def decorate(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(retry_times):
try:
return func(*args, **kwargs)
except errors:
sleep(random() * max_wait_secs)
return None
return wrapper
return decorate
方法二:from functools import wraps
from random import random
from time import sleep
class Retry(object):
def __init__(self, *, retry_times=3, max_wait_secs=5, errors=(Exception, )):
self.retry_times = retry_times
self.max_wait_secs = max_wait_secs
self.errors = errors
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(self.retry_times):
try:
return func(*args, **kwargs)
except self.errors:
sleep(random() * self.max_wait_secs)
return None
return wrapper
点评:我们不止一次强调过,装饰器几乎是Python面试必问内容,这个题目比之前的题目稍微复杂一些,它需要的是一个参数化的装饰器。题目49:写一个函数实现字符串反转,尽可能写出你知道的所有方法。点评:烂大街的题目,基本上算是送人头的题目。方法一:反向切片def reverse_string(content):
return content[::-1]
方法二:反转拼接def reverse_string(content):
return ''.join(reversed(content))
方法三:递归调用def reverse_string(content):
if len(content) <= 1:
return content
return reverse_string(content[1:]) + content[0]
方法四:双端队列from collections import deque
def reverse_string(content):
q = deque()
q.extendleft(content)
return ''.join(q)
方法五:反向组装from io import StringIO
def reverse_string(content):
buffer = StringIO()
for i in range(len(content) - 1, -1, -1):
buffer.write(content[i])
return buffer.getvalue()
方法六:反转拼接def reverse_string(content):
return ''.join([content[i] for i in range(len(content) - 1, -1, -1)])
方法七:半截交换def reverse_string(content):
length, content= len(content), list(content)
for i in range(length // 2):
content[i], content[length - 1 - i] = content[length - 1 - i], content[i]
return ''.join(content)
方法八:对位交换def reverse_string(content):
length, content= len(content), list(content)
for i, j in zip(range(length // 2), range(length - 1, length // 2 - 1, -1)):
content[i], content[j] = content[j], content[i]
return ''.join(content)
扩展:这些方法其实都是大同小异的,面试的时候能够给出几种有代表性的就足够了。给大家留一个思考题,上面这些方法,哪些做法的性能较好呢?我们之前提到过剖析代码性能的方法,大家可以用这些方法来检验下你给出的答案是否正确。题目50:按照题目要求写出对应的函数。要求:列表中有1000000个元素,取值范围是[1000, 10000),设计一个函数找出列表中的重复元素。def find_dup(items: list):
dups = [0] * 9000
for item in items:
dups[item - 1000] += 1
for idx, val in enumerate(dups):
if val > 1:
yield idx + 1000
点评:这道题的解法和计数排序的原理一致,虽然元素的数量非常多,但是取值范围[1000, 10000)并不是很大,只有9000个可能的取值,所以可以用一个能够保存9000个元素的dups列表来记录每个元素出现的次数,dups列表所有元素的初始值都是0,通过对items列表中元素的遍历,当出现某个元素时,将dups列表对应位置的值加1,最后dups列表中值大于1的元素对应的就是items列表中重复出现过的元素。如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,咱们下期见!答案获取方式:已赞 已评 已关~学习更多知识与技巧,关注与私信博主(03)
今天分享小学数学逻辑思维训练题附答案(第4篇)-分析法。觉得有用可以点击左下角“赞同”支持一下哦,资料有点多,建议收藏。可获取电子版(下载方式在文末)!分析法仔细地分析总是可以让人更加准确地得出问题的最佳答案。如果 一个人有较强的分析思维能力, 那么他便可以游刃有余地行走在自己 的人生道路上。因为对他来讲, 一切问题在他的分析之下都不再成为问题。初级题:1.你能猜到他的年龄吗?在训练的过程中, 你是司令, 你手下有两名军长, 五名团长, 十名排长和十二名士兵,那么请问你能猜到司令今年的年龄吗?2.算一算,那天是星期几?今天的两天前是星期五,那么请问明天的后一天是星期几?3.一元钱到哪了?有 3 个人去旅店住宿,住 3 间房, 每间房 10 元, 于是他们付给 了老板 30 元。第二天, 老板觉得 25 元就够了, 于是就让伙计退 5 元 给这 3 位客人, 谁知伙计贪心, 只退回每人一元, 自己偷偷拿了 2 元。 这样一来便等于那 3 位客人各花了 9 元,于是 3 个人一共花了 27 元,
在加上伙计独吞的 2 元,总共 29 元。可当初 3 个人一共付了 30 元, 那么还有 1 元到哪里去了?4.找错误一个正方体有 6 个面, 每个面的颜色都不同, 并且只能是红、黄、蓝、绿、黑、白 6 种颜色。如果满足:1.红的对面是黑色2.蓝色和白色相邻3.黄色和蓝色相邻那么,下面结论错误的是:A.红色与蓝色相邻B.蓝色的对面是绿色C.白色与黄色相邻D.黑色与绿色相邻5.最后剩下的是谁?50 名运动员按顺序排成一排, 教练下令: “单数运动员出列! ” 剩下的运动员重新排列编号, 教练又下令: “单数运动员出列! ”如
此下去, 最后只剩下一个人, 他是几号运动员?如果教练喊: “双数
运动员出列。 ”最后剩下的又是谁?6.有意思的钟爷爷有两个钟, 一个钟两年只准一次,而另一个钟每天准 2 次, 爷爷问小明想要那个钟。如果你是小明, 你会选哪只。当然, 钟是用来看时间的。7.黑球白球一个大小均匀的长管子,两端有口, 里面有 4 个白球和 4 个黑 球, 球的直径、两端开口的直径等于管子的内径。现在白球和黑球的 排列是 yyyyhhhh, 要求不取出任何一个球,使得排列为 hhyyyyhh。8.怎样取回自己的袜子?曾经有两个盲人, 他们同时都买了两双白袜和两双黑袜, 八双袜 子的布质、大小完全相同, 每一双袜子都有一张标签纸连着。两个盲 人不小心将八双袜子混在一起。他们怎样才能取回自己的袜子?9.男人女人有一天, 旅社来了三对客人, 两个男人, 两个女人, 还有一对夫 妇, 他们开了三个房间, 门口分别挂上了带有标记的“男”、“女”“男 女”的牌子, 以免走错房间。但是爱开玩笑的饭店服务员, 把牌子巧妙地调换了位置, 让房间里的人找不到自己的房间。据说, 在这种情况下, 只要知道一个房间的情况, 就可以找到其 他房间的情况。请问:应该敲挂什么牌子的房间门呢?现在, 桌子上放了两支同样的蜡烛 A 和 B, 每支燃尽需要一个小 时,那么,如何燃烧这两支蜡烛, 可判定一个 45 分钟呢。注:只有 这两支蜡烛和点火工具。11.找最大的钻石在某大楼里, 从一楼到十楼, 每层楼的电梯门口都会放着一颗钻 石, 但大小不一。有一个女人在一楼乘电梯到十楼, 每到一层楼, 电 梯的门都会打开一次。从头至尾, 这个女人只能拿一次钻石, 她怎样 才能拿到最大的一颗?12.怎样分盐现在, 桌子上摆着一只天平, 两个砝码, 分别为 7g、2g。如何只 用这些物品分三次将 140g 的盐分成 50、90g 各一份?13.十年有几天有一首歌叫十年, 也有一首歌叫 3650 夜。那我现在问: 十年有 多少天?14.如何过桥在一个夜晚, 同时有 4 人需要过一桥, 一次最多只能通过两个人, 且只有一只手电筒, 而且每人的速度不同。 A,B,C,D 需要时间分别 为: 1,2,5,10 分钟。问:在 17 分钟内这四个人怎么过桥?15.找相应的开关在一个卧室内有 3 盏灯, 卧室外有 3 个开关 A、B、C, 分别控制 卧室内的三盏灯。在卧室外看不见卧室内的情况。你只能进门一次, 问你用什么方法来区分哪个开关控制哪盏灯?16.生门? 死门?你现在面临两扇门, 有一扇是生门, 另一扇时死门。生门及死门 都有一个人看守着, 而这两个人之中, 一个只会说真话, 另一个只会 说假话, 这两位守门人知道哪一扇门是生门, 哪一扇是死门, 而你则 是不知道的。同时, 你更不知道那个人会说真话,那个人会说假话,更不知道他们各守的是哪扇门?请问有什么方法, 可以只问其中一位守门员一个问题, 就可以知 道那扇是生门?17.摆铅笔现在, 你的桌子上有 5 根铅笔, 请问你如何摆放才能使他们首尾相接?18.犯人被抓有两个犯人同时被抓, 如两个人能同时坦白, 各判刑期 5 年; 如 果一人坦白, 他就是一年, 另一个人十年; 如果两人都不坦白, 各判三年。两个人无法沟通, 他们经过挣扎考虑后, 都坦白了, 都获得 5 年刑期。请问:他们为什么要这样选择呢?19.猜猜这个数字?有一个奇怪的数字, 去掉第一个数字, 是 13, 去掉最后一个数字是 40。请问:这个奇怪的数字是什么?20.如何吃药你一个人到了一座荒岛上, 救援人员 20 天后才能到达(今天是 第 0 天)。你有 A 和 B 两种药片, 每种 20 粒。每天你必须各吃一片才 能活到第二天。但是你不小心把这两种要混在了一起, 无法识别。你 该怎么办?中级题:21.飞机事件已知: 有 N 架一样的飞机停靠在同一个机场, 每架飞机都只有一 个油箱, 每箱油可使飞机绕地球飞半圈。注意: 天空没有加油站, 飞 机之间只是可以相互加油。如果使某一架飞机平安地绕地球飞一圈, 并安全地回到起飞时的机场,问:至少需要出动几架飞机?注: 路途中间没有飞机场, 每架飞机都必须安全返回起飞时的机 场,不许中途降落。22.如何推出自己帽子的颜色一个牢房, 里面关有 3 个犯人。因为玻璃很厚, 所以 3 个犯人只 能互相看见, 不能听到对方所说的话。一天, 国王命令下人给他们每 个人头上都戴了一顶帽子, 告诉他们帽子的颜色只有红色和黑色, 但 是不让他们知道自己所戴的帽子是什么颜色。在这种情况下, 国王宣布两条命令如下:1.哪个犯人能看到其他两个犯人戴的都是红帽子,就可以释放谁;2.哪个犯人知道自己戴的是黑帽子,也可以释放谁。事实上, 他们三个戴的都是黑帽子。只是他们因为被绑, 看不见 自己的罢了。很长时间, 他们 3 个人只是互相盯着不说话。可是过了 不久,聪明的 A 用推理的方法,认定自己戴的是黑帽子。您也想想, 他是怎样推断的呢?23.填数字找规律填数字是一个很有趣的游戏, 特别锻炼观察和思考的能力。 试试看,有规律填写以下空格:114710192225112358345512471116374614916496424.猜猜谁买了什么车吉米、瑞恩、汤姆斯刚新买了汽车, 汽车的牌子分别是奔驰、本 田和皇冠。他们一起来到朋友杰克家里, 让杰克猜猜他们三人各买的 是什么牌子的车。杰克猜道:“吉米买的是奔驰车,汤姆斯买的肯定 不是皇冠车,瑞恩自然不会是奔驰车。”很可惜,杰克的这种猜测, 只有一种是正确的,你知道他们各自买了什么牌子的车吗?25.体育竞赛有一场体育比赛中,共有 N 个项目, 有运动员 1 号, 2 号, 3 号 参加。在每一个比赛项目中, 第一, 第二, 第三名分别得 A,B,C 分, 其中 A,B,C 为正整数, 且 A>B>C。最后 1 号选手共得 22 分, 2 号与 3 号均得 9 分, 并且 2 号在百米赛中取得第一。最后, 求 N 的值, 并 分析出谁在跳高中得第二名。26.野鸭蛋的故事四个旅游家(张虹、印玉、东晴、西雨) 去不同的岛屿去旅行, 每个人都在岛上发现了野鸡蛋( 1 个到 3 个)。 4 人的年龄各不相同, 是由 18 岁到 21 岁。已知:①东晴是 18 岁。②印玉去了 A 岛。③21 岁的女孩子发现的蛋的数量比去 A 岛女孩的多 1 个。 ④19 岁的女孩子发现的蛋的数量比去 B 岛女孩的多 1 个。 ⑤张虹发现的蛋和 C 岛的蛋之中,有一者是 2 个。⑥D 岛的蛋比西雨的蛋要多 2 个。请问: 张虹、印玉、东晴、西雨分别是多少岁? 她们分别在哪个 岛屿上发现了多少野鸡蛋?27.小圆能转几周?两个直径分别是 2 和 4 的圆环, 如果小圆在大圆内部绕大圆转一 周, 那么小圆自身转了几周?如果在大圆的外部转, 小圆自身又要转 几周呢?28.他懂计算机吗?已知下列 A、B、C 三个判断中,只有一个为真。A.甲班有些人懂计算机。B.甲班王某与刘某都不懂计算机。C.甲班有些人不懂计算机。请问:甲班的班长是否懂计算机? (注意:要有分析的过程。)39.是否参加鉴定?有一个工业公司, 组织它下属的 A、B、C 三个工厂联合试制一种 新产品。关于新产品生产出来后的鉴定办法, 在合同中做了如下规定:(1)如果 B 工厂不参加鉴定, 那么 A 工厂也不参加。
(2)如果 B 工厂参加鉴定,那么 A 工厂和丙工厂也要参加。 请问:如果 A 工厂参加鉴定, C 工厂是否会参加?为什么?30.拥有古物的是谁?孙某和张某是考古学家老李的学生。有一天, 老李拿了一件古物 来考验两人, 两人都无法验证出来这件古物试谁的。老李告诉了孙某 拥有者的姓, 告诉张某拥有者的名, 并且在纸条上写下以下几个人的 人名,问他们知道谁才是拥有者?纸条上的名字有: 沈万三、岳飞、岳云、张飞、张良、张鹏、赵括、赵云、赵鹏、沈括。孙某说:如果我不知道的话, 张某肯定也不知道。张某说:刚才我不知道,听孙某一说,我现在知道了。孙某说:哦, 那我也知道了。请问:那件古物是谁的?31.如何分汤两个犯人被关在监狱的囚房里, 监狱每天都会给他们提供一小锅 汤, 让这两个犯人自己来分。起初, 这两个人经常会发生争执, 因为 他们总是有人认为对方的汤比自己的多。后来他们找到了一个两全其美的办法:一个人分汤,让另一个人先选。于是争端就这么解决了。 可是,现在这间囚房里又加进来一个新犯人, 现在是三个人来分汤。 因此,他们必须找出一个新的分汤方法来维持他们之间的和平。请问:应该如何?32.喝救命水你去沙漠旅行, 事先准备的水喝光了, 你口喝难忍, 这时你看到 了有个瓶子, 拿起来一看, 里面还有多半瓶水。可是瓶口用软木塞塞 住了, 这个时候在不敲碎瓶子, 不拔木塞, 不准在塞子上钻孔的情况 下,你怎样完整地喝到瓶子里的酒呢?33.破案某公寓发生了一起凶杀案, 死者是已婚妇女。探长来到现场观察。 法医说:“尸体经过检验后, 不到 2 个小时, 被一把刀刺中心脏而死。 ”探长发现桌上有一台录音机, 问其他警员:“你们开过录音没有?” 从警员都说没开过。于是,探长按下放音键,传出了死者死前挣扎的声音:“是我老公想杀我, 他一直想杀我。我看到他进来了, 他手里拿 着一把刀。他现在不知道我在录音, 我要关录音机了, 我马上要被他 杀死了……咔嚓。”录音到此中止。探长听到录音后, 马上对众警员说, 这段录音是伪造的。你知道 探长为什么这么快就认定这段录音是伪造的吗?34.哪种说法是假的?高校 2007 年秋季入学的学生中有些是免费师范生。所有的免费师范生都是家境贫寒的。凡是贫困学生都参加了勤工助学活动。如果以上说法是真的, 那么, 请找出以下对此错误的看法:A.有些参加勤工助学活动的学生不是免费师范生。B.2007 年秋季入学的学生中有人家境贫寒。C.凡是没有参加勤工助学活动的学生都不是免费的师范生。 D.有些参加勤工助学活动的学生是 2007 年秋季入学的。35.人寿保险在一个住宅小区的居民中, 大多数中老年人都办了人寿保险, 所 有买了四居室以上住房的居民都办了财产保险。所有办理人寿保险的 都没有办财产保险。如果上述说法是真的, 那么以下哪种说法是真的?1.某些中老年买了四居室以上的房子。2.某些中老年没办此案产保险。3.没有办人寿保险的是买四居室以上房子的人。A . 1 、 2 和 3B . 1 和 2C . 2 和 3D . 1 和 336.四个杯子饭店的餐桌上有四个杯子,每个杯子上写着一句话。第 1 个杯子: 每个杯子里都有水果糖。第 2 个杯子: 我的里面有苹果。第 3 个杯子: 我的里面没有巧克力。第 4 个杯子: 有的杯子里没有水果糖。以上所述, 如果有一句话是真的,那么以下哪种说法为真?A.每个杯子中都有水果糖。B.每个杯子中都没有水果糖。C.每个杯子里都没有苹果。D.第 3 个杯子里有巧克力。高级题:37.过河在一条河边有猎人、狼、男人领着两个小孩, 一个女人也带着两 个小孩。条件为: 如果猎人离开的话, 狼就会把所有的人都吃掉, 如 果男人离开的话, 女人就会把男人的两个小孩掐死, 而如果女人离开, 男人则会把女人的两个小孩掐死。这时, 河边只有一条船, 而这个船上也只能乘坐两个人(狼也算 一个人), 而所有人中, 只有猎人、男人、女人会划船。则问, 怎样做才能使他们全部度过这条河?38.他们中谁的存活机率最大?一条船上有 5 个囚犯, 分别被编为 1、2、3、4、5 号, 他们分别 要在装有 100 颗黄豆的麻袋里抓黄豆, 每人至少要抓一颗, 抓得最多 和最少的人都将被扔下海去。他们五个人在抓豆子的时候不能说话,但在抓的时候, 可以摸出剩下的豆子数。问他们中谁的存活几率最大?提示: 1.他们都是很聪明的人。2.他们先求保命,然后再考虑去多杀人。3.100 颗黄豆不需要全部都分完。4. 若出现两人或多人有一样的豆子,则也算最大或最小, 一并 丢下海去。39.他们分别是哪里人?奥林匹克运动会结束后, 下面这五个人在进行议论。他们中有一 个是讲真话的南区人, 一个是讲假话的北区人, 一个是既讲真话又讲 假话的中区人, 还有两个是局外人。他们每个人要么就先说两句真话, 再说一句假话; 要不然就先说两句假话, 再说一句真话。请看以下他们的陈述:A.1.如果运动员都可以围腰布,那我也能参加。2.B 一定不是南区人。3.D 没能赢得金牌。4.C 如果不是因为有晒斑,也能拿到金牌。B.1.E 赢得了银牌。2.C 第一句话说的是假的。3.C 没能赢得奖牌。4.E 如果不是中区人就是局外人。C.1.我不是中区人。2.我就算没有雀斑也赢不了金牌。3.B 的铜牌没有拿到。4.B 属于南区人。D.1.我赢得了金牌。2.B 的铜牌没有拿到。3.假如运动员都能围腰布, A 本来会参加。4.C 不属于北区人。E.1.我得了金牌。2.C 就算没有晒斑,也拿不到金牌。3.我并不是南区人。4.假如运动员都能围腰布, A 本来会参加。那么, 谁是南区人, 谁是北区人, 谁是中区人, 哪两个是局外人, 谁得了奖牌呢?40.谁是凶手小甜和小蜜幸福地生活在一所豪宅里。她们既不参加社交活动, 也没有与人结怨。有一天, 女仆安卡歇斯底里地跑来告诉李管家, 说 她们倒在卧室的地板上死了。李管家迅速与安卡来到卧室, 发现正如安卡所描述的那样,两具尸体一动不动地躺在地板上。李管家发现房间里没有任何暴力的迹象, 尸体上也没有留下任何 印记。凶手似乎也不是破门而入的, 因为除了地板上有一些破碎的玻 璃外, 没有其他迹象可以证明这一点。李管家排除了自杀的可能; 中 毒也是不可能的, 因为晚餐是他亲自准备、亲自伺候的。李管家再次 仔细的弯身检查了一下尸体, 但仍是没有发现死因, 但注意到地毯湿了。请问:小甜和小蜜是怎么死的呢! 究竟谁杀了她们?41.共有几条病狗?一个村子里一共有 50 户人家,每家每户都养了一条狗。村长说
村里面有病狗, 然后就让每户人家都可以查看其他人家的狗是不是病
狗, 但是不准检查自己家的狗是不是病狗。当这些人如果推断出自家
的狗是病狗的话, 就必须自己把自家的狗枪毙了, 但是每个人在看到
别人家的狗是病狗的时候不准告诉别人, 也没有权利枪毙别人家的狗, 只有权利枪毙自家的狗。然后, 第一天没有听到枪声, 第二天也没有,第三天却传来了一阵枪声。请问:这个村子里一共有几条病狗, 请说明理由?42.为什么呢?曾经有座山, 山上有座庙, 只有一条路可以从山上走到山下。每 周一早上 8 点, 有一个聪明的小和尚去山下化缘, 周二早上 8 点从山 脚回山上的庙里。注意: 小和尚的上下山的速度是任意的, 但是在每 个往返中,他总是能在周一和周二的同一钟点到达山路上的同一点。 例如, 有一次他发现星期一的 9 点和星期二的 9 点他都到了山路靠山脚的地方。请问:这是为什么?43.会遇到几艘来自纽约的船问题内容: 一般在每天中午的时间, 从法国塞纳河畔的勒阿佛有 一艘轮船驶往美国纽约,在同一时刻纽约也有一艘轮船驶往勒阿佛。 我们已经知道的是, 每次横渡一次的时间是 7 天 7 夜, 以这样的时间匀速行驶,可清楚的遇到对方的轮船。问题是: 今天从法国开出的轮船能遇到几艘来自美国的轮船。44.如何找出不标准的球?有 80 个外观一致的小球, 其中一个和其它的重量不同,(不知道 更轻还是更重)。现在给你一个天平,允许你称四次, 把重量不同的 球找出来,怎么称?45.老师的生日是哪一天?小刘和小红都是张老师的学生, 张老师的生日是 M 月 N 日, 2 人 都知道张老师的生日是下列 10 组中的一天,张老师把 M 值告诉了小 刘,把 N 值告诉了小红,然后问他们老师的生日到底时哪一天?3 月 4 日、 3 月 5 日、 3 月 8 日、 6 月 4 日、 6 月 7 日、 9 月 1 日、 9 月 5 日、 12 月 1 日、 12 月 2 日、 12 月 8 日。小刘说:如果我不知道的话, 小红肯定也不知道。小红说:刚才我不知道,听小红一说我知道了。小刘说:哦, 那我也知道了。请根据以上对话推断出张老师的生日是哪一天46.哪位小姐养蛇?一道著名的逻辑分析题, 有信心的朋友们可以试着分析一下, 看 你的智商有多高? 有五位小姐排成一列, 这五位小姐的姓氏不同, 衣服的颜色、喝的饮料、喜欢的宠物、吃的水果都不相同。1.钱小姐穿红色衣服2.翁小姐养了一条狗3.陈小姐喜欢喝茶4.穿白色衣服的在穿绿色衣服的右边5.穿绿色衣服的小姐在喝咖啡6.吃西瓜的小姐养了一只鸟7.穿黄色衣服的小姐在吃梨8.在中间站着的小姐和牛奶9.在最左边站着的是赵小姐10. 吃桔子的小姐站在养猫小姐的旁边11. 吃梨小姐的旁边站在养鱼小姐的旁边12. 吃苹果的小姐在喝香槟13. 江小姐在吃香蕉14. 蓝色衣服小姐的旁边站的是赵小姐15. 吃桔子的小姐的旁边站在喝开水小姐问题出来了,请问:养蛇的是哪位小姐?47.谁说了假话?张、王、李、赵四人的血型各不相同,张说:我是 A 型。王说: 我是 O 型。李说: 我是 AB 型。赵说: 我不是 AB 型。这四个人中只有 一人说了假话。请问:以下哪项成立?A.不管谁说了假话,都能推出四个人的血型情况。B.王的话假, 可以推出。C.李的话假, 可以推出。D.赵的话假,可以推出。48.找出正确的做法侯同学的以下实验操作中正确的是?(请写出分析过程。)A.用酒精提取碘水中的碘。B.有 CC14 分离苯和溴苯。C.用裂化汽油提取溴水中的溴。D.将金属钠保存到十二烷中。49.哪只兔子死掉了在一个茂密的森林里, 有 10 只兔子,大兔子病了, 二兔子瞧, 三兔子买药, 四兔子熬, 五兔子死了, 六兔子抬, 七兔子挖坑, 八兔 子埋, 九兔子坐在地上哭起来, 十兔子问他为什么哭?九兔子说: “五兔子意外死去! ”这是一件密谋杀兔事件。请问:哪知兔子死掉了?50.谁和谁是夫妻有四对夫妻, 赵结婚的时候张来送礼, 张和江是同一排球队队员, 李的爱人是洪的爱人的表哥。洪夫妇与邻居吵架, 徐、张、王都来助 阵。李、徐、张结婚以前住在一个宿舍。请问: 赵、张、江、洪、李、徐、王、杨这八个人谁是男谁是女, 谁和谁是夫妻?51.结果如何ABCD 四人参加公务员考试, 报考同一职位。该职位只招录一人,
有且只有该四人报名。四人均准备充分,在考试中发挥出最高水平。考试结束后,四个人讨论如下:A:只要考试不黑,我肯定能考上。B:即使考试不黑,我也考不上。C:如果考试不黑,我就能考上。D:如果考试很黑,那么,我肯定考不上。结果出来后, 证明 ABCD 四人预测均正确, 则有一人成功考取, 则可推出公务员考试:A.黑B.不黑C.有时黑, 有时不黑52.哪种说法对?在人口统计调查的过程中, 男女比例相当, 但是, 黄种人跟黑种 人相比多得多。在白种人中, 男性比例大与女性, 由此可见, 请选择以下正确的说法:A.黄种女性多于黑种男性B.黑种女性少于黄种男性C.黑种男性少于黄种男性D.黑种女性少于黄种女性最佳答案:初级题:1. 分析: 需要注意的是题目中所给的数字是无用的, 因为第一 句话说: “你是司令“,所以司令的年龄,就是读者你的年龄。2.答案:星期二分析: 星期五的前一天是星期四, 今天的前两天是星期五, 所以 我们可以知道今天是星期日, 那么星期日的明天的后一天, 即后天是 星期二。3. 分析: 这是个偷换概念的问题, 每人每天 9 元, 老板得到 25 元,伙计得到 2 元, 27=25+2.不能把客人和伙计得到的钱加起来。4.答案:选 C分析: 有条件 1 可得, 其余的四种颜色, 黄绿蓝白为两组互为对 色的颜色, 又有 2、3 可得: 白色与黄色为对面, 蓝色与绿色为对面。 所以选 C。5.分析:教练下令“单数”运动员出列时,教练只要下 5 次命 令, 就能知道剩下的那个人。此人在下第五次令之前排序为 2, 在下 4 次令之前排序为 4,在下 3 次令之前排序为 8,在下 2 次令之前排 序为 16, 在下 1 次令之前排序为 32,即 32 位运动员。而后者, 双数 运动员出列时, 我们可以得出剩下的是 1 号运动员。因此:前者 32 号, 后者 1 号。6.答案:这道题如果换一个问的方式,就很好回答, 要是一只 钟是停的, 而另一只中每天慢一分钟, 你会选择哪个呢?当然你会选 择每天只慢一分钟的钟。本题就是这样, 两年准一次, 也就是一天慢 1 分钟, 需要走慢 720 分钟,也就是 24 小时,才能在准一次,也就是需要两年,而每天准 两次的钟是停的。因此,选择每年准两次的钟。7. 答案: 切下管子的 hh 端, 装到另一端, 成为 hhyyyyhh; 或者 如果可以歪曲管子也可以达到这个效果。8.答案: 我们知道, 八双袜子的质量和大小完全相同。因此, 可 以让他们把标签撕下来, 按顺序每人取一只, 重新组合在一起就可以 了。9.答案: “男女”的房间。分析: 因为确定每个牌子都是错的, 所以挂有“男女”牌子的房 间一定是只有“男”或只有“女”。很容易就能判断出来了。确定了这 个,其中两个也就出来了。10. 答案: 一共耗时 45 分钟。分析: 第一步: 点燃蜡烛 A 的两头, 并点燃蜡烛 B 的一头, 共用30 分钟。第二步: 当蜡烛 A 燃烧完后, 再点燃蜡烛 B 的另外一头, 待蜡烛 B 燃烧完后,用 15 分钟。11. 分析: 第一步: 对前三个进行比较大小, 对于最大的心里要有一个概念。第二步:中间 3 个作为参考, 确认最大的一个的平均水平。第三步: 在最后 4 个中选择一个属于最大一批的, 闭上眼睛不再 观察之后的。这就是最大的一颗。12. 答案: 称量出 20g,倒入另一份 70g 中,获得 50g,90g。分析:第一步:将盐分为两个 70g,取出其中一份。第二步:利用两个砝码称出 9g。第三步: 利用9g 盐和2g 砝码称出 11g。13. 答案: 10 年可能 3653 或者 3652 天。分析:假如, 第 1 年为闰年, 则第 5 年, 第 9 年也为闰年。共 3563 天。假如, 第 2 年为闰年, 则第 6 年, 第 10 年也为闰年。共 3563 天。假如,第 3 年为闰年, 则第 7 年为闰年,共 3652 天。 假如,第 4 年为闰年,则第 8 年为闰年,共 3652 天。14. 答案: 总共是 17 分钟分析:第一步: A、B 过花时间 2 分钟。第二步: B 回花时间 2 分钟。第三步: C、D 过花时间 10 分钟。第四步: A 回花时间 1 分钟。第五步: A、B 再过花时间 2 分钟。15. 分析: 第一步:打开开关 A,5 分钟后关闭开关 A;第二步:打开开关 B;第三步: 进入卧室, 开关 B 控制的是亮着的灯, 用手去摸不亮的 灯,发热的是开关 A 控制的灯,不发热的是开关 C 控制的灯!16. 答案: 只要问其中一个: “你认为另一个守门人会说他守的是生门还是死门? ”就可以知道那扇是生门, 那扇是死门。分析: 问其中一位守门员, 如果回答是生门即实际是死門, 反则 生门。或者问:“对方认为哪边是死門?”看他会指向那扇门?17. 答案: 环形摆放。分析: 如果想使 5 根铅笔首尾相接, 也就是说没跟铅笔的头部要与另一支铅笔的尾部相接, 这样才能达到 5 根铅笔首尾相接的效果。 所以将他们组成一个封闭的图形, 所以应将它们按照环行摆放。18. 分析: 由于他们没有办法, 他们都想:1.(1) 如果他坦白: 我坦白, 5 年; 不坦白, 10 年。坦白更好; 2.(2) 如果他不坦白: 我坦白, 1 年; 不坦白, 3 年。坦白更好。 因此他们都选择了“坦白”。19.分析: 43。其读音是“四十三”, 去掉“四”为“十三”, 去掉 “三”为“四十”。即这个数字是“四十三”。20.分析:只要把药片全部碎成粉末, 搅匀后平均分成 10 份,一天吃一 份。中级题21. 分析及答案: 一共需要 10 架飞机。假设绕地球一圈为 1,每
架飞机的油只能飞 1/4 个来回。从原机(也就是要飞地球一圈的飞机) 飞行方向相同的方向跟随加油的飞机以将自己的油一半给要供给飞机为原则, 那跟随飞机就只能飞 1/8 个来回。推理得以四架供一架飞 机飞 1/4 的方法进行,那么原机自己飞行 1/4 到 3/4 的那段路程, 0 至 1/4 和3/4 至4/4 由加油机加油供给, 就是给 1/2 的油, 原机就能 飞 1/4 了, 所以跟随和迎接两个方面分别需要供油机在 1/4 处分给原 机一半的油, 供油机在 1/4 处分完油飞回需 4 架飞机供油, 所以综上 所述得( 1+4) ×2= 10。22.分析及答案: 在国王宣布过第 1 条命令后,过了一段时间, 仍没人被释放。因此, 可以证明 3 顶帽子中没有 2 顶红帽, 也可以说 三个人中可能有 2 黑 1 红, 或者 3 黑。于是出现了两种情况: 假设 A 戴的是红帽,于是他就看见了 2 顶黑的。B 和 C 都可以看见 1 黑 1 红。 但是既然红的在 A 头上, 那么 B 和 C 都是黑的。那么 B 和 C 早就能确 定自己带的是黑帽。所以 A 不可能戴红帽。因此 A 推定自己头上戴的 肯定是黑帽。因为只有出现 3 顶黑帽, 才没有人敢确定红帽是否在自 己头上。聪明的你想到了吗?23. 分析及答案:1.(1)第 2 个数字比第 1 个数字多 3,第 3 个数字比第 2 个数 字多 3,第 4 个数字也比第 3 个多 3, 这像是一个等差数列, 差是 3。 按这个想法, 应该填 13,16, 那接下来 19,22,25 都符合这个规律。2.(2) 仔细观察,你会发现每个数字的差不一样,后面的基本 都比前面的大, 有什么规律呢?第 3 个数字 2 是第 1 个和第 2 个数字的和, 第 4 个数字 3, 是第 2 个和第 3 个数字的和, 每个数字都是它 前面两个数字的和。按这个想法, 应该填 13,21, 在后面的 34 正好 等于 13+21,55 也正好等于 21+34,按照这样的规律填即可。3.(3) 这一组数字,后面的数字都比前面的大, 那差分别多少 呢?看看,21=1,42=2,74=3,117=4,1611=5……你看出规律了吗?每一个数字根前面数字的差都增加 1。那这样 应该填 22,29,后面正好也符合这个规律。4.(4) 首先可以看出后面的数字比前面的数字大,大多少呢? 3,5,7。这个规律成立吗?试试看, 填进大 9 和 11 的数字, 得到 25, 36。36+13=49,49+15=64。正好成立。24. 分析: 从杰克的猜测中, 我们可知只有“汤姆斯买的肯定不 是皇冠车”这种猜测是正确的, 那么他买的就只能是本田或奔驰。吉 米应该买的不是奔驰,只能是皇冠或本田,那么吉米买的是皇冠车, 瑞恩买的是奔驰车,汤姆斯买的是本田车。25. 分析: 因为 1 号、 2 号、 3 号三人共得分为 22+9+9=40 分, 又因为三名得分均为正整数且不等,所以前三名得分最少为 6 分。 40=5*8=4*10=2*20=1*20,不难得出项目数只能是 5。即 N=5。1 号总共得 22 分,共 5 项,所以每项第一名得分只能是 5, 22=5*4+2,故 1 应得 4 个一名 1 个二名.第二名得 1 分, 又因为 2 号百米得第一,所以 1 只能得这个第二。2号共得9分,其中百米第一5分,其它4项全是 1分,9=5+1=1+1+1。 即 2 号除百米第一外全是第三,跳高第二必定是 3 号所得。26. 因为 21 岁的女孩不是去了 A 岛(印玉)(③), 所以, 21 岁的是张虹。所以可推断, 19 岁的是印玉。姓名年龄岛卵张虹 21 岁 1 个或 2 个印玉 19 岁 A1 个或 2 个东晴 18 岁西雨 20 岁 3 个假设张虹有 2 个的话, 那么印玉就有 3 个(③), 这与④相互矛 盾的。所以,张虹是 1 个,印玉是 2 个。因此可知, C 岛是发现了 2 个(⑤),去 C 岛的是东晴。根据条件⑥可知,张虹去了 D 岛,剩下的西雨去了 B 岛。 所以,结果就是:姓名年龄岛卵张虹 21 岁 D1 个印玉 19 岁 A2 个东晴 18 岁 C2 个西雨 20 岁 B3 个27. 答案: 小圆能转 3 周。分析:两圆的直径分别为 2、4, 那么半径分别为 1、2。假如把 大圆剪开并拉直, 那么小圆绕大圆转一周, 就变成从直线的一头移动 到另一头。因为这条直线长就是大圆的周长, 是小圆周长的 2 倍, 所 以小圆需要滚动 2 圈。但现在小圆在沿大圆滚动的同时, 自身还要作转动。小圆在沿着 大圆滚动 1 周并回到原出发点的同时, 小圆自身也转了 1 周。如果小 圆在大圆的内部滚动, 其自转的方向与滚动的转向相反, 因此小圆自 身转了 1 周; 如果小圆在大圆的外部滚动, 其自转的方向与滚动的转 向相同, 因此小圆自身转了 3 周。28. 答案: 甲班班长懂计算机。分析: A 与 B 是等值关系, 真假情况完全相同, 假如 C 真, 那么 B 也是真的。因为这三个判断中只有一个是真的,所以只能是 B 与 C假, A 真。A 如果是假的, 意味着“甲班所有的同学懂计算机”真, 这是因 为 B 与“甲班所有的同学懂计算机”是矛盾关系。既不可以同时使真 的, 也不可以同时都是假的, 如果有一个是假的, 那么另一个必定是 真的。另外, 如果甲班所有的同学懂计算机, 那么说明甲班班长也懂 计算机。29. 答案: C 工厂参加鉴定。分析: 如果 B 工厂不参加鉴定, 那么 A 工厂也不参加; 如果 B 工 厂参加鉴定,那么 A 工厂和 C 工厂也要参加; A 工厂参加鉴定。1.(1) 如果 B 工厂不参加鉴定, 那么 A 工厂也不参加。2.(2) A 工厂参加鉴定。所以, B 工厂参加鉴定。3.(3) 如果 B 工厂参加鉴定, 那么 A 工厂和丙工厂也要参加。B 工厂参加鉴定。所以, A 工厂参加时, C 工厂也会参加。30. 答案: 岳飞。分析: 孙某说:“如果我不知道的话, 张某肯定也不知道。”那名 字和姓肯定有多个选择的, 排除沈、万、三和张良, 把姓沈和姓张也 同时排除。现在剩下: 赵括、赵云、赵鹏、岳飞、岳云。张某说:“刚 才我不知道, 听孙某一说, 我现在知道了。”所以肯定是多选的排除:那就是“云”,剩下:赵括、赵鹏、岳飞。最后: 孙某说:“哦, 我也知道了。”那姓肯定是惟一的, 那只有 “岳飞”了。31. 分析: 想要使三个人都得到心里平衡, 分汤的方法就必须要 公平、公正、公开。因此, 可以得出以下结论:第一步:让第一个人将汤分成他认为均匀的三份。第二步: 让第二个人将其中两份汤重新分配, 分成他认为均匀的 2 份。第三步: 让第三人第一个取汤, 第二人第二个取汤, 第一人第三 个取汤。32. 把软木塞按进去。答案: 5 岁的孩子说: “老爷爷, 这个房子我租了。我没有孩子, 我只带来两个大人。 ”房东听了, 感觉孩子确实很乖, 于是把房子租 给了他们。33. 分析: 如果真的是他老公杀的话, 死者就不可能说: “他不 知道我在录音, 我要关录音机了。 ”如果被杀者录音并不被杀人者所 知, 录音不会有卡擦声, 这样被杀人就可能知道录音机所在何处, 离 开时也会同时把录音机销魂,就不会存在这个录音了。34. 答案:选 A。分析: 在选项 B 中, 有免费师范生入学, 一定有贫寒生入学, 因 为免费师范生是贫寒的。 C 选项免费师范生一定贫寒, 一定参加勤工 助学, 没参加勤工的一定不是免费师范生。 D 有些参加勤工的指的就 是那些 2007 秋季入学的免费师范生。排除得 A 错误,原因在于那年 勤工助学的可能就是那几个免费师范生,没其他人。35. 答案:选 C分析: 2 正确, 因为肯定有中老年教员办人寿保险, 所以肯定没办财产保险。 3 正确, 买四居室以上都办了财保, 办人寿的没办财保,
办财保的也肯定没办人保, 所以这些大户都没办人保。 1 不能断定, 大多数买人保, 也可以有人买了四居室以下也没买人保的。36. 答案:选 D分析: 由题目得, 第一和第四个杯子一定有句真话, 因为这两句话是 矛盾的。假设第一个杯子是真话, 第二个杯子就是假话, 第三个杯子 是真话, 有 2 句真话矛盾。所以第四个杯子说的是真话, 其他三个杯 子都是假话! A 排除。 B 也排除,因为有些杯子没有糖,有些杯子是 有的, 例如, 第一个杯子有糖, 第二个有糖, 第三个有巧克力, 第四 个有苹果。由此可以看出, C 也不对。只有 D 是真的, 如果第三个杯 子没有巧克力, 那么就有 2 句话是真的了。高级题:37. 分析: 第一步: 猎人与狼先乘船过去, 放下狼, 回来后再接 女人的一个孩子过去。第二步:放下孩子将狼带回来, 然后一同下船。第三步: 女人与她的另外一个孩子乘船过去, 放下孩子, 女人再 回来接男人;第四步: 男人和女人同时过去, 然后男人再放下女人, 男人回来下船,猎人与狼再上去。第五步:猎人与狼同时下船, 然后,女人再上船。第六步: 女人过去接男人, 男人划过去放下女人, 回去接自己的一个孩子。第七步: 男人放下自己的一个孩子, 把女人带上, 划回去, 放下女人,再带着自己的另外一个孩子。第八步: 男人再回来接女人。38.分析:第一个人选择 17 颗豆子时,存活几率最大。他有先动 优势。他有可能被后面的 2、3、4、5 号逼死, 但可能性不大。假如 第 1 个人选择 21 颗豆子,那么 1 号将自己暴露在一个非常不利的环 境下。 24 号就会选择 20, 五号就会被迫在 119 中选择, 则 1、5 号处死。所以, 1 号会选择一个更小的数。如果 1 号选择一个小于 20 的数, 2 号就不会选择与他偏离很大 的数。因为如果偏离大, 2 号就会死, 只会选择+1 或 1, 离死的概率 会小一些。当考虑这些的时候, 必须要学会逆向考虑。 1 号需要考虑2、3、4 号的选择, 2 号必须考虑 3、4 号的选择, 而 5 号会没有选择。用 100/6=16.7,1 号最终必然是在 16、17 中做选择,这样的几 率会很大。在分别对 16、17 计算概率后,得出有 3 个人会选择 17, 如果第四个人选择 16, 则为均衡的状态, 但是 4 号选择 16 不及前三 个人选择 17 生存的机会大; 若 4 号也选择 17, 那么整个游戏的人都 要死(包括他自己)! 因此, 只有按照 17、17、17、16、N(133 随机)选择时, 1、2、3 号的生存机会最大。39. 答案: A 是北区人; B 是南区人, 获得铜牌; C 是中区人; D是局外人,获得金牌; E 是局外人,获得银牌。分析: 说话者之中有一个是南区人, 一个是中区人, 一个是北区人,两外两个时局外人。E 第 3 次说的话是真实的, B 的第四次陈述是真实的,因为 E 可 以肯定要么是中区人,要么是两个局外人之一。C 第 1 次说的可能是虚假的, 也可能是真实的。如果是真实的, B 要么是南区人, 要么是两个局外人之一。如果是假的, 那么 C 就是 中区人。D 第 4 次陈述, 即 C 不是北区人, 是真实的。因此, B、C、D、E每个人至少有一次真实的陈述。因此, A 是北区人,此陈述是假的。A 第 2 次陈述, 即 B 不是南区人, 是虚假的。那么, B 是南区人,此说法是真的。B 第 2 次陈述,即 C 的第一次陈述是虚假的,所以 C 是中区人。C 第 1 次和第三次是虚假的, 第二次和第四次陈述是真实的。以 此,也可以推出 D 和 E 是两个局外人。A 第 3 次陈述是虚假的, D 赢得了金牌。B 第 1 次陈述是真实的, E 赢得了银牌。C 第 3 次陈述, 即 B 没有赢得铜牌,是虚假的, B 赢得了铜牌。D 第 1 次和第四次陈述是真实的,第二次和第三次陈述是虚假的。E 第 2 次和第三次陈述是真实的,第一次和第四次陈述是虚假的。40. 从题意中可以很明显的发现小甜和小蜜并不是主人, 而是水 缸里养的两条金鱼, 所以李管家并没有报警。因为没有其他人在房间, 而水缸是不会自己翻倒的。安卡一日后被解雇了, 因为她在工作中太不小心, 打碎了水缸,致使两条金鱼意外死亡。所以,李管家把安卡解雇了。41. 答案: 3 条病狗。分析:1.(1) 假如有 1 条病狗,那主人肯定不能看自己家的狗, 出去 没有发现病狗, 但村长却说有病狗。他就会知道自己家的狗是病狗, 那么第一天就应该有枪声, 但是事实上大家并没有听到枪声, 因此推出病狗不是一条。2.(2) 假如有 2 条病狗,设为甲家和乙家。第一天甲和乙各发 现对方家的狗是病狗, 但是第一天没有听到枪响。第二天就会意识到 自己家的狗也是病狗。接着第二天就应该有枪响,但事实上也没有,所以 2 条病狗也不对。3.(3)假设有 3 条病狗,设为甲、乙、丙家。第一天甲、乙、 丙各发现 2 条病狗, 他们就会想第二天晚上就会有枪响, 但是第二天 晚上没枪响, 第三天晚上他们就会意识到自己家的狗也有病, 所以开 枪杀狗。因此通过假设,我们可以看出这个村里有 3 条病狗。42. 分析: 如果是一天早上 8 点, 有“两个”和尚分别从山上的 庙和山脚同时出发, 并且只有一条路可走, 你想他们是不是一定会相遇。换一种说法, 就是小和尚在同一钟点到达山路上的同一地点。回到问题, 星期一和星期二都是 8 点出发, 又是相向的走同一条 路, 如果能跨越时间思维的局限, 星期一和星期二都的 8 点出发看成 是小和尚有分身之术同一天的 8 点分别从山上的庙和山脚出发“今 天的小和尚必然和昨天的自己”相遇就不难理解了。这样, 就能证明 小和尚能在同一钟点达到同一地点了。43. 答案: 一共有 15 搜船。分析: 首先我们先想一下, 从美国纽约开往勒阿佛的海航线上总 会有 7 艘轮船, 只有每天中午时, 只有 6 艘轮船, 每两艘轮船相距一 天路程。今天中午从勒阿佛开出的船每半天(12 小时)会遇到一艘从 纽约来的船横渡一次的时间是 7 天 7 夜,本应是会遇到 14 艘, 可是 从勒阿佛开出的船是中午开出。因此最后一艘是在美国纽约遇到的, 第一艘是在法国勒阿佛遇到的,所以正确答案是:路途中遇到 13 艘 从纽约来的船。然后, 还要加上在勒阿佛遇到的刚刚到达的从纽约来 的一艘船,还要加上在美国遇到的准备出发的一艘船。44. 分析:第 1 次称量: 天平左端放 27 个球。右端也放 27 个球。有 2 种可能性: A 平衡、 B 不平衡。如果平衡了, 那么下一次就以余留的 80- 27-27=26 个球作为研究对象。如果不平衡,那面选择轻的一端的 27 各球作为第二次称量的物品。第 2 次称量: 天平左右两边都放 9 个球。研究对象中还有 8~9 个球没有放入天平中。有 2 种可能性: A 平衡 B 不平衡。如果平衡了, 那么下一次就以余留的 8~9 个球作为研究对象。如果不平衡,那么就选择轻的一端的 9 各球作为下次称量的物品。第 3 次称量: 左右两边个放 3 各球。研究对象中还有 23 个球没 有放入天平中。有 2 种可能性: A 平衡 B 不平衡。如果平衡了, 那么 下一次就以余留的 2~3 个球作为研究对象。如果不平衡,那么就选 择轻的一端的 3 个球作为下一次称量的物品。第 4 次称量: 天平的左右两边各放 1 个球。研究对象中还有 0~ 1 个球没有放入天平中。有 2 种可能性: A 平衡 B 不平衡。如果平衡 了, 那么余留的另一个球就是要找的球。如果不平衡, 那么轻的一端 就是你要找的球。45. 答案: 9 月 1 号。分析:首先, 我们来分析一下这 10 组日期,经观察不难发现, 只有 6 月 7 日和 12 月 2 日这两组日期的日数是唯一的。由此可以看 出, 假如小红知道的 N 是 7 或者 2, 那么她肯定知道老师的生日时哪 一天。再次,我们来分析一下小刘说的话,小刘说:“如果我不知道的话, 小红肯定也不知道”, 而该 10 组日期的月数分别为 3,6,9,12, 而且相应月的日期都有两组以上, 所以小刘得知 M 后是不可能知道老 师生日的。进一步分析, 小刘说:“如果我不知道的话, 小红肯定也不知道”, 通过结论 2 我们可知小红得知 N 后也绝不可能知道。然后,结合 1 和 3 的分析,可以推断:所有 6 月和 12 月的日期 都不是老师的生日,因为如果小刘得知的 M 是 6,而若小红的 N=7, 则小红就知道了老师的生日。同样的道理, 如果小刘的 M= 12, 若小红的 N=2, 则小红同样可
以知道老师的生日。即: M 不等于 6 和 9。现在只剩下 “3 月 4 日、 3
月 5 日、 3 月 8 日、 9 月 1 日、 9 月 5 日”五组日期。而小红知道了,
所以 N 不等于 5 (有 3 月 5 日和 9 月 5 日), 此时, 小红的 N∈( 1,
4,8)注: 此时 N 虽然有三种可能, 但对于小红只要知道其中的一种,
就得出结论。所以有“小红说: 本来我也不知道, 但是现在我知道了”, 通过这样的推理, 最后就剩下 “3 月 4 日、 3 月 8 日、 9 月 1 日”三
个生日。分析“小刘说: 哦, 那我也知道了”, 说明 M=9,N= 1,(N=5 已 经被排除, 3 月份的有两组)。因此正确答案应该是 9 月 1 日。46. 答案: 江小姐养蛇。分析:左、左二、中、右二、右赵、陈、钱、江、翁黄、蓝、红、绿、白开水、茶、牛奶、咖啡、香槟梨、桔子、西瓜、香蕉、苹果猫、鱼、鸟、蛇、狗用表格来表示为:姓物品 9.赵 3.陈 1.钱 13.江 2.翁衣 7.黄 14.蓝 1.红 4.绿 4.白饮料 15.开水 3.茶 8.牛奶 5. 咖啡 12.香槟宠物 10.猫 11.鱼 6.鸟 2.狗水果 7.梨 10.桔子 6.西瓜 13.香蕉 12.苹果47. 答案:选 B.分析: 1.(1) 如果赵不是 AB 是假的,则其余必真, 赵是 AB 型与李也是 AB 型,血型各不相同矛盾: 所以丁必真。2.(2) 如果李是 AB 是假的, 则其余真, 即李必为 B 型, 但赵不是 AB 真也必为 B 型矛盾:所以李必真。3.(3) 如果王假甲真, 其余真, (张 A,李 AB)丁 O,王 B 是可以 的。4.(4) 如果张假王真, 其余真, (王 O,李 AB)丁 A,张 B 是可以 的。综上所说, 3 和 4 都无法确定谁真谁假, 张假可以推出, 王假可以推出, 但李、赵说假话的题目就错了, 什么都推不出。 A 无论谁说 假话范围太大, 应该说无论张、王哪个说假话都可以推出: A、B、C、 D 只有一个正确答案,那就是 B。48. 答案:选 D。分析:A 中的酒精可以溶解碘, 所以提取后会得到酒精、水和碘三者组 成的溶液,不符合提取的要求,所以不能用酒精萃取碘水中的碘。B 的道理和 A 比较相似, 由于四氯化碳、苯、溴苯三种有机物可以两两互溶,也不符合提取条件。C 中的裂化汽油里含有烯烃等不饱和烃,容易与溴发生加成反应,所以不能用裂化汽油萃取溴水中的溴。D 的说法是正确的,由于十二烷是液态的有机物,不会与钠反应,
而且可以起到隔绝空气和水的作用。所以可把金属钠保存到十二烷中。49. 答案: 五兔和六兔。分析:1.(1) 首先,兔子也是分阶级的, 因为大兔子病了, 如果要救 她,就必须牺牲一切代价, 甚至牺牲一只兔子,也救他。2.(2) 其次, 生病的是大兔子, 可死的却是五兔子, 很显然, 五 兔子是被做成了药引。3.(3) “买药”其实一句黑话,实际上草药并不需要那么多,主要是药引。因此这个“买药”实际上是说指要去杀兔子做药引, 所 以断定三兔子是一个杀手。4.(4) 也许你不明白, 被做成“药引”的为什么首先是五兔?
其实这个原因很简单, 是不是和做药引, 医生说了算, 二兔子就是医 生。5.(5) 因此, 我们可得知, 二兔子“借刀杀人”搞死了五兔子。6.(6) 你知道那只兔子是母兔吗? 想一下,爱哭,是女人的天 性。因此我们知道九兔是一只母兔, 九兔知道了真相, 所以才酷哥不停。7.(7) 可以断定“六兔子抬是一个病句, 因为一只兔子根本就 没有办法抬。他显然是被抬, 因为他死了, 所以才会被抬。而抬他的就是事后挖坑、埋尸的兔子,即七兔子和八兔子。8.(8) 看到这里, 你肯定认为六兔子是被七、八两只兔子所杀。 其实不然, 他是被杀手三兔子杀死的。三兔子本来没想杀他, 可它和 五兔子的关系非常好, 当时它们正好在一起, 并联手对付它, 因此三 兔子借机把他们两个同时杀了。50. 答案: 洪与江、李与王、赵与徐、张与杨为夫妻。分析: 首先分析性别, 因为李的爱人是洪的爱人的表哥, 所以说 明李是女性, 当然, 与李在结婚前同住在一个宿舍的徐和张也为女性。 所以我们得出了:男: 赵、洪、王、杨女: 李、徐、张、江接下来分析夫妻关系, 从洪入手, 因为洪夫妇和邻居吵架, 徐、 张、王来帮忙, 说明了洪的对象不能是徐和张所以洪的对象有两个可能: 李和江。但是由于李的爱人是洪的爱 人的表哥,所以否定了李, 洪与江是对象。下来分析李的爱人: 因为洪夫妇与邻居吵架, 徐、张、王都来助 阵, 这里只有王是男性, 而且李的爱人是洪的爱人的表哥。所以说明 王很有可能就是江的表哥, 也就是李的丈夫。这样我们分析出了王与李是一对。剩下的男性还有赵和杨, 女性还有张和徐。第一句说了: 赵结婚 的时候张来送礼, 说明赵不是和张结婚, 所以赵和徐是夫妻。而张和 杨是夫妻。51. 答案: 选择 B分析如下:A:只要考试不黑,我肯定能考上。因为不黑,所以 A 考上了 B:即使考试不黑,我也考不上。因为不黑,他可能考不上C:如果考试不黑,我就能考上。因为不黑,所以他考不上D: 如果考试很黑, 那么, 我肯定考不上。因为不黑, 他有可能考 上或是考不上上面四种分析后没有出现冲突,因此选 B。52. 答案:选 A分析: 在世界总人口中, 男女比例相当, 但是, 黄种人跟黑种人 相比多得多。在白种人中, 男性比例大与女性,由此可见:1.(1) 黄男+黄女>黑男+黑女2.(2) 黄男+黑男+白男=黄女+黑女+白女3.(3) 白男>白女通过 3(3), 2(2)推出 4(4):黄女+黑女>黄男+黑男结合 1( 1), 4(4) 相加,得出 5(5): 黄男+黄女+黑女+黄女>黑男+黑女+黄男+黑 男所以:黄女>黑男小学语数英资料合集以及电子版获取方式都在下方链接,请自行查看

我要回帖

更多关于 python asyncio 的文章

 

随机推荐