北京扁平疣好的医院 http://baijiahao.baidu.com/s?id=1688833387258790876&wfr=spider&for=pc

本篇文章将继续介绍Python的内建函数。

Pprint()

最常用的打印函数,可以传入多个参数一并打印。print包含多个关键字参数:sep,end,file和flush。通过关键字参数sep可以设置间隔字符以及end设置结束字符,file用于指定打印到的目标位置,可以是文件,也可以是IO流对象,默认是sys.stdout,即标准输出。flush用于强制清空缓冲区。

a=1b="hello"classC:passc=C()print(a,b,c,sep="

",end="END")#1

hello

__main__.Cobjectat0x7fecb8f6cENDd={"key":"value","layer1":{"key":[1,2,3],"layer2":{"layer3":{"layer4":{"key":"value",}},},}}print(d){key:value,layer1:{key:[1,2,3],layer2:{layer3:{layer4:{key:value}}}}}

可以看到,嵌套很深、内容很多的字典项通过print后均被压缩到一行内进行打印,层级不明显。Python提供了一个pprint标准库,用以实现友好打印的功能:

importpprintpprint.pprint(d){key:value,layer1:{key:[1,2,3],layer2:{layer3:{layer4:{key:value}}}}}

pprint函数会将字典项进行自动分层次打印。

a=[1,2,3,4]a.insert(0,a)print(a)#[[...],1,2,3,4]pprint.pprint(a)#[Recursiononlistwithid=,1,2,3,4]Pproperty()

生成一个特性(property)对象。property对象是定义数据描述符(DataDescriptor)的一种简洁的方式(啥是描述符?参见这个系列)。普通的描述符需要单独定义一个类,并给出__get__,__set__和__delete__的定义,最后再在目标类中指定描述符所控制的属性:

classOneOf:def__init__(self,*options):self.options=set(options)defvalidate(self,value):ifvaluenotinself.options:raiseValueError(f"Expected{value!r}tobeoneof{self.options!r}")def__set_name__(self,owner,name):self.name="_"+namedef__get__(self,obj,objtyp=None):returngetattr(obj,self.name)def__set__(self,obj,value):self.validate(value)setattr(obj,self.name,value)

上例定义了一个描述符,其中__set_name__特殊方法用于获取目标属性的名字,即name参数。该描述符的作用在于判断类属性是否是给定的options的其中之一,下面看一下其用法:

classSchool:course=OneOf("math","Chinese","English")score=OneOf("A","B","C")def__init__(self):self.course="English"s1=School()print(s1.course)#Englishs1.score="D"#ValueError:ExpectedDtobeoneof{B,C,A}

如果采用property,那么可以不用额外定义类OneOf,直接在目标类School中实现:

classSchool:def__init__(self):self.course_range={"math","Chinese","English"}defcourse_get(self):returnself._coursedefcourse_set(self,value):ifvaluenotinself.course_range:raiseValueError(f"Expected{value}tobeoneof{self.course_range}")self._course=valuecourse=property(fget=course_get,fset=course_set)s=School()s.course="English"print(s.course)#Englishs.course="Programming"#ValueError:ExpectedProgrammingtobeoneof{English,math,Chinese}

当然,可以采用最简洁的装饰器形式定义property:

classSchool:def__init__(self):self.course_range={"math","Chinese","English"}

propertydefcourse(self):returnself._course

course.setterdefcourse(self,value):ifvaluenotinself.course_range:raiseValueError(f"Expected{value}tobeoneof{self.course_range}")self._course=values=School()s.course="Programming"#ValueError:ExpectedProgrammingtobeoneof{Chinese,English,math}

另一个例子如下:

classCube:def__init__(self,length=0,width=0,height=0):self._length=lengthself._width=widthself._height=heightdefget_volume(self):"""Returnthevolumeofthecube"""returnself._length*self._width*self._heightvolume=property(fget=get_volume)

propertydeflength(self):returnself._length

length.setterdeflength(self,value):assertvalue=0self._length=value

length.deleterdeflength(self):self._length=0c=Cube(width=5,height=3)c.length=-2#AssertionErrorc.length=4print(c.volume)#60delc.lengthprint(c.volume)#0Rrange()

在Python中,range实际上是一种不可变的序列类型:

fromcollections.abcimportSequencea=range(10)print(isinstance(a,Sequence))#True

因为是序列类型,所以序列的基本操作,range都是支持的:

a=range(0,10,1)#Start,Stop,Stepprint(a[1])#1print(a[:5])#range(0,5)print(len(a))#10print(3ina)#True

那么,为什么不直接用list呢?因为range是固定的模式,即,从start开始,以step为步长,直到stop的序列,所以range所占用的内存空间永远是固定的,它只需存储三个变量:

importsysa=range(int(10e6))b=list(a)print(sys.getsizeof(a),sys.getsizeof(b))#

最后,range对象相等性在于range中元素是否完全相等,而不取决于start,step和stop是否相等:

a=range(4,8,2)b=range(4,7,2)print(list(a),list(b))#[4,6][4,6]print(a==b)#TrueRrepr()

返回一个对象的可打印的表示字符串,即(printablerepresentation)。repr的目的在于生成的字符串尽可能能够通过eval得到原对象,即s=eval(repr(s)):

a=range(10)print(repr(a))#range(0,10)print(eval(repr(a))==a)#True

需要同str区分开来。str通常返回对用户友好的字符串,str的结果不能用eval复原为原对象:

a="python"print(repr(a),str(a))#pythonpythonprint(eval(repr(a))==a)#Trueprint(eval(str(a))==a)#NameError:namepythonisnotdefined

对于自定义类型,可以通过__repr__特殊方法控制repr得到的结果:

classPoint:def__init__(self,x,y):self.x=xself.y=ydef__repr__(self):returnf"Point(x={self.x},y={self.y})"def__eq__(self,other):ifself.x==other.xandself.y==other.y:returnTrueelse:returnFalsep=Point(1,2)print(p)#Point(x=1,y=2)print(p==eval(repr(p))#TrueRreversed()

返回一个目标对象反序的迭代器:

a=[1,2,3,4]print(list(reversed(a)))#[4,3,2,1]

对于自定义类型,可以通过特殊方法__reversed__来自定义反序操作:

classSentence:def__init__(self,words):self.words=wordsself.s=.join(self.words)def__str__(self):returnself.sdef__reversed__(self):forwinself.words[::-1]:yieldws1=Sentence(["It","is","not","only","Python"])print(s1)#ItisnotonlyPythons2=Sentence(reversed(s1))print(s2)#PythononlynotisItRround()

取整函数:

print(round(0.4),round(0.6))#01

需要特别注意的是,round使用的取整算法称作bankerrounding,而非四舍五入,区别在于bankerrounding将所有的半数(0.5,1.5,2.5...)向最靠近的偶数取整(可以称作四舍六入五留双):

print(round(0.5),round(1.5),round(2.5))#

为什么有这样反直觉(实际反的是我们四舍五入的直觉)的规则呢?给出如下一系列数字,我们来看看不同的取整方法得到的平均数是多少:

l=10a=[x+0.5forxinrange(l)]print(a,sum(a)/l)#[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5]5.0#四舍五入fromdecimalimportDecimalb=[Decimal(x).quantize(Decimal(1),rounding=decimal.ROUND_HALF_UP)forxina]print(sum(b)/l)#5.5#roundprint(sum([round(x)forxina])/l)#5.0

可以看到,对平均数的计算,round要更准确。四舍五入的方法,对于大量的数字统计而言,会产生巨大的偏差。

往期文章:

Python内建函数(六)

Python内建函数(五)

Python内建函数(四)

Python内建函数(三)

Python内建函数(二)

Github看全文


转载请注明地址:http://www.tanhuaa.com/thzp/10923.html