class A(object):
def __init__(self):
pass
def __getattr__(self, item):
return "Timi"
a=A()
print(a.asd) #Timi
print(a.haha) #Timi
什么是属性描述符?
描述符是对多个属性运用相同存取逻辑的一种方式,是实现了特性协议的类,这个协议包括了__get__、__set__和__delete__方法来实现属性对象的查找、设置、删除行为。一个类只要是内部定义了方法 get, set, delete 中的一个或多个,就可以称为描述符,描述符的本质是一个类。
属性描述符可分为两类:
属性描述符的作用:
描述符的作用是用来代理另外一个类的属性的。
class Person(object):
def __init__(self,name):
self.name = name
def __get__(self, instance, owner):
print('__get__:查询属性',self.name)
return self.value
def __set__(self, instance, value):
print('__set__:设置属性',self.name)
if isinstance(value,(int,str)):
self.value = value
else:
raise TypeError
def __delete__(self, instance):
print('刪除屬性',self.name,self.value)
class User():
weight = Person('weight')
sex = Person('sex')
def __init__(self,weight,sex):
self.weight = weight
self.sex = sex
if __name__ == '__main__':
user=User(6,'male')
print(user.weight)
print(user.sex)
del user.sex
__set__:设置属性 weight
__set__:设置属性 sex
__get__:查询属性 weight
6
__get__:查询属性 sex
male
刪除屬性 sex male
上例中Person类就是作为User类的属性存在,这里我们在对修改属性的时候,还对属性的值进行判断,属性类型不为整型或字符串就抛出异常。
元类实际上就是创建类的类
def create_class(name):
if name == 'user':
class User:
def __init__(self):
pass
return User
User=create_class('user')
print(type(User))
user=User()
print(type(user))
class Base_class():
def __init__(self):
self.info = 'python'
def speak(self):
msg='%s speak haha'%(self.name)
return msg
def __str__(self):
return 'Hello'
User=type('User',(Base_class,),{'name':'gg','speak':speak,'__str__':__str__})
user=User()
print(type(user))
print(user.name)
print(user.info)
print(user.speak())
print(user.__str__())
执行结果:
gg
python
gg speak haha
Hello
如果在创建类时,想用 MetaClass 元类动态地修改内部的属性或者方法,则类的创建过程将变得复杂:先创建 MetaClass 元类,然后用元类去创建类,最后使用该类的实例化对象实现功能。
如果想把一个类设计成 MetaClass 元类,其必须符合以下条件:
必须显式继承自 type 类;
类中需要定义并实现 __new__() 方法,该方法一定要返回该类的一个实例对象,因为在使用元类创建类时,该 __new__() 方法会自动被执行,用来修改新建的类。
#定义一个Metaclass
class ListMeta(type):
def __new__(cls, name,bases,attrs):
attrs['name'] = 'list' #动态添加一个name属性
return super().__new__(cls,name,bases,attrs)
class MyList(object,metaclass=ListMeta):
pass
li=MyList()
print(li.name)
利用Metaclass属性功能拓展
class ListMeta(type):
def __new__(cls, name,bases,attrs):
def add(a,value): #定义一个add方法
return a.append(value)
attrs['add'] = add #新增一个add方法
# attrs['add'] = lambda self,value:self.append(value)
return super().__new__(cls,name,bases,attrs)
class MyList(list,metaclass=ListMeta):
pass
li=MyList()
print(li.name)
print(li)
li.add(1)
print(li)
使用Metaclass控制实例的创建
只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。换句话说,我们可以把这个类型的对象当作函数来使用,相当于 重载了括号运算符。
class ListMeta(type):
def __call__(self, *args, **kwargs):
if len(args)== 0 or args[0] != 'a':
raise TypeError('parameter mistake')
else:
print('')
class MyList:
pass
class YouList:
pass
class Use_c1:
lst = {"1":MyList,"2":YouList}
def __new__(cls, name):
if name in cls.lst:
return cls.lst[name]()
else:
raise NameError('Not have this name')
li=Use_c1('2')
迭代器指的是迭代取值的工具,迭代是指一个重复的过程,每一次重复都是基于上一次结果而来.可用for遍历任何可迭代对象。
迭代提供了一种通用的不依赖索引的迭代取值方式,可以作用于next()函数。
可以用for循环遍历的对象都是可迭代对象。
• 有内置的__next__()方法的对象,执行该方法可以不依赖索引取值
• 有内置的__iter__()方法的对象,执行迭代器的__iter__()方法得到的依然是迭代器本身
可迭代对象不一定是迭代器
可以被next()函数调用并不断返回下一个值的对象称为迭代器。可以通过iter()方法将可迭代的对象,转为迭代器。
next()只能顺延调用,不能往前。
li = [1, 2, 3, 4]
lis = iter(li)
while True:
try:
print(next(lis))
except StopIteration:
break
生成器的定义:
在Python中,一边循环一边计算的机制,称为生成器:generator。
为什么要有生成器
import os
import psutil
def show_memory_info(args):
'''显示当前程序占用内存的大小'''
pid = os.getpid() #获取pid
p = psutil.Process(pid)
info = p.memory_full_info()
memory = info.uss / 1024 /1024
print('{} memory used :{} MB'.format(args,memory))
def test_iterator():
show_memory_info("initing iterator")
list_1 =[i for i in range(1000000)]
show_memory_info('after iterator inited')
print(sum(list_1))
show_memory_info('after sum called')
def test_generator():
show_memory_info("initing generator")
list_2 =(i for i in range(1000000))
show_memory_info('after generator inited')
print(sum(list_2))
show_memory_info('after sum called')
test_iterator()
print('~~~~~~~~~~~~~~~~~~')
test_generator()
执行结果:
initing iterator memory used :6.484375 MB
after iterator inited memory used :45.17578125 MB
499999500000
after sum called memory used :45.203125 MB
~~~~~~~~~~~~~~~~~~
initing generator memory used :6.79296875 MB
after generator inited memory used :6.79296875 MB
499999500000
after sum called memory used :6.79296875 MB
结果发现当我们使用迭代器生成元素后,元素都会保存在内存中,如果增加元素的个数至十亿,内存可能会出现OOM错误。(OOM,Out of memory,翻译过来大意是内存用完了)。而使用生成器则不会产生这样的现在。如果我们既要大量的数据,又想要使其占用的内存少,就可以使用生成器。
方法一:
把一个列表生成式的[]改成(),就创建了一个generator:
gen =(i for i in range(1000))
print(type(gen))
#
方法二:
如果一个函数中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。调用函数就是创建了一个生成器(generator)对象。
其工作原理就是通过重复调用next()或者__next__()方法,直到捕获一个异常。
yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
使用生成器实现实现斐波那契数列,除第一个和第二个数外,任何一个数都可以由前两个相加得到:
1,1,2,3,5,8,12,21,34…
def number():
a,b =0,1
for i in range(10):
yield b
a,b = b,a+b
if __name__ == '__main__':
goal=number()
for i in goal:
print(i)
文件300G,文件比较特殊,一行 分隔符 {|}
def readlines(f,newline):
buf = ""
while True:
while newline in buf:
pos = buf.index(newline) #获取分隔符的位置
yield buf[:pos] #截取到分隔符的内容
buf = buf[pos + len(newline):]
chunk = f.read(4096*10) #每次读取文件大小
if not chunk: #当最后一次读取文件内容不到4096*10时
yield buf
break
buf += chunk
if __name__ == '__main__':
with open('demo.txt') as f:
for line in readlines(f,"{|}"):
print(line)