Python 高级技巧

(一)生成器

  通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。这个其实是惰性求值,数据不是全部一下子载入到内存中,而是一个一个来。

g = (i for i in range(10))
print(g)
# 把列表推导的圆括号换成方括号就变成了一个生成器
# <generator object <genexpr> at 0x000001AA11DD3D68>

我可以通过 next(g) 方法访问元素,在访问完所有的元素后会抛出一个异常。但是这种使用方法几乎不被推荐。正确的做法是用 yield 编写一个生成器函数,最后返回一个可迭代对象,然后用 for 循环来调用。

 1 def my_range(n):
 2     i = 0
 3     while i != n:
 4         i += 1
 5         yield i # 协程
 6 
 7 
 8 r = my_range(10) # 返回一个可迭代对象
 9 for i in r:
10     print(i)

yield 这种处理方式其实是协程,这个有点像系统终中断。协程,又称微线程,纤程。英文名Coroutine。协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用。子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。——廖雪峰

 

(二)重要的魔法方法

 

'''
__getattribute__ # 可以 hook 住所有的读操作,在访问元素的时候 Foo.name 先调用 __getattribute__
__setattribute__

***
# 什么都没有的时候才会被触发
# 这个操作更加的重要,下面两个函数被触发的时候,一定没有这个属性 missing method
__getattr__
__setattr__  
'''
class Foo(object):
    def __init__(self, name):
        self.id = None
        self.name = name
     
    def __getsttribute__(self, item):
        print(item)
        
foo = Foo('Jack')
foo.name
# 输出 Jack



# __getattr__
class Any(object):
    def __getattr__(self, item):
        print(item)
      
    def __setattr__(self, k, v):
        print("set", k, v)
        
a = Any()
a.a
# 输出 a ,这是一个没有的属性
     
# __setattr__
a.a = 1
# 输出 set a 1



"""
希望有一个类可以接受任何参数和任何函数
"""

 

  

 

(三)装饰器与闭包

  装饰器是为了给函数或类添加一些特定的功能,如打印日志等。装饰器采用闭包原理实现。闭包就是有一个内层函数,并且外层函数返回内层函数的函数名。外层函数传入的是一个函数名或者类名

  

"""
使用装饰器实现一个单例模式
"""

def singleton(cls, *args, **kwargs):
    instance = {}
    def wrapper(*args, **kwargs):
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)
        return instance[cls]
    return wrapper

@singleton
class Foo(object):
    pass

foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)
# 输出: True

  

 

 

(四) 运算符重载

 

# __repr__
# __str__的区别:
"""
	两个方法同时定义的时,调用 print 函数打印对象的时候,会优先调用 __str__ 方法
	
	__str__是面向用户的,而__repr__面向程序员
	
	重构了 __str__方法,交互式调用显示的式地址,直接 print 的时候是显示重构的内容。
	__repr__ 改了的话,交互式和 print 都是统一的
"""

class Com(object):
	"""
		加减法实现运算符重载
	"""
	def __init__(self, value):
		self.value = value

	def __add__(self, other):
		return self.value + other

	def __sub__(self, other):
		return self.value - other


com = Com(5)
print(com + 5)
print(com - 10)


"""
	索引的取值和复制 __getitem__, __setitem__
	通过这两个方法实现 i[index] 的取值、赋值和切片操作
	
"""
class Index(object):

	data = [8,2,5,5,1,5,3,9,6]
	def __getitem__(self, index):
		return self.data[index]

	def __setitem__(self, k, v):
		self.data[k] = v
		print(self.data)

i = Index()
print(i[3])

i[0] = 8999
print(i[1:])


"""
	__iter__,__next__ 实现迭代器
	什么是迭代器? 能够把容器中的元素遍历(for loop)访问的对象被称为迭代器
	含有 __iter__() 方法或 __getitem__() 方法的对象称之为可迭代对象。
"""

 

  

 

转载于:https://www.cnblogs.com/owenqing/p/10449571.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值