快捷搜索:  

简述装饰器的应用场景 python装饰器有什么用

python装饰器有什么用

先来个形象比方

内裤可以用来遮羞,但是到了冬首迹纳天它没法为我们防风御寒,聪明的人们发明了长裤,有了长裤后宝宝再也不冷了,装饰器就像我们这里说的长裤,在不影响内裤作用的前提下,给我们的身子提供了保暖的功效。

再回到我们的主题

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

先来看一个简单例子:

def foo():
print("i am foo")

现在有一个新的需求,希望可以记录下函数的执行日志,于是在代码中添加日志代码:

def foo():
print("i am foo")
logging.info("foo is running")

bar()、bar2()也有类似的需求,怎么做?再写一个logging在bar函数里?这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门处理日志 ,日志处理完之后再执行真正的业务代码

def use_logging(func):
logging.warn("%s is running" % func.__name__)
func()def bar():
print("i am bar")use_logging(bar)

逻辑上不难理解,
但是这样的话,我们每次都要将一个函数作为参数传递给use_logging函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑时,执行运行bar(),但是现在不得不改成use_logging(bar)。那么有没有更好的方式的呢?当然有,答案就是装饰器。


简单装饰器
def use_logging(func):

def wrapper(*args, **kwargs):
logging.warn("%s is running" % func.__name__)
return func(*args, **kwargs)
return wrapperdef bar():
print("i am bar")bar = use_logging(bar)bar()

函数use_logging就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像bar被use_logging装饰了。在这个例子中,函数进入和退出时
,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。

@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作


def use_logging(func):

def wrapper(*args, **kwargs):
logging.warn("%s is running" % func.__name__)
return func(*args)
return wrapper@use_loggingdef foo():
print("i am foo")@use_loggingdef bar():
print("i am bar")bar()

如上所示,这样我们就可以省去bar =
use_logging(bar)这一句了,直接调用bar()即可得到想要的结果。如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增者没加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。


带参数的装饰器

装饰器还有更大的灵活性,例如带参数的装饰器:在上面的装饰器调用中,比如@use_logging,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时州缓,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。

def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
logging.warn("%s is running" % func.__name__)
return func(*args)
return wrapper

return decorator@use_logging(level="warn")def foo(name="foo"):
print("i am %s" % name)foo()

上面的use_logging是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当我
们使用@use_logging(level="warn")调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。


类装饰器

再来看看类装饰器,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的\_\_call\_\_方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。


class Foo(object):
def __init__(self, func):
self._func = func

def __call__(self):
print ("class decorator runing")
self._func()
print ("class decorator ending")

@Foo
def bar():
print ("bar")

bar()

functools.wraps

使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子:

装饰器

def logged(func):
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging

函数

@loggeddef f(x):
"""does some math"""
return x + x * x

该函数完成等价于:


def f(x):
"""does some math"""
return x + x * xf = logged(f)

不难发现,函数f被with_logging取代了,当然它的docstring,__name__就是变成了with_logging函数的信息了。

print f.__name__    # prints "with_logging"print f.__doc__     # prints None

这个问题就比较严重的,好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

from functools import wrapsdef logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging@loggeddef f(x):
"""does some math"""
return x + x * xprint f.__name__  # prints "f"print f.__doc__   # prints "does some math"

内置装饰器

@staticmathod、@classmethod、@property

装饰器的顺序
@a@b@cdef f ():

等效于


f = a(b(c(f)))

简述装饰器的应用场景 python装饰器有什么用

123墨盒和123ⅹL墨盒有什么区别?

文件操作


1. 若有一个jsonline格式的文件file.txt,大小约为10K,我们的处理方式为:

def get_lines(): l = [] with open("file.txt", "rb") as f: for eachline in f: l.append(eachline) return lif __name__ == "__main__": for e in get_lines(): process(e) #处理每一行数据

现在要处理一个大小为10G的file.txt文件,但是内存只有4G。如果在只修改get_lines 函数而其他代码保持不变的情况下,应该如何实现?需要考虑腔渣的问题都有那辩嫌些?

def get_lines(): l = [] with open("file.txt","rb") as f: data = f.readlines(0) l.append(data) yield l

要考虑的问题有:内存只有4G,无法一次性读入10G文件。而分批读入数据要记录每次读入数据的位置,且分批每次读取得太小会在读取操作上花费过多时间。

模块与包

2.如何输入日期, 判断这一天是这一年的第几天?

import datetimedef dayofyear(): year = input("请输入年份: ") month = input("请输入月份: ") day = input("请输入天: ") date1 = datetime.date(year=int(year),month=int(month),day=int(day)) date2 = datetime.date(year=int(year),month=1,day=1) return (date1-date2).days+1

数据类型

3.如何反转字符串"aStr"?

print("携圆手aStr"[::-1])

4.下面代码的输出结果将是什么?会报错吗?

list = ["a","b","c","d","e"]
print(list[10:])

代码将输出[],并不会产生IndexError 错误。如果尝试用超出成员的个数的index来获取某个列表的成员,那就会报错。例如,尝试获取 list[10] 和之后的成员,会导致IndexError。然而当我们尝试获取列表的切片时,开始的index超过成员个数并不会产生IndexError,而是仅仅返回一个空列表。因为并不会报错,所以这种Bug很难追踪到。

5.请写出一段Python代码,实现删除list里面的重复元素?

l1 = ["b","c","d","c","a","a"]l2 = list(set(l1))print(l2)

用list类的sort方法可以保证顺序不变:

l1 = ["b", "c", "d", "c", "a", "a"]l2 = list(set(l1))l2.sort(key=l1.index)print(l2)

也可以这样写:

l1 = ["b", "c", "d", "c", "a", "a"]l2 = sorted(set(l1), key=l1.index)print(l2)

也可以用遍历:

l1 = ["b", "c", "d", "c", "a", "a"]l2 = []for i in l1: if not i in l2: l2.append(i)print(l2)

企业面试题

6.设计实现遍历目录与子目录,抓取.pyc文件

第一种方法:

import osdef getFiles(dir, suffix): res = [] for root, dirs, files in os.walk(dir): for filename in files: name, suf = os.path.splitext(filename) if suf == suffix: res.append(os.path.join(root, filename)) print(res)getFiles("./", ".pyc")

第二种方法:

import osdef pick(obj): try: if obj.[-4:] == ".pyc": print(obj) except: return Nonedef scan_path(ph): file_list = os.listdir(ph) for obj in file_list: if os.path.isfile(obj): pick(obj) elif os.path.isdir(obj): scan_path(obj)if __name__ == "__main__": path = input("输入目录") scan_path(path)

7.如何反转一个整数,例如-123–> -321?

class Solution(object): def reverse(self, x): if -10 < x < 10: return x str_x = str(x) if str_x[0] != "-": str_x = str_x[::-1] x = int(str_x) else: str_x = str_x[1:][::-1] x = int(str_x) x = -x return x if -48 < x < 47 else 0if __name__ == "__main__": s = Solution() reverse_int = s.reverse(-120) print(reverse_int)

Python高级

Python高级包含很多重要的模块,例如函数、类和实例、系统编程、正则表达式、网络编程等等。根据这些高级属性,Python可用于数据科学、网页开发、机器学习等等。

设计模式

8.对设计模式的理解,简述你了解的设计模式?

设计模式是为我们经常会碰到的一些编程问题构建的可重用解决方案,它是总结性和经优化的。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码,反之,设计模式更为高级,它是一种在特定情形下实现的方法模板。常见的是工厂模式和单例模式。

单例模式应用的场景一般发现在以下条件下:资源共享的情况下,避免由于资源操作时导致的性能或损耗等,如日志文件,应用配置。控制资源的情况下,方便资源之间的互相通信。

9.生成器和迭代器的区别?

迭代器是一个更抽象的概念,任何对象,如果它的类有 next 方法和 iter 方法返回自己本身,它就是可迭代的。对于 string、list、dict、tuple 等这类容器对象,使用for循环遍历是很方便的,for 语句实际上会对容器对象调用 iter() 函数。iter() 会返回一个定义了 next() 方法的迭代器对象,它在容器中逐个访问容器内元素,在没有后续元素时,next()会抛出一个StopIteration异常。

生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用yield语句。生成器能做到迭代器能做的所有事,而且因为自动创建iter()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常。

10.对装饰器的理解,你能写出一个计时器装饰器,它能记录函数的执行时间吗?

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

import time def timeit(func): def wrapper(): start = time.clock() func() end = time.clock() print("used:",end-start) return wrapper @timeit def foo(): print("in foo()"foo())

系统编程

11.介绍一下你了解的进程。

程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间片、pid。创建进程:首先要导入multiprocessing中的Process;创建一个Process对象;创建Process对象时,可以传递参数。

p = Process(target=XXX, args=(tuple,), kwargs={key: value})target = XXX # 指定的任务函数,不用加()args = (tuple,)kwargs = {key: value} # 给任务函数传递的参数

使用start()启动进程 结束进程 给子进程指定函数传递参数Demo

import osfrom mulitprocessing import Processimport timedef pro_func(name, age, **kwargs): for i in range(5): print("子进程正在运行中,name=%s,age=%d,pid=%d" % (name, age, os.getpid())) print(kwargs) time.sleep(0.2)if __name__ == "__main__": # 创建Process对象 p = Process(target=pro_func, args=("小明", 18), kwargs={"m": 20}) # 启动进程 p.start() time.sleep(1) # 1秒钟之后,立刻结束子进程 p.terminate() p.join()

12.谈谈你对多进程、多线程、以及协程的理解,项目是否用?

进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。线程: cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,叫主线程,而多个线程共享内存可以极大地提高了程序的运行效率。协程: 是一种用户态的轻量级线程,协程的调度完全由用户控制,协程拥有自己的寄存器上下文和栈。协程调度时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操中栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

关于系统编程还有很多问题,例如:

应用场景是什么?怎样判断、描述一个产品的应用场景?

应用场景,指一个应用(通常就是用户的那个产品)被使用的时候,用户最可能的所处场景。场景包括时间、空间、设备支持、社交及用户情绪等多个方面,进行应用场景的判断和描述的时候,尽量把这些都考虑到比较好。

例如描述:a.时间不确定(见到感兴趣的商品就会比一比);b.地点不确定(比如说正在逛街或者逛淘宝)。可以判定出用户的应用应当给出怎么样的服务,通过这样的设想,用户可以塑造出你的产品雏形。

产品设计师经常被要求设想用户场景,是脊肢为了拟定开发计划,尽量减少浪费,要让用户设想合理,只要按照一般人在生活中的习惯来思考,并将生活场景拆分成多个可变因素,进行选择重组即可。

扩展资料:

注意事项:

应用场景包括金融、生产、教育、媒体、娱乐、政府、零售商业、健康、医疗、供应链、保险、公用事业。那不是大吗?但我想说的是,这些场景,面对真正强大的区块链应用程序,这些场景不得不躲在角落和颤抖。

现在区块链真正活跃的应御野兆用场景是庞氏应用程序,通常被称为“庞氏骗局”。它是一种智能合约式镇租的财富宝,是一种进出黄金的区块链游戏,是一种以交易为目的的ICO,是一个通用的养老平台。

相关专题: 场景 墨盒