目录
1.isinstance和isinstance
2.反射
2.1 反射模块
2.2 反射实际应用案列
2.3 反射隐藏属性and设置属性
3.反射内置方法 __setattr__ __delattr__ __getattr__
4.__getattribute__ 属性被访问时行为
5.__setitem__ __getitem__ __delitem__ []获取 设置 删除
6.__format__格式化打印格式
7.__str__ 显示内容
8.__del__ 关闭系统资源
9.__doc__ 类的注释信息
10.__call__ 预执行
11.__new__ 对象生成
12.__init__ 初始化
13.__all__ 限制属性
14.__len__ 计算长度
15.__hash__ 转换类型
16.__eq__ 对象 == 触发
17. __class__ 显示对象类
18.__module__ 显示对象所属模块
19.__slots__ 控制对象可以使用的属性
20. __dict__ 对象属性
21.__next__和__iter__ 实现迭代器
22.__enter__和__exit__ 上下文管理器
23.描述符
23.1 描述符小案例
23.2 描述符的分类
23.3描述符机制来实现类型限制功能
24.类的装饰器
24.1 自制property装饰器
24.2 @classmethod类方法
24.3 @staticmethod 静态方法
1.isinstance和isinstance
# 判断某个对象是不是某个类的实例
# isinstance()
class Person:
pass
class Student(Person):
pass
stu = Student()
#判断 两个对象是不是同一个类型
print(type(1) == type(1))
# 判断stu对象是不是Student类的实例
print(isinstance(stu,Student))
# 是不是子类
# issubclass()
# 判断一个类是不是 另一个类子类 (所有类都是object的子类或子子类)
print(issubclass(Student,object))
# 单继承(父类--》父类)
class Animal:
pass
class Dog(Animal):
pass
class TDog(Dog):
pass
print(issubclass(TDog,Dog))
print(issubclass(TDog,Animal))
# 多继承下
import json
class Foo:
pass
# 多继承
class Mydic(dict,Foo):
def to_json(self):
return json.dumps(self)
# 判断多继承类是不是子类
print(issubclass(Mydic,dict))
print(issubclass(Mydic,Foo))
# py3中:所有的类都是由type构造来的
# py3中:所有类都继承object
# print(type(object))
# print(type(type))
2.反射
"""
反射:通过字符串来操作类或者对象的属性
hasattr() # 判断一个对象中是否由某个属性或方法
getattr() # 通过字符串获取对象中的属性或方法
setattr() # 通过字符串设置对象的属性或方法
delattr() # 通过字符串删除对象的属性或方法
"""
# 一、hasattr() # 判断一个对象中是否由某个属性或方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
p = Person('mzk', 18)
# 判断p对象中是否有name属性和print_name方法
# p是对象判断字符串name属性是否存在
print(hasattr(p,'name'))
# print('name' in p.__dict__)
# p是对象判断字符串print_name方法是否存在
print(hasattr(p,'print_name'))
# print('print_name' in Person.__dict__)
# 二、getattr() # 通过字符串获取对象中的属性或方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
p = Person('mzk', 18)
# 一个通过字符串获得(反射),一个通过点:正常的对象调用方法
f=getattr(p,'print_name')
f=p.print_name
print(f) # 函数内存地址
f() # 执行
# 三、setattr() # 通过字符串设置对象的属性或方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
p = Person('mzk', 18)
# 反射属性到对象名称空间
p=setattr(p,'sex','男')
# 对象属性的设置
p.sex='男'
print(p)
# 反射属性到类名称空间
setattr(Person,'sex','男')
# 类的属性设置
Person.sex='未知'
print(p.sex)
# 反射方法到类的内部
def xxx(self):
print('xxx')
print(self.age)
# 绑定给对象的方法是写在类中,如果使用反射,要反射到类内部
setattr(Person,'print_age',xxx)
p.print_age()
# 反射对象
def xxx(obj):
print(obj.age)
setattr(p,'print_age',xxx)
p.print_age(p)
# 四、delattr() # 通过字符串删除对象的属性或方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
p = Person('mzk', 18)
delattr(p,'name') # 通过反射删除了属性
print(p.name) # 查询没有
delattr(p,'print_name') # 通过反射删除了方法
p.print_name() # 查询没有
2.1 反射模块
方法: __import__('字符串')
# 使用小方法
i=input('请输入使用哪个模块:')
# 模块以字符串形式传入
s1=__import__(i)
# 调用模块方法
s1.test()
# 打印模块中的变量
print(s1.name)
# 拓展,带路径的模块导入,点路径
i = input('请输入使用哪个模块:')
s1 = __import__(i, fromlist=True)
s1.test()
print(s1.name)
# 反射模块(py3中用的比较多,框架中)
import importlib
i=input('请输入您要使用的模块:')
a=importlib.import_module(i)
a.test()
2.2 反射实际应用案列
class Person:
def __init__(self, name, age, sex):
self.age = age
self.sex = sex
self.name = name
def print_age(self):
print(self.age)
def print_name(self):
print(self.name)
def print_sex(self):
print(self.sex)
def print_info(self):
print('我的名字是%s,年龄是%s,性别是%s' % (self.name, self.age, self.sex))
def server_forever(self):
while True:
ss = input('请输入您要执行的方法,按q退出') #
if 'q' == ss.lower(): break
if hasattr(self, ss):
# f=getattr(self,ss)
# f()
# 下面这一步等同于上面注释的那两个
getattr(self, ss)()
else:
print('您输入的指令不执行,我正在学习中')
p = Person('mzk', 18, '男')
p.server_forever()
2.3 反射隐藏属性and设置属性
# 反射成隐藏属性
class Person:
def __init__(self, name, age, sex):
self.age = age
self.sex = sex
self.__name = name
p = Person('lqz', 18, '男')
# name=getattr(p,'__name') # 这个方法拿不到隐藏属性
# __dict__方法中的写法可以拿到
name=getattr(p,'_Person__name')
print(name)
# 设置成隐藏属性
class Person:
def __init__(self, name, age, sex):
self.age = age
self.sex = sex
self.__name = name
def print_wife(self):
print(self.__wife)
p = Person('lqz', 18, '男')
# 对象方法:设置隐藏属性
setattr(p,'__wife','刘亦菲')
print(p.__wife) # 能拿到属性
# 对象和字符串类名加属性隐藏
setattr(p,'_Person__wife','刘亦菲')
print(p.__dict__)
print(p.__wife) # 拿不到
# 直接从方法中拿到返回值的隐藏属性
p.print_wife()
# 类的方法:设置隐藏属性
# 类和字符串类名加属性隐藏
setattr(Person,'_Person__wife','刘亦菲')
print(Person.__dict__)
print(Person._Person__wife) # 拿到隐藏属性
# 直接从方法中拿到返回值的隐藏属性
p.print_wife()
3.反射内置方法 __setattr__
adn __delattr__
and __getattr__
'''
# 面向对象中的魔法方法,在某种情况下就会触发它的执行
# __setattr__ :在 对象.属性=值 会触发它的执行
# __getattr__ :在 对象.属性 获取值会触发它的执行
# __delattr__ :在 del 对象.属性 会触发它的执行
setattr(对象,key,value)
内部:对象.__setattr__(key,value)
保证对象必须要有__setattr__,所有类的基类,object中有__setattr__
'''
class Person:
def __setattr__(self, key, value):
# print('我执行了')
# print(key)
# print(value)
# setattr(self,key,value) # 本质会调用对象自己的__setattr__ ,出递归,报错
object.__setattr__(self,key,value)
def __getattr__(self, item): # 当属性不在对象中,会触发它的执行
print('我执行了')
def __delattr__(self, item):
# delattr(self,item)
print('删除会触发我')
p = Person()
p.name = 'mzk'
# print(p.age)
del p.name
4.__getattribute__
(了解即可)
'''
无论属性在对象中是否存在,都先触发__getattribute__的执行(用的比较少)
对象.属性 调用顺序
先执行:__getattribute__----》类的名称空间----》__getattr__(本质是去对象自己的名称空间拿东西)
对象.属性的查找顺序
当getattribute与getattr同时存在,只会执行getattrbute,
除非getattribute在执行过程中抛出异常AttributeError
重点: __getattribute__: 对象.属性---》__getattribute__---》__getattr__
'''
class Person:
name = 'lqz'
# 属性不存在,才触发
def __getattr__(self, item):
print('getattr触发了')
def __getattribute__(self, item):
print('__getattribute__触发了')
p = Person()
print(p.name)
5. __setitem__ 、__getitem__ 、__delitem__
(了解即可)
'''
__getitem__:通过中括号取值触发它的执行
__setitem__:通过中括号赋值,触发它的执行
__delitem__:通过中括号删除值,触发它的执行
item系列
__getitem__: 对象['name'],触发它的执行
__setitem__: 对象['name']='value',触发它的执行
__delitem__: del 对象['name'],触发它的执行
应用:把一个对象做成既能.取值赋值,又能[] 取值赋值
-自己定义这种类(会出现递归现象,反射setattr)
-对象.__dict__
-object.__setattr__(self,key,value) 普通函数,有几个值,就传几个值
-object.__setattr__(self,key,value)
-对象.__name='mzk'
后期封装+setattr的使用(注意)
后期源码中常出现的操作(flask框架源码中使用)
-object.__setattr__(self,'_类名__属性名',value)
-对象.__dict__[_类名__属性名]='mzk'
-类内部使用 self.__属性名
-类外部使用: 对象._类名__属性名
'''
class Person:
def __getitem__(self, item):
print('__getitem__执行')
def __setitem__(self, key, value):
print('__setitem__执行')
def __delitem__(self, key):
print('__delitem__执行')
p=Person()
p['name']='lqz'
p['name']
del p['age']
# 自己定义一个字典,但是不继承字典
# 作业:写一个字典,不继承字典,支持 [] 取值赋值,不支持 . 取值赋值
class Mydict:
def __init__(self,**kwargs):
# 方案一
# for key,value in kwargs.items():
# setattr(self,key,value)
# 方案二
self.__dict__.update(kwargs)
# 方案三
# for key,value in kwargs.items():
# self.__dict__[key]=value
def __getitem__(self, item):
# 方案一
# return self.__dict__[item]
# 方案二
return getattr(self,item)
def __setitem__(self, key, value):
# 方案一
# setattr(self,key,value)
# 方案二
self.__dict__[key]=value
def __delitem__(self, key):
del self.__dict__[key]
dic=Mydict(name='lqz',age=18)
# 打印属性
print(dic.name)
# 触发__getitem__方法
print(dic['name'])
# 触发__setitem__方法
dic['age']=18
print(dic.age)
# 触发__delitem__方法
del dic.age
print(dic.__dict__)
6.__format__
格式化打印格式(了解即可)
'''
__format__
-format(对象) ---》触发类中__format__的执行
-'{:n-m}'.format(对象) ---》触发类中__format__的执行
'''
# 一 字符串格式
s = '我的名字是:%s' % 'mzk'
print(s)
# 字符串的format方法支持的格式化方式
res = '我的名字是{},年龄是{}'.format('mzk', 18)
res = '我的名字是{0},年龄是{1}'.format('mzk', 18)
ll = ['mzk', 19]
l2 = ['男']
res = '我的名字是{0[0]},年龄是{0[1]},性别是{1[0]}'.format(ll, l2)
dic = {'name': 'mzk', 'age': 19, 'sex': '男'}
res = '我的名字是{name},年龄是{age},性别是{sex}'.format(**dic)
class Person:
def __init__(self):
self.name = 'mzk'
self.age = 19
self.sex = '男'
p = Person()
# res='我的名字是{0.name},年龄是{0.age},性别是{0.sex}'.format(p)
res = '我的名字是{obj.name},年龄是{obj.age},性别是{obj.sex}'.format(obj=p)
print(res)
# 对象的__format__
class Person():
__dic = {
'n-a': '名字是:{obj.name}-----年龄是:{obj.age}', # 名字是:mzk-年龄是:18
'n:a': '名字是:{obj.name}:::::年龄是:{obj.age}', # 名字是:mzk:年龄是:18
'n/a': '名字是:{obj.name}/////年龄是:{obj.age}', # 名字是:mzk/年龄是:18
}
def __init__(self, name, age, sex):
self.name = name
self.sex = sex
self.age = age
def __format__(self, format_spec):
# print(format_spec)
if format_spec and format_spec in self.__dic:
s = self.__dic[format_spec]
else:
s = self.__dic['n-a']
return s.format(obj=self)
p = Person('mzk', 18, '男')
# 内置函数
# 第一种触发它执行
# res=format(p)
# res=format(p,'n-a')
# res = format(p,'n/a')
# res = format(p,'n:a')
print(format(p, 'n-a'))
# 第二种触发方式
# print('n-a'.format(p))
# 写一个Date类,实例化的时候传入年 月 日,格式化方法
# d=Date(2020,12,23)
# print('y-m-d'.format(p)) # 2020-12-23
# print('y/m/d'.format(p)) # 2020/12/23
# print('y:m:d'.format(p)) # 2020:12:23
# print('y年m月d日'.format(p)) # 2020年12月23日
7.__str__
显示内容
"""
__str__
前后带杠杠的都是特殊的内置函数 会在某些时机自动执行 一般情况我们不应该直接调用他们
当我们需要自定义打印显示内容时 就需要实现__str__方法
该方法必须返回一个字符串 返回的是什么 打印出来就是什么
"""
class Test:
def __init__(self,name):
self.name = name
def __str__(self):
print("str run....")
return self.name
t = Test("安米")
# __str__ : print(对象) 触发对象的 __str__
print(t)
# 在讲一个对象转换字符串时 本质就是在调用这个对象 __str__方法
print(str(t))
8.__del__
关闭系统资源
"""
__del__
当对象被从内存中删除时会自动执行
另一种情况时 程序员手动删除了这个对象 也会自动执行
什么时候使用它
在python中 有自动内存管理机制 所以 python自己创建的数据 不需要我们做任何操作
但是有一种情况 我们使用python打开了一个不属于python管理的数据
比如打开了一个文件 这个文件一定是操作系统在打开 会占用系统内存 而python解释器无法操作系统内存的
所以 当你的python解释器运行结束后 文件依然处于打开状态 这时候就需要使用__del__来关闭系统资源
简单地说 当程序运行结束时 需要做一些清理操作 就使用__del__
__del__也称之为 析构函数
分析构造 并拆除这个对象
"""
class TextFile:
def __init__(self,filepath,mode="rt",encoding="utf-8"):
self.file = open(filepath,mode=mode,encoding=encoding)
def read(self):
return self.file.read()
def write(self,text):
self.file.write(text)
# 该方法其实就是一个通知性质 仅仅是告诉程序员 对象即将被删除
def __del__(self):
# 在这里关闭系统的文件 妥妥的
self.file.close()
tf = TextFile("今日内容.txt")
tf.read()
tf.write()
# tf.file.close() 不需要手动关闭了 在对象删除时会自动关闭
9. __doc__
类的注释信息
'''
__doc__: 类下面的注释 类名.__doc__ ,把注释打印出来
'''
class Person:
'''
类的提示信息,注释
'''
pass
print(Person.__doc__)
from bs4 import BeautifulSoup
print(BeautifulSoup.__doc__)
# 注意:继承关系下,类的注释不能继承
class Animal:
'''
Animal的注释,动物类,所有属于动物的都继承我
'''
class Person(Animal):
pass
print(Animal.__doc__)
print(Person.__doc__)
10.__call__
预执行
"""
__call__ 调用的意思
在对象被调用时 执行 函数 类
自定义元类的目的
1.可以通过__call__ 来控制对象的创建过程
2.可用控制类的创建过程
"""
# 自定义一个元类 元类也是一个类 但是需要继承type
class MyMeta(type):
# self 表示要创建对象的那个类(Person) *args是调用Person类时传入的参数
def __call__(self, *args, **kwargs):
print("MyMte中的 call run'")
print(self, *args, **kwargs)
# 下面的三步是固定写法 一个模板 只要你需要控制对象的创建过程 就应该先把模板写出来
# 1.创建空对象
obj = object.__new__(self)
# 2.调用初始化方法
self.__init__(obj, *args, **kwargs)
# self.__init__(obj)
# 3.得到一个完整的对象
return obj
# 修改Person类的元类为MyMeta
class Person(metaclass=MyMeta):
def __init__(self, name, age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print("call run...")
# 调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法
p = Person("张三疯", 80)
# print(p)
# 当调用对象时 会执行该对象所属类中的__call__方法
p()
# print(p.name)
# print(p.age)
11.__new__
对象生成
'''
__new__ 对象生成 ,类() 会触发,是在__init__之前触发
类实例化得到对象的本质是先调用__new__生成一个空对象,然后再调用__init__完成初始化
总结:类实例化得到对象,本质是在执行类的 __new__,返回什么对象,p拿到的就是什么对象,在__new__内部,调用了__init__
'''
class Person:
def __init__(self, name):
# 初始化,self这个对象,已经造出来了
# self是在哪里造出来的? __new__中造出来的
print('__init__执行了')
print(self)
self.name = name
# def __new__(cls, *args, **kwargs):
# print('我出生了')
# print(args)
# print(kwargs)
# # return 1
# cls.__init__(1,*args)
# ## 如果一个类,没有重写 __new__方法,在__new__中自动触发了对象的__init__的执行
def __new__(cls, *args, **kwargs):
print('我出生了')
# cls(*args,**kwargs) # 出递归
# obj=object.__new__(cls) # 静态方法之类来调用
obj = super().__new__(cls) # 静态方法之对象来调用
cls.__init__(obj, *args, **kwargs) # 穿衣服,调用__init__
## 如果一个类,没有重写 __new__方法,在__new__中自动触发了对象的__init__的执行
return obj # 必须要return,造出来的对象
p = Person('mzk')
print(p)
print(p.name)
# 列子
'''
Person()---->本质触发的是__new__,因为__new__返回什么对象就是什么
__init__是初始化方法,在__new__后执行的
__new__:创造出一个空对象,没有初始化
__init__:创造完空对象后,再触发它,完成初始化
'''
class Person:
def __init__(self,name):
print('我执行了,我是__init__')
self.name=name
def __new__(cls, *args, **kwargs):
print('我出生了')
# __new__内部会触发 self.__init__的执行
obj=object.__new__(cls)
# return {'name':'l1z'} # 不会触发__init__
return obj # 触发 __init__
p=Person('lqz') # 触发__new__,返回 1 对象
print(p)
12.__init__
初始化
'''
__init__ 对象初始化调用 类() 会触发
'''
13.__all__
限制属性
# a.py
__all__=['age','name']
age=10
name='lqz'
sex='男'
# __all__:使用from a import *导入模块时,限制能够使用的属性
# 在使用from a import * 导入模块时,只能导入__all__指定的属性
from a import *
print(age)
print(name)
# print(sex)
14.__len__
计算长度
'''
__len__:计算对象长度,返回几,len(对象),结果就是几
len(对象)----》触发对象的__len__()
'''
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def __len__(self):
return len(self.name)
f = Foo('lqz', 19)
print(len(f))
15.__hash__
转换类型(了解即可)
'''
__hash__
-字典类型---》hash类型---》key值必须可hash
-可变类型(字典,列表)不可hash,不可变类型(数字,字符串,元组)可以hash,可以作为字典的key
-重写自己定制的类的hash方法,使对象可以hash
__hash__ ,hash(对象)触发执行,返回什么就是什么
如果一个对象不可hash,通过重写 __hash__让它变得可hash
'''
# 普通用法
l=['1',3,54,56]
dic={'name':'lqz'}
a=10
print(hash(a))
# print(hash(dic))
print(hash(l))
# 魔法方法
class Foo:
def __init__(self):
self.name = 'lqz'
self.l = ['1', 3, 4]
def __hash__(self):
return hash(self.name)
f = Foo()
print(hash(f))
16.__eq__
对象 == 触发(了解即可)
'''
两个对象 == 比较的时候,触发 __eq__的执行,在内部,自定制比较规则即可
'''
class Foo:
def __str__(self):
return self.name
def __init__(self):
self.name='lqz'
def __eq__(self, other):
# print(self)
# print(other)
# 自己定制比较规则
if self.name == other.name:
return True
else:
return False
f1=Foo()
# f1.name='mzk'
f1.age=999
f2=Foo()
f2.age=888
print(f1==f2)
# print(f1 is f2)
17.__class__
显示对象类(了解即可)
'''
__class__ 对象.__class 查看对象的类
'''
class Animal:
pass
class Person(Animal):
pass
print(Person.__bases__) # 查看所有父类
p=Person()
print(p.__class__) # 查看对象的类
18.__module__
显示对象所属模块(了解即可)
'''
__modules__:看对象属于哪个模块
'''
from a import C
obj = C()
class Person():
pass
p=Person()
print(obj.__module__)
print(p.__module__)
19.__slots__
控制对象可以使用的属性
'''
__slots__:控制对象可以使用的属性
-控制对象的属性(__dict__没了)
-对象很多,对象属性比价少
-本质:对象没有__dict__,统一被类的__dict__管理起来了,在dict内部使用更紧凑的存储方式,节约内存空间
'''
slots的使用
对象只拥有name和age属性,其它放不进去
class Person:
__slots__ = ['name', 'age'] # 对象只拥有name和age属性
# __slots__ = 'name'
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name
p = Person('mzk', 18)
print(p.name)
p.sex = '男'
20. __dict__
对象属性
'''
__dict__ 查看对象中的属性
'''
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name
p = Person('mzk', 18)
p.sex = '男'
print(p.__dict__)
21.__next__
和__iter__
实现迭代器
'''
0 python中的for循环,是依赖于迭代的循环,不依赖于索引
# 1 for i in 可迭代对象
# 2 java中 for(i=0;i++;i<10){}
# 3 python中 for循环的本质
for i in 可迭代对象:会调用可迭代对象的__iter__,得到一个迭代器对象,不停的调用对象.__next__,得到一个值,直到抛出异常,for循环结束
1 可迭代对象:对象有__iter__方法的,就是可迭代对象,调用__iter__,得到迭代器对象
2 迭代器对象:既有__iter__又有__next__对象,就是迭代器对象
__iter__和__next__
-可迭代对象:对象有__iter__方法,这个对象就是一个可迭代对象
-for循环本质就是在循环可迭代对象
-for i in 对象(必须是可迭代对象)
-for循环的本质:先调用对象的__iter__得到一个迭代器对象,然后调用迭代器对象的__next__ 方法,每次获得一个值(next这种获取值的方式不依赖于索 引,又叫迭代循环)
-迭代器对象:
-既有__iter__又有__next__的对象,就是迭代器对象
-迭代器对象一定是可迭代对象
-定制自己的可迭代对象
-重写类中的__iter__和__next__
-让它支持for循环直接循环(做出一种不依赖于索引取值的方式)
-不停的return 值,当要停下时,抛出异常
'''
# 链式调用(跟语言无关)
f.test().test2().test3() # java,js:中广泛应用,设计程序的模式
# 如何实现支持链式调用的对象
class Foo:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def print_name(self):
print(self.name)
return self
def print_age(self):
print(self.age)
return self
def print_sex(self):
print(self.sex)
return self
f=Foo('lqz',16,'男')
f.print_name()
f.print_sex()
f.print_age()
# 链式调用
f.print_name().print_sex().print_age()
# 1 给一个类,重写__iter__,__next__
class Foo:
def __init__(self):
self.__x = 1
def __iter__(self):
return self
def __next__(self):
self.__x += 1
return self.__x
f = Foo() # f就是一个可迭代对象,所以他就能够被for 循环
# 自定制可迭代对象(自己写的对象,可以迭代,可以被for循环)
for i in f: # f.__iter__()----->每循环一次,调用一下 f.__next__()
print(i)
# 2 加入异常,for循环该对象,可以停止
class Foo:
def __init__(self,start,end):
self.__start = start
self.__end=end
def __iter__(self):
return self
def __next__(self):
self.__start+=1
if self.__start>=self.__end:
raise StopIteration('') # 抛出一个异常,程序就结束了
return self.__start
for i in Foo(1,20):
print(i)
# 实现自己的range
class MyRange:
def __init__(self, start, end,step=1):
self.__start = start
self.__end = end
self.__step = step
def __iter__(self):
return self
def __next__(self):
self.__start += self.__step
if self.__start >= self.__end:
raise StopIteration('') # 抛出一个异常,程序就结束了
return self.__start
for i in MyRange(1, 20):
print(i)
# 斐波那契数列(通过__iter__和__next__实现)
# 产生小于多少的斐波那契数列
class Fib:
def __init__(self, count):
self.start = 0
self.second = 1
self.count = count
def __iter__(self):
return self
def __next__(self):
self.start,self.second=self.second,self.start+self.second
if self.start >= self.count:
raise StopIteration()
return self.start
for i in Fib(100):
print(i)
22.__enter__
和__exit__
上下文管理器
'''
with open() as f:
with 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明enter和exit方法
优点:
使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在exit中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
-with:上下文管理协议
-with 对象 as f: # 处理异常,不被with管理后,会清理资源
代码
代码
-学过的 open,支持上下文管理协议
-自定制一些对象,支持with管理
-在类中重写 __enter__和__exit__
-with 你写的对象 as f:
# 触发对象的__enter__ 方法执行,做一些初始化的工作,返回一个对象,会给f
# 写代码,可以有异常,不用咱们手动处理异常
-脱离了with的管理,会执行对象的__exit__,处理异常,资源清理工作
'''
# __enter__ 和 __exit__
class Open:
def __enter__(self):
print('enter执行了')
def __exit__(self, exc_type, exc_val, exc_tb):
print('--',exc_type)
print('--',exc_val)
print('--',exc_tb)
print('exit执行了')
# with 对象,触发对象的 __enter__的执行
# 顶格写,脱离了with,就会执行 __exit__
with Open() as f:
print('with上下文管理器')
print(f)
print('with结束了')
class Open:
def __str__(self):
return 'f对象'
def __enter__(self):
print('enter执行了')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('--',exc_type)
print('--',exc_val)
print('--',exc_tb)
print('exit执行了')
f=Open()
# print(f)
with f as ff1:
print('with上下文管理器')
print(f)
print(ff1) # enter的执行返回结果赋值给ff1
print(f is ff1)
print('with结束了')
# exit的参数解释:exit()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
class Open:
def __enter__(self):
print('enter执行了')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('异常类型',exc_type)
print('异常信息',exc_val)
print('追溯信息',exc_tb)
print('exit执行了')
return True # 忽略掉异常,不爆红
with Open() as f:
f.witer() # 没有
print('结束')
# 自定制一个open,打开文件
class Open:
def __init__(self, path, mod='rt', encoding='utf-8'):
self.f = open(path, mod, encoding=encoding)
def __enter__(self):
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
# 如果exc_tpye 不为空,表示with上下文内部出了错误,处理错误
if exc_type:
print('程序出错了,但是我处理好了,继续执行就好了')
print(exc_val)
return True
# 没有错误,正常结束,资源清理工作(关闭文件)
print('文件关闭了,放心好了')
self.f.close()
# def read(self):
# return self.f.read()
# 后期会使用with ,处理数据库链接,redis链接
with Open('a.txt', 'r', encoding='utf-8') as f:
res = f.read()
print(res)
23.描述符
'''
描述符是什么?
就是一个新式类,实现了 __get__ __set__ __delete__ 其中一个,就被称为描述符类
作用: 代理类属性
class Person:
name=描述符() # 代理类属性
描述符
-新式类,__get__ __set__ __delete__
-代理类的属性(一旦使用描述符代理,对象的__dict__中没有这个属性了)
-数据描述符和非数据描述符(__get__)
1.类属性
2.数据描述符
3.实例属性(对象属性)
4.非数据描述符
5.找不到的属性触发getattr()
-通过描述符写了一个控制对象类型的案例
-通过类装饰器+描述符实现对象类型控制
-自定制 property
-自定制 classmethod
-自定制 staticmethod
'''
23.1 描述符小案例
# 小案例,写一个描述符类(get,set,delete 参数都是固定的)
class Foo:
def __get__(self, instance, owner):
print('触发get')
def __set__(self, instance, value):
print('触发set')
def __delete__(self, instance):
print('触发delete')
f1 = Foo()
f1.name = 'mzk' # 不会触发 __set__的执行
# 这种情况会触发
class Str:
def __get__(self, instance, owner):
print('触发get')
def __set__(self, instance, value):
print('触发set')
def __delete__(self, instance):
print('触发delete')
class People:
age=19
name = Str()
def __init__(self, name): # name被Str类代理,age被Int类代理
self.name = name # 触发描述符类,set的执行
p=People('lqz')
print(p.name) # 触发描述符类,get的执行,由于get返回None,所以打印出None
23.2 描述符的分类
描述符分类:两类
'''
数据描述符: 除了get以外的,还写了别的
非数据描述符: 只有get,非数据描述符
'''
# 注意:
'''
描述符本身应该定义成新式类,被代理的类也应该是新式类
必须把描述符定义成这个类的类属性,不能为定义到构造函数中
要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性(对象属性)
4.非数据描述符
5.找不到的属性触发getattr()
'''
#举例
class Person:
def __init__(self):
name='mzk' # 在函数中定义了一个局部变量,用完就没了,不属于任何对象或类
self.name='mzk' # 属于对象,放在对象的名称空间中
Person.name='mzk' # 属于类,放在类的名称空间中,对象也能使用的到
p=Person()
print(p.name)
print(Person.name)
# 举例
class Str:
def __get__(self, instance, owner):
print('触发get')
def __set__(self, instance, value):
print('触发set')
def __delete__(self, instance):
print('触发delete')
class People:
age = 19
name = Str()
def __init__(self, name): # name被Str类代理
self.name = name # 触发描述符类,set的执行
pass
p=People('lqz')
p.name='xxx' # 放到对象的名称空间
print(p.name)
23.3描述符机制来实现类型限制功能
# python是强类型动态语言
'''
1 强类型:不同类型直接不允许直接运算
res=1+'sddd' # python中不允许,类型转换后操作,js中允许,java:隐士类型转换,go语言强类型
2 动态语言(静态语言)
-动态语言---->解释型:js,php,python,不使用显示数据类型声明,声明变量不需要指定变量类型 var a='ddd'
-静态语言---->编译型:java,c,go,
'''
# 这种只是一个提示作用,不会限制(公司里通常这么做)
def test(a:int,b:str)->int:
print(a)
print(b)
return 18
test('1',89)
# 了解
class Typed:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, owner):
# print('get--->', instance, owner)
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
print('类型不匹配')
return
instance.__dict__[self.name] = value
print(instance.__dict__)
def __delete__(self, instance):
print('delete--->', instance)
instance.__dict__.pop(self.name)
class People:
name = Typed('name', str)
age = Typed('age', int)
salary = Typed('salary', float)
def __init__(self, name, age, salary):
self.name = name # 触发Typed的 __set__,
self.age = age
self.salary = salary
# 类People中的属性 name:str age:int salary:float
p = People('mzk', '19', 1000.1)
p.salary = '99'
print(p.__dict__)
24.类的装饰器
# 1.类的装饰器:无参
def decorate(cls):
print('类的装饰器开始运行啦------>')
return cls
@decorate # 类的装饰器 People=decorate(People) 仍旧是 People=People
class People:
pass
People() # 等同于 decorate(People)()--等同于-->People()
# 2.类的装饰器:有参
def typeassert(**kwargs):
def decorate(cls):
print('类的装饰器开始运行啦------>', kwargs)
return cls
return decorate
@typeassert(name='mzk', age=19) # 执行typeassert(name='mzk',age=19)--->decorate内层函数--->People=decorate(People)
class People:
pass
p = People()
# 3.使用类装饰器+描述符,实现对对象类型的控制
class Typed:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, owner):
print('get--->', instance, owner)
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
print('set--->', instance, value)
if not isinstance(value, self.expected_type):
print('类型不匹配怕')
return
instance.__dict__[self.name] = value
def __delete__(self, instance):
print('delete--->', instance)
instance.__dict__.pop(self.name)
def typeassert(**kwargs):
def decorate(cls):
print('类的装饰器开始运行啦------>', kwargs)
for name, expected_type in kwargs.items():
'''
# 通过反射,把 name,Typed的对象,放到类中
# People.'name'=Typed('name',str)
# People.'age'=Typed('age',int)
# People.'salary'=Typed('salary',float)
本质就是如下
name = Typed('name', str)
age = Typed('age', int)
salary = Typed('salary', float)
'''
setattr(cls, name, Typed(name, expected_type))
return cls
return decorate
# 这种写法和下面的写法,效果,完全一致
@typeassert(
name=str, age=int, salary=float
) # 有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
class People:
def __init__(self, name, age, salary):
self.name = name # 描述符类的 __set__
self.age = age
self.salary = salary
# 这种写法跟上面的写法,效果,完全一致
class People:
name = Typed('name', str)
age = Typed('age', int)
salary = Typed('salary', float)
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
print(People.__dict__) # {'name':Typed的对象(属性不一样),'age':Typed的对象,'salary':Typed的对象}
# 实例化得到一个People对象
p=People('mzk',19,100.1)
p.age='15' ## 描述符类的 __set__
p.age=15
print(p.__dict__)
24.1 自制property装饰器
class Lazyproperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
# self.func是 Room类的area的内存地址,普通函数---需要传对象 area(instance)
print('我被执行')
return self.func(instance) # 此时你应该明白,到底是谁在为你做自动传递self的事情
class Room:
def __init__(self, name, width, length):
self.name = name
self.width = width
self.length = length
@Lazyproperty # area=Lazyproperty(area)--->Lazyproperty类的__init__执行,把area放到了Lazyproperty的对象中然后返回了-->area代指Lazyproperty的对象
def area(self):
return self.width * self.length
r1 = Room('alex', 2, 3)
# r1.area是Lazyproperty的对象,类是描述符类---->r1.area会触发描述符类的 __get__方法
print(r1.area) # 触发描述符类的 __get__ 的执行
print(r1.area) # 触发描述符类的 __get__ 的执行
print(r1.area) # 触发描述符类的 __get__ 的执行
# 想缓存一下
class Lazyproperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
print('我被执行')
res = self.func(instance)
# instance是r1对象,向r1对象中放了一个 r1.'函数名字'=6
instance.__dict__[self.func.__name__] = res
# 相当于
# instance.__dict__['area']=6
return res
# def __set__(self, instance, value): # 加了它,变成数据描述符,查找顺序就不对了,不能加它
class Room:
def __init__(self, name, width, length):
self.name = name
self.width = width
self.length = length
@Lazyproperty # area=Lazyproperty(area)--->Lazyproperty类的__init__执行,把area放到了Lazyproperty的对象中然后返回了-->area代指Lazyproperty的对象
def area(self):
return self.width * self.length
r1 = Room('alex', 2, 3)
# r1.area是Lazyproperty的对象,类是描述符类---->r1.area会触发描述符类的 __get__方法
print(r1.__dict__)
print(r1.area) # 触发描述符类的 __get__ 的执行
print(r1.__dict__) # {'name': 'alex', 'width': 2, 'length': 3,area:6}
print(r1.area) # 直接先从对象自身找
print(r1.area) # 直接从对象自身找
24.2 @classmethod类方法
@classmethod
class ClassMethod:
def __init__(self, func):
self.func = func
def __get__(self, instance,owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback():
print('在这里可以加功能啊...')
return self.func(owner)
return feedback
class People:
def __init__(self,name):
self.name=name
@ClassMethod # get_obj=ClassMethod(get_obj)--->ClassMethod的对象
def get_obj(cls):
print(cls)
print('这是类的绑定方法')
# People.get_obj # 触发 描述符类的__get__,--->返回feedback的内存地址
People.get_obj() # 其实执行的是feedback()--->self.func--->People类的get_obj方法,self.func(类)--->get_obj(People传入了)
24.3 @staticmethod 静态方法
@staticmethod
class StaticMethod:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
def feedback():
print('在这里可以加功能啊...')
return self.func()
return feedback
class People:
def __init__(self, name):
self.name = name
@StaticMethod # get_obj=StaticMethod(get_obj)--->StaticMethod的对象
def get_obj():
print('这是静态方法')
# People.get_obj # --->触发__get__执行----feedback内存地址
People.get_obj() # feedback()
# 带参数情况下
class StaticMethod:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
def feedback(*args, **kwargs):
print('在这里可以加功能啊...')
return self.func(*args, **kwargs)
return feedback
class People:
def __init__(self, name):
self.name = name
@StaticMethod # get_obj=StaticMethod(get_obj)--->StaticMethod的对象
def get_obj(a, b):
print(a, b)
print('这是静态方法')
# People.get_obj # --->触发__get__执行----feedback内存地址
People.get_obj(7, 8) # feedback()
网友评论