目录
getattr__与__getattribute
当访问的属性不存在时,会自动调用__getattr__魔法方法
class User(object):
def __init__(self, name, info):
self.name = name
self.info = info
def __getattr__(self, item):# item就是传入的gender/agg
try:
return self.info[item]
except Exception as e:
return f'不存在{item}这个属性'
ls = User("lisi", {"gender":"male"})
print(ls.gender)
print(ls.age)
当定义了__getattribute__时,它会无条件的优先执行。优先级高于__getattr__。当定义了__getattribute__就不会调用__getattr__了。
属性描述符
只要实现了 __get__和__set__和__delete__三个方法
中的任意一个,这个类就算是描述符
用类的方式创建描述符如下:
class IntFiled(object):
def __set__(self, instance, value):
# print("Set")
# print(isinstance)
# print(value) # 20
if not isinstance(value, int):
raise ValueError("不是整数")
self.values = value
def __get__(self, instance, owner):
# print("get")
# print(isinstance) # <built-in function isinstance>
# print(owner) # <class '__main__.User'>
return self.values
def __delete__(self, instance):
print("delete")
class User(object):
age = IntFiled()
ls = User()
ls.age=20
print(ls.age)
del ls.age
使用属性类型创建描述符:property
class AgeDemo:
def __init__(self, age):
self.age = age
def get_age(self):
return self.age
def set_age(self, age):
if not isinstance(age, int):
raise TypeError("TypeError")
self.age = age
age_pro = property(fget=get_age, fset=set_age)
a = AgeDemo(19)
print(a.age_pro)
a.age_pro = 30
print(a.age_pro)
描述符的查找顺序
class IntFiled(object):
def __set__(self, instance, value):
# print("Set")
# print(isinstance)
# print(value) # 20
if not isinstance(value, int):
raise ValueError("不是整数")
self.values = value
def __get__(self, instance, owner):
# print("get")
# print(isinstance) # <built-in function isinstance>
# print(owner) # <class '__main__.User'>
return self.values
def __delete__(self, instance):
print("delete")
class User(object):
age = IntFiled()
# pass
ls = User()
# ls = IntFiled()
ls.age=20 # 不是实例属性 这是类属性
print(ls.__dict__)
ls.__dict__['age'] = 30
print(ls.age) # 当是数据描述符时,get优先级高于dict优先级
print(ls.__dict__)
元类
元类其实就是创建类的类
def create_class(name):
if name =="user":
class User(object):
def __str__(self):
return "user"
return User
elif name == "person":
class Person(object):
def __str__(self):
return "person"
return Person
myclass = create_class("person")
obj = myclass()
print(obj)
type()创建元类
type(“类名”,(父类,),{属性,方法})
(注意这里的父类,若只有一个父类,那么后面要加上逗号,不然会报错。这里也支持C3算法规则)
class fa:
def info(self):
print("info")
class fa2:
def info(self):
print("info2")
def test(self):
print("test2")
@staticmethod
def stat_func():
print("i am staticmethod")
@classmethod
def cls_func(cls):
print("i am classmethod")
def __init__(self, name):
self.name = name
print("i am init")
User = type("User",(fa,fa2),{"age":18, "__init__":__init__, "stat_func":stat_func, "cls_func":cls_func})
obj = User("lisi")
print(obj.age)
obj.info()
obj.test()
metaclass属性
如果一个类中定义了metaclass 属性,那么python就会用元类的方式来创建类,就可以控制创建类的行为
下面的例子是传入属性名,在不改变类代码的情况下,自动把属性名和属性值都转换为大写
def upper_attr(cls_name, cls_parents, cls_attr):
new_attr = {}
for name, value in cls_attr.items():
if not name.startswith("_"):
new_attr[name.upper()] = value.upper()
return type(cls_name, cls_parents, new_attr)
class MyClass(object, metaclass=upper_attr): # 元类来改变
name = "ls"
my = MyClass()
print(my.NAME)
当一个类继承多个类的时候,会优先查找继承type的类去执行
# 会优先寻找metaclass类
class Demo(object):
def __new__(cls, *args, **kwargs):
print("demo")
return super().__new__(cls)
class MetaClass(type): #继承元类
def __new__(cls, *args, **kwargs):
print("metaclass")
return super().__new__(cls,*args,**kwargs)
class User(Demo,metaclass=MetaClass): #metaclass 优先级最高
def __str__(self):
return "user"
obj = User()
print(obj)
迭代器
说到迭代器,那就要先说说可迭代对象。可迭代对象就是能被for循环的对象。
str,list,dict,set,tuple都是可迭代对象,但可迭代对象都是迭代器吗?
不不不不,可迭代对象不一定是迭代器,但迭代器一定是可迭代对象。
from collections import Iterable
list1 = [1,2,3]
print(isinstance(list1, iterable)) # False
可迭代对象不一定是迭代器,可迭代对象没有__iter__(),__next__方法。当使用next()时就会报错。
如果想要一个可迭代对象变成迭代器,直接通过iter(list1)
即可把可迭代对象变成迭代器。
from collections import Iterator
list1 = [1,2,3]
list2 = iter(list1)
print(isinstance(list2, Iterator)) # True
当对象变为迭代器对象时,就可以使用next()方法了,但是不能通过下标取值
迭代器和可迭代对象的区别
- 可以for循环的对象都是可迭代对象
- 作用next()的都是迭代器类型
- list,dict,str,set,tuple都是可迭代对象,但都是不是迭代器
- 可迭代对象可以使用 iter()转换为迭代器对象
- python的for循环就是不断调用next()函数实现的
生成器
何为生成器,先说说为什么要引入生成器。列表的所有数据都是存在内存中的,当数据量很大的时候,就很耗费内存。有时候我们只访问前面的几个数据,用不到那么多数据的时候,该怎么节省内存呢。这时候可以引入生成器。生成器generator可以在循环过程中使用算法不断推算得出后面的数据,这样就不需要创建完整的列表,从而节省大量的空间。它就是一边循环一边计算的机制。
生成器表达式
生成器表达式来源于迭代和列表解析的结合
de = (i for i in range(100000))
print(type(de))
# <class 'generator'>
生成器使用next来下一步的时候,超出会报错
de = (i for i in range(5))
print(next(de))
print(next(de))
print(next(de))
print(next(de))
print(next(de))
print(next(de)) # 报错了
生成器函数
当一个函数包含yeild关键字时,那它就变成了生成器函数
下面是用生成器函数输出斐波那契数列
def createNums():
print("start")
a, b = 0, 1
for i in range(6):
yield b
a, b = b, a+b
print("end")
g = createNums()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g)) # 报错,意味着结束 打印了 end
yield
yield和return都是返回数据,但是yield可以记住这个返回值的位置,等到下次调用next()时,会从yield下一行的语句开始执行。return是直接结束函数。
迭代器与生成器
迭代器拥有的生成器都有,生成器能做到迭代器做的所有事。
而且生成器自动创建了iter()和next()方法,生成器更加简洁,而且高效。
读取大文件
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:
yield buf
break
buf += chunk
with open('demo.txt') as f:
for line in readlines(f,"{|}"): # 分隔符 |
print(line)