点击上方”python宝典”,关注获取python全套视频,
技术文章第一时间送达!
python3中列表推导式和生成器的不同:
(1)列表推导式是将所有的值一次性加载到内存中
生成器是将列表推导式的[]改成(),不会将所有的值一次性加载到内存中,延迟计算,一次返回一个结果,它不会一次生成所有的结果,这对大数据量处理,非常有用
def fun():
for i in range(1,50):
sleep(1)
yield i
for i in fun():
print(i)
# 生成器函数: 一个函数中包含了yield关键,那么这个函数就不是普通的函数,是一个生成器函数
# 调用生成器函数,不会立马执行该函数里面的代码, 而是会返回一个 生成器
def func():
print("a")
yield
print("b")
yield
print("c")
yield
print("d")
yield
generator = func()
print(generator)
print(type(generator))
# next(generator)
# next(generator)
# next(generator)
for i in generator:
pass
sum(x for x in range(10000000000))
sum([x for x in range(10000000000)])
第一个几乎没什么内存占用,第二个内存占有很多
原理:sum函数时python3中的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以我们可以直接计算一系列值的和,而不用多此一举先构造一个列表.
生成器还可以提高代码的可读性:
# 求一段文字中,每个单词出现的位置
def index_words(text):
result = []
if text:
result.append(0)
for index,letter in enumerate(text,1):
if letter == ' ':
result.append(index)
return result
def index_words(text):
if text:
yield 0
for index,letter in enumerate(text,1):
if letter == '':
yield index
(2)列表推导式可以遍历任意次
生成器只能遍历一次
generator = (i for i in range(1,5))
print(next(generator))
print(next(generator))
for i in generator:
print(i)
for i in generator:
print(i)
打印结果:
1
2
3
4
list1 = [i for i in range(1,5)]
print(list1[0])
print(list1[1])
print(list1[2])
for i in list1:
print(i)
for i in list1:
print(i)
打印结果:
1
2
3
1
2
3
4
1
2
3
4
python__new__方法以及与装饰器单例模式比较
在学习面向对象的时候,我们接触过init方法,它是来初始化类的属性的,那么new方法是干什么的呢?
1.new方法的定义
new方法是来实例化类的对象的,它返回类的对象(对的常见的obj = cls()就是调用new来返回实例)所以它在init方法前调用,因为在调用init方法时,类的实例化对象已经生成了
通过下面的例子来理解:
class Foo():
def __init__(self):
print("This is init func")
def __new__(cls, *args, **kwargs):
print("This is new func")
# return super(Foo, cls).__new__(cls) #返回类的实例化对象
# return object.__new__(cls) #同上
obj1 = Foo()
执行结果为
This is new func
但是,init方法并没有执行啊?因为我们只是调用了new方法,但是并没有返回实例,这个例子只是体现出new方法在init之前,我们取消new方法的注释,随便用哪个都行,这两个return都是返回类的实例
class Foo():
def __init__(self):
print("This is init func")
def __new__(cls, *args, **kwargs):
print("This is new func")
return super(Foo, cls).__new__(cls) #返回类的实例化对象
# return object.__new__(cls)
obj1 = Foo()
执行结果为:
This is new func
This is init func
可以看到,先用new返回实例化对象,再执行的init方法
2.使用new方法返回单例
单例在程序设计中是比较常用的设计模式,它用于类只能实例化一个对象,比如某个程序只能执行出现一个窗口,不能同时运行多个,这个大多就是通过单例模式来实现的
class Foo():
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'): # 当对象不存在instance属性,即类还没有被实例化时,返回实例化对象
cls.instance = super(Foo, cls).__new__(cls) # 创建当前类的对象,相当于object.__new__(cls)
return cls.instance
obj1 = Foo("123")
print(obj1.name)
obj2 = Foo("321")
print(obj1 == obj2, obj1.name, obj2.name, id(obj1), id(obj2))
执行结果为:
123
True 321 321 2239300270792 2239300270792
这里的核心思想是,定义instance属性(随便什么名都行,代表这个属性是类的实例化对象),判断这个属性是否存在,若不存在,则创建实例对象,若存在则直接返回实例
而且我们可以看到,当我们重新实例化这个对象时,其实这个对象的id没有变化,但是属性改变了,记住这点,我们接下来会与装饰器单例进行比较
3.装饰器单例模式
既然都说到单例模式了,不得不提的是装饰器的单例模式,那么装饰器单例的实现方式如下列代码:
def decorator_single_obj(cls, *args, **kwargs):
instance = {} # 创建字典来保存实例
def get_instance(*args, **kwargs):
if cls not in instance: # 若实例不存在则新建
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return get_instance
@decorator_single_obj
class Foo(object):
def __init__(self, name):
self.name = name
obj1 = Foo("123")
print(obj1.name, id(obj1))
obj2 = Foo("321")
print(obj2.name, id(obj2))
我们可以看到,虽然也还是实现了单例模式,但是第二次实例化得时候,属性并没有被改变
所以装饰器单例与new单例的区别在于属性不会被覆盖
因为new会重新调用init方法,为实例重新初始化属性,而装饰器单例模式则是直接返回之前生成的对象,并不会重新初始化对象,所以new单例从某种程度上也可以视作伪单例模式
最后呢,再留个彩蛋
对于上面的代码我们加上一行
obj3=object.new(Foo)
会发生什么?
链接:
https://blog.csdn.net/renyiforever/article/details/79859394
https://blog.csdn.net/jimmy_gyn/article/details/79142101
识别图中二维码,欢迎关注python宝典