🚩前言
上节介绍到了类与对象的一些基本概念,今天主要分享一下类的实操。如何把一个类中的方法作为属性使用?如何把类变为一个迭代器,然后把生成的对象当列表一样被for循环进行迭代?如何实现将一个方法或者函数每次运行的环境保存下来? |
➰类中的装饰器
💓基本概念
在函数学习的时候已经接触过了装饰器这个概念,今天再来重新提一下,装饰器可以为函提供一个最初的运行环境,在调用你写的函数之前,往往会先调用函数上方的装饰器,一个函数可以拥有多个装饰器。一般的用法如下: |
import time #装饰器函数 def timeit(func): def wrapper(*s): start=time.perf_counter() func(*s) end=time.perf_counter() print('运行时间:',end-start) return wrapper #函数使用装饰器 @timeit def mysum(n): sum=0 for i in range(n):sum+=i print(sum) #调用函数 mysum(10)
类中方法的装饰器有很多,只不过功能与函数有些不同,方法中的装饰器主要是为了限定方法的某些功能或者限定方法的类别。例如我们上节提到的@staticmethod
、@classmethod
。今天着重介绍的是@property
装饰器,他的作用可以让某些方法当做属性一样进行访问。默认的话只提供一个只读的权限,可以人为实现@getter
@setter
@deleter
property装饰器原型:proper(fget=None,fset=None,fdel=None,doc=None)
💓实现方式
Python中的实现可以将某些方法当做属性一样来访问、修改、删除已达到对某些属性的更好的封装。 |
第一种
class PTest1: def __init__(self,name): self.__name=name @property def getname(self): return self.__name p=PTest1("xiaolan") print(p.getname)
第二种
class PTest1: def __init__(self,name): self.__name=name @property def opname(self): return self.__name @opname.setter def opname(self,value): self.__name=value @opname.deleter def opname(self): self.__name="" p=PTest1("xiaolan") print(p.opname) p.opname="123" print(p.opname) del p.opname print(p.opname)
第三种
class PTestX: def __init__(self,name): self.__myname=name def getname(self): return self.__myname def setname(self,v): self.__myname=v def delname(self): self.__myname="" name=property(getname,setname,delname,"404 NotFond") p=PTestX("xiaolan") print(p.name) p.name="123" print(p.name) del p.name print(p.name)
➰类与迭代器的无缝衔接
💓基本概念
迭代器可以使用next()函数依次获取该迭代器内的下一个值,迭代器可以使程序更通用、优雅、高效、更具有Python编码风格。普通对象可以通过实现__iter__()与__next__()两个方法,使得对象变为可迭代对象,可以通过循环进行迭代。如果类只实现了__iter__()方法,该类生成的对象就变为了可迭代对象,只不过运行的时候会报TypeError: iter() returned non-iterator of type '**'如果只实现__next__()方法那么程序会报TypeError: '**' object is not iterable所以只有将类的两个方法都实现了,对象才会变为能够迭代的对象。__iter__()与__next__()方法又称为迭代器协议。
💓实现方式
将两方法实现一下,然后方法iter中返回对象本身,next返回你要返回的下一个值。 |
测试可迭代对象是否可迭代
import collections.abc class ITClass: def __init__(self,name): self.__name=name self.a=1 # 以下二者合称为迭代器协议 def __iter1__(self): return self def __next__(self): self.a+=1 return self.a i1=ITClass("小黄") # 测试对象是否可迭代 print(isinstance(i1,collections.abc.Iterable)) print(isinstance(ITClass,collections.abc.Iterable)) print(isinstance([1,2,3],collections.abc.Iterable)) # 测试对象是不是迭代器 print(isinstance(i1,collections.abc.Iterator)) print(isinstance(ITClass,collections.abc.Iterator)) print(isinstance((i for i in range(100)),collections.abc.Iterator)) # 只有i1对象的isinstance的两项结果都为True的时候才可以无限循环迭代。 for i in i1: print("Hello")
使用迭代器实现斐波那契数列
class fib: def __init__(self,nums): self.nums=nums self.a,self.b=0,1 self.i=0 def __iter__(self): return self def __next__(self): self.i+=1 # 达到终止条件就抛出异常来终止否则会一直迭代下去 if self.i>self.nums: raise StopIteration self.a,self.b=self.a+self.b,self.a return self.a f=fib(100) for i in f: print(i)
反向迭代器的实现
反向迭代器
实现了__reversed__方法的可迭代对象,可以使用reversed()反向迭代可迭代对象。
自己实现range可迭代对象
class Range: def __init__(self,startnums,endnums): self.endi=endnums self.a,self.b=0,1 self.starti=startnums def __iter__(self): while self.starti<=self.endi: yield self.starti self.starti+=1 def __reversed__(self): while self.starti<=self.endi: yield self.endi self.endi-=1 f1=Range(10,20) for i in f1: print(i) f2=reversed(Range(10,20)) for i in f2: print(i)
💓手写一个range函数
可以传入起始数值、结尾数值。默认步长是1,也可以自己传入,支持正反向迭代。 |
class Range: def __init__(self,startnums,endnums,dis=1): self.endi=endnums self.starti=startnums self.dis=dis def __iter__(self): i=self.starti j=self.endi if self.starti<self.endi: while i<=self.endi: yield i i+=self.dis else: while self.endi<=i: yield i i-=self.dis f1=Range(10,30,2) for i in f1: print(i)
➰生成器
💓基本概念
在函数中如果使用yield语句代替return 语句返回一个值,则定义了一个生成器函数 生成器函数使用yield语句返回一个值,然后保存当前函数的整个执行状态等待下一次调用(下次调用还从上次返回的时候开始)。生成器函数是一个迭代器,是可迭代对象、支持迭代。我记得这种生成器在scrapy框架中有使用,大家先记住这种语法与如何操作的即可,实际应用咱们后来再补充。
💓实现方式
def gentripls(n): for i in range(n): yield i*3 f=gentripls(10) for i in f: print(i) # 生成器表达式 # 生成器表达式与列表推导式基本一样,只不过使用()代替了[] ls=(1,2,3,4,5,6) for i in ls: print(i)