1.property动态属性
2种实现方式
- 1 通过给一个变量进行方法的实现
例:S=property()
再设置 setter和getter方法 - 2 直接使用装饰器的方法
2._getattr_和_getattribute_
_getattr_ 在查找不到属性的时候调用
_getattribute_是在_getattr_之前执行的魔法方法,尽量不要重写这个方法
先看一下_getattr_的例子:
from datetime import date,datetime
class User:
def __init__(self,name,birthday):
self.name= name
self.birthday = birthday
def __getattr__(self, item):
print("not find attr")
if __name__ == '__main__':
user1 = User('zjk',date(year=1989,month = 10,day=1))
print(user1.age)
执行结果:
not find attr
None
为什么会有一个none的出现,是因为在打印类的时候 ,程序没有给出返回值,所以就是None
再看一下加了_getattribute_的例子:
from datetime import date,datetime
class User:
def __init__(self,name,birthday):
self.name= name
self.birthday = birthday
def __getattr__(self, item):
print("not find attr")
def __getattribute__(self, item):
return '123'
if __name__ == '__main__':
user1 = User('zjk',date(year=1989,month = 10,day=1))
print(user1.age)
执行结果:
123
此时我们可以看到结果,程序原本应该是输出 not find attr 的,但是由于 _getattribute_ 是在 _getattr_ 之前执行,所以就直接输出了,而不会再调用 _getattr_ 了,所以在程序中尽量不要重写 _getattribute_ 方法
2.1. _getattr_ 中的item
我们来看一下程序代码:
from datetime import date,datetime
class User:
def __init__(self,name,birthday):
self.name= name
self.birthday = birthday
def __getattr__(self, item):
print(item)
print("not find attr")
if __name__ == '__main__':
user1 = User('zjk',date(year=1989,month = 10,day=1))
print(user1.age)
执行结果:
age
not find attr
None
此结果我们看出来,item其实就是我们在程序调用时给的属性
2.2. 通过_getattr_ 获取类中 字典中的属性
我们来看一下实现代码:
from datetime import date,datetime
class User:
def __init__(self,name,birthday,info ):
# info 属性是一个字典形式的
self.name= name
self.birthday = birthday
self.info = info
def __getattr__(self, item):
return self.info[item] # 此时是把item 当作字典中的key
if __name__ == '__main__':
user1 = User('zjk',date(year=1989,month = 10,day=1),{"age":18})
print(user1.age)
执行结果:
18
从程序和结果我们可以看到,通过字典形式取值时,item其实就是我们字典当中的key,也就是把我们调用时传的属性值当作key
我们通过上面的方法,可以自定义一些信息,如果我们写_getattr_方法,当程序中找不到我们要调用的属性时程序会直接报错
3.数据描述符
3.1数据描述符
在类中实现了get、set、delete中任何一个方法,就被称为属性描述符
class IntField(object):
def __get__(self, instance, owner):
print("__get__")
return self.values # 这里通过get方法进行值的返回
def __set__(self, instance, value):
print("__set__")
if not isinstance(value,int):
raise TypeError
self.values = value # 这里的value 其实就是设置的属性的值
#如果这里搞不太明白,我们可以分别 打印输出 instance 和 Value 的值来查看结果
def __delete__(self, instance):
pass
class User:
age = IntField
user = User()
user.age= 20
print(user.age)
3.2 非数据描述符
在类中只实现了 _get_方法
4.自定义元类
元类就是创建类的类,type
4.1 笨方法动态创建类
def new_class(name):
if name == "user":
class User:
def __str__(self):
return "user"
return User
elif name == "person":
class Person:
def __str__(self):
return "Person"
return Person
if __name__ == '__main__':
user1 = new_class('user')
print(user1)
执行结果:
<class 'main.new_class.<locals>.User'>
4.2 通过type方法动态创建类
一般我们不用type方法创建类
我们通过分析type的源,可以知道type还可以动态的创建类,type(类名,由父类组成的元组,包含属性的字典)
程序中类重名,程序不会报错
- 1 创建没有任何属性的类
# 创建没有任何属性的类
User = type("User",(),{})
obj = User()
print(obj)
- 2 创建带有属性的类
User = type("User",(),{'name':'zjk','age':18})
obj = User()
print(obj.name)
结果:
zjk
如果我们不想在类创建的时候给属性赋值或是空,可以写成 {'name':''}
或是 {'name':None}
- 3 创建带有属性和方法的类
def info(self):
return self.name
User = type("User",(),{'name':'zjk','age':18,'info':info})
obj = User()
print(obj.info())
结果:zjk
注意:我们通过 type动态创建类时要添加方法的话也是在属性字典中完成,只不过我们要把方法单 独写出来,并且方法中传的参数是 self ,然后在属性字典中通过 {'info':info}的就去指向 我们自己创建的方法,实例调用 的时候 和我们正常的方法调用形式是一样的
注:私有方法不能通过动态创建类的时候进行引用
- 4 创建带有继承的类
class BaseClass:
def demo(self):
return "基类"
def info(self):
return self.name
User = type("User",(BaseClass,),{'name':'zjk','age':18,'info':info})
obj = User()
print(obj.demo())
结果:
基类
注意:我们在元组进行类的继承的时候,写完父类后,一定要在后面加一个 ,号,否则程序会报错,这一点要特别注意
5.metaclass属性
如果一个类中定义了_metalass_ = xxx,Python就会用元类的方式来创建类
也就是我们可以通过 metaclass 这种方式自定义类的一些实现方式
- python2 与 python 使用的区别
python2 中示例:
class A:
\__metalass\__ = xxx
python 3 中示例:
class B(object,metaclass = xxx):
- 使用示例:
def upper_attr(class_name,class_parents,class_attr): # 相当于type创建类时传递的参数,名字可以是任意的,因为这里是形参
newattr = {}
for name,value in class_attr.items():
if not name.startswith("__"):
newattr[name.upper()]=value
return type(class_name,class_parents,newattr)
class User(object,metaclass=upper_attr):
name = 'zjk'
print(hasattr(User,'name'))
print(hasattr(User,'NAME'))
执行结果:
False
True
通过结果我们可以看出,我们在创建类的时候,如果指定了 metaclass 程序会先按照我们指定的方法或类进行创建
6.迭代器和生成器
6.1迭代器
在介绍迭代器之前,先说明下迭代的概念:
迭代:通过for循环遍历对象的每一个元素的过程。
Python的for语法功能非常强大,可以遍历任何可迭代的对象。
在Python中,list/tuple/string/dict/set/bytes都是可以迭代的数据类型。
6.1.1迭代器是什么?
迭代器是一种可以被遍历的对象,并且能作用于next()函数。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。 迭代器只能往后遍历不能回溯,不像列表,你随时可以取后面的数据,也可以返回头取前面的数据。
6.1.2判断列表是否是迭代器,是否是可以迭代的
from collections import Iterable,Iterator
print(isinstance(list(),Iterable))
print(isinstance(list(),Iterator))
6.1.3列表转换成迭代器
lis = [2,3,4]
it =iter(lis)
print(isinstance(it,Iterator))
6.1.4 next 和 for 遍历 迭代器的区别
next当迭代不出数据时,程序会报错,for循环当迭代不出数据时候,会自动停止
6.2生成器
有时候,序列或集合内的元素的个数非常巨大,如果全制造出来并放入内存,对计算机的压力是非常大的。
所以此时我们需要用 yield关键字
我们看一段代码:
def createNum():
a,b = 0,1
for i in range(5):
a,b = b,a+b
yield b
g = createNum()
print(g)
for i in g:
print(i)
执行结果:
1
2
3
5
8
其实看结果我们可以看到上面的程序其实完成的是一个输出 斐波纳契 数列
6.2.1 return 和 yield 的区别
return会直接返回一次的值,但是 yield 会在yield时候程序会进行暂停,并且保存数据,并且会继续循环,直至循环完成
7 生成器读取大文件
场景: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(1024*10)
if not chunk:
yield buf
break
buf += chunk
with open('1.txt') as f:
for line in readlines(f,'|'):
print(line)