6.3【类与对象】可管理的对象属性及类比较

文章讨论了在面向对象编程中,如何通过方法作为对象的接口来提高安全性与灵活性,对比了直接访问属性和使用方法的优缺点。介绍了使用`property`来创建访问器和设置器,以及如何通过重载运算符实现对象间的比较。此外,还展示了装饰器的概念及其在多层调用中的工作原理。
摘要由CSDN通过智能技术生成
在面向对象编程中,把方法(函数)看作对象的接口。直接访问对象的属性可能是不安全的,或设计上不够灵活。但是使用调用方法在形式上不如访问属性简洁
circle.getRadius()
circle.setRadius(5.0) # 繁

circle.radius
circle.radius = 5.0 # 简
能否在形式上是属性访问,但实际上调用方法?

from math import pi
class Circle(object):
	def __init__(self, radius):
		self.radius = radius
	
	def getRadius(self):
		# 灵活性 return round(self.radius, 2)
		return self.radius
	
	def setRadius(self, value):
		if not isinstance(value, (int, long, float)):
			raise ValueError('wrong type.')
		self.radius = float(value)
	
	def getArea(self):
		return self.radius ** 2 * pi

c = Circle(3.2)
c.radius = 'abc'
d = c.radius * 2
print d # 运行没错,逻辑错误;
# 安全方面
c.setRadius('abc')
# 灵活性,无法对输入再做操作,因为直接访问到了内部属性
c.getRadius()

但访问器和设置器使用繁琐:使用property函数为类创建可管理属性,fget/fset/fdel对应相应属性访问
from math import pi
class Circle(object):
	def __init__(self, radius):
		self.radius = radius
	
	def getRadius(self):
		return self.radius
	
	def setRadius(self, value):
		if not isinstance(value, (int, long, float)):
			raise ValueError('wrong type.')
		self.radius = float(value)
	
	def getArea(self):
		return self.radius ** 2 * pi
	
	R = property(getRadius, setRadius)

c = Circle(3.2)
print c.R
c.R = '3'
print c.R
c.R = 'abc'

类比较
自定义的类,实例间可以使用<,<=,>,>=,==,!=符号进行比较,自定义比较的行为。
例如,有一个矩形的类,希望比较两个矩形的实例时,比较的是他们的面积
class Rectangle:
	def __init__(self,w,h):
		self.w = w
		self.h = h
	def area(self):
		return self.w*self.h
rect1 = Rectangle(5,3)
rect2 = Rectangle(4,4)
rect1 > rect2  #  =>  rect1.area() > rect2.area()

# 运算符重载,需实现如下方法:
__lt__,__le__,__gt__,__ge__,__eq__,__ne__
  <		  <=	  >		 >=		  =		 !=
使用标准库下的functools下的类装饰器total_ordering可以简化此过程
class Rectangle:
	def __init__(self,w,h):
		self.w = w
		self.h = h
	def area(self):
		return self.w*self.h
	def __lt__(self,obj):
		return self.area() < obj.area()
	def __le__(self,obj):
		return self.area() <= obj.area()
r1 = Rectangle(5,3)
r2 = Rectangle(4,4)

r1 < r2 # 实际调用 r1.__lt__(r2)
r1 <= r2

from functools import total_ordering
@total_ordering
class Rectangle:
	def __init__(self,w,h):
		self.w = w
		self.h = h
	def area(self):
		return self.w*self.h
	def __eq__(self,obj): # 重载两个方法,其中一个为等于,另一个随意
		return self.area() == obj.area()
	def __lt__(self,obj):
		return self.area() < obj.area()
rect1 = Rectangle(5,3)
rect2 = Rectangle(4,4)
r1 <= r2


多个修饰器

def outter61(func1):
    def inner61(*args,**kwargs):   
        print("第一个装饰器~~~~111")
        func1(*args,**kwargs)
    return inner61
def outter62(func2):            
    def inner62(*args,**kwargs):
        print("第二个装饰器~~~~2222")
        func2(*args,**kwargs)
    return inner62
def outter63(func3):    
    def inner63(*args,**kwargs):
        func3(*args, **kwargs)
        print("第三个装饰器~~~~333")
    return inner63

@outter61
@outter62
@outter63
def check():
    print("check")
check()

"""
输出结果:
第一个装饰器~~~~111
第二个装饰器~~~~2222
check
第三个装饰器~~~~333
"""

仅由程序执行过程来看,先执行outter61.  进入outter61后,
首先打印("第一个装饰器~~~~111")
下一步执行func1,此时func1的执行需要调用inner62才能完成,
执行过程进入inner62后打印("第二个装饰器~~~~2222")  
下一步执行func2,此时func2的执行需要调用inner63,
执行过程进入inner63,此时func3正是被传入(装饰)的原函数check(),
继而返回inner63,执行inner63内剩余步骤,即打印("第三个装饰器~~~~333")
执行过程进入原函数,打印check(输出到此结束,但是程序的执行还未停止),
执行到这一步,返回到inner62,func2对inner63的调用完成。
执行到这一步,返回到inner61,func1对inner62的调用完成。
整个函数结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值