温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么理解Python猴子补丁

发布时间:2021-11-01 17:10:12 阅读:185 作者:iii 栏目:编程语言
Python开发者专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

这篇文章主要介绍“怎么理解Python猴子补丁”,在日常操作中,相信很多人在怎么理解Python猴子补丁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么理解Python猴子补丁”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

题目:谈谈你对“猴子补丁”(monkey patching)的理解。

“猴子补丁”是动态类型语言的一个特性,代码运行时在不修改源代码的前提下改变代码中的方法、属性、函数等以达到热补丁(hot patch)的效果。很多系统的安全补丁也是通过猴子补丁的方式来实现的,但实际开发中应该避免对猴子补丁的使用,以免造成代码行为不一致的问题。

在使用gevent库的时候,我们会在代码开头的地方执行gevent.monkey.patch_all(),这行代码的作用是把标准库中的socket模块给替换掉,这样我们在使用socket的时候,不用修改任何代码就可以实现对代码的协程化,达到提升性能的目的,这就是对猴子补丁的应用。

另外,如果希望用ujson三方库替换掉标准库中的json,也可以使用猴子补丁的方式,代码如下所示。

import json, ujsonjson.__name__ = 
'ujson'json.dumps = ujson.dumpsjson.loads = ujson.loads

单元测试中的Mock技术也是对猴子补丁的应用,Python中的unittest.mock模块就是解决单元测试中用Mock对象替代被测对象所依赖的对象的模块。

怎么理解Python猴子补丁

题目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 --> B --> C --> A --> object。

ACBD

题目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) == 
0def 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 remessage = 
'hello, world!'pattern = re.compile('[aeiou]')print(pattern.sub('#', message))

扩展:还有一个面试题,列表中保存了一系列的文件名,如filenames = ['a9.txt', 'a12.txt', 'a8.txt', 'b2.txt', 'b19.txt','a3.txt'],对这些文件名进行排序,要求按照字面表和数字大小进行排序,简单的说就是a9.txt会排在a12.txt的前面,b2.txt会排在b19.txt的前面。大家可以思考下这个问题如何解决。

题目35:如何剖析Python代码的执行性能?

剖析代码性能可以使用Python标准库中的cProfile和pstats模块,cProfile的run函数可以执行代码并收集统计信息,创建出Stats对象并打印简单的剖析报告。Stats是pstats模块中的类,它是一个统计对象。当然,也可以使用三方工具line_profiler和memory_profiler来剖析每一行代码耗费的时间和内存,这两个三方工具都会用非常友好的方式输出剖析结构。如果使用PyCharm,可以利用“Run”菜单的“Profile”菜单项对代码进行性能分析,PyCharm中可以用统计表格(Statistics)或者调用图(Call Graph)的方式来显示性能剖析的结果。

下面是使用cProfile剖析代码性能的例子。

example.py

import 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装饰器,代码如下所示。

@profilerdef 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

到此,关于“怎么理解Python猴子补丁”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:http://blog.itpub.net/69923331/viewspace-2698471/

AI

开发者交流群×