27面向对象2_属性装饰器

 

目前创新互联建站已为上千余家的企业提供了网站建设、域名、雅安服务器托管成都网站托管、企业网站设计、临颍网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

目录

属性装饰器...1

对象的销毁:...3

overload方法重载:...4

习题:...4

 

 

 

属性装饰器

对用户来说,属性装饰器包装后的这种用法好,只记一种即可,如stu1.chinese、stu1.chinese=100、del stu1.chinese;对程序员来说,两种写法的代码量并没有减少;

查看@property源码,class property(object),python3的类祖先为object,def __init__(self,fget=None,fset=None,fdel=None,doc=None);

两种方式:

方一:@property、@chinese.setter、@chinese.deleter

方二:english = property(lambda self: self._english,setenglish)

 

一般好的设计,把实例的属性保护起来,不让外部直接访问,外部使用getter读取属性和setter设置属性;

property装饰器,后面跟的函数名就是以后的属性名,它就是getter,这个必须有,有了它至少是只读属性;

setter装饰器,与属性名同名,且接收2个参数,第一个是self,第二个是将要赋值的值,有了它,属性可写;

deleter装饰器,可控制是是否删除属性,很少用;

property装饰器必须在前,setter、deleter装饰器在后;

property装饰器能通过简单的方式,把对方法的操作变成对属性的访问,并起到了一定隐藏效果;

 

注:

类设计:自圆其说;客户满意;

pycharm中stu1.__后面属性内容不会提示,即认为解释器要隐藏的东西;

 

例:

class Person:

    def __init__(self,chinese,english,history):

        self._chinese = chinese   #对于要隐藏的实例属性要用_或__,下面要提供获取或修改属性的方法,且一定要用方法来操作,不要直接操作

        self._english = english

        self.__history = history

 

    def getscore(self):

        return self._chinese,self._english,self.__history

 

    def gethistory(self):   #实例属性的获取getter,经常用

        return self.__history

 

    def sethistory(self,value):   #实例属性的设置setter,经常用,即self.__history该属性可rw读写

        self.__history = value

 

    def getenglish(self):   #self._english该属性只可r读,另可w不可r用处不大

        return self._english

 

stu1 = Person(80,90,88)

print(stu1.gethistory())   #这样的事很多,每次都用获取方法得到或设置方法修改,这样很麻烦

print(stu1.getscore())

输出:

88

(80, 90, 88)

 

例:

class Person:

    def __init__(self,chinese,english,history):

        self._chinese = chinese

        self._english = english

        self.__history = history

 

    @property   #属性装饰器,将方法转为属性,方一,通过stu1.chinese该属性可读

    def chinese(self):

        return self._chinese

 

    @chinese.setter   #此处chinese即为上面方法转属性的chinese,通过stu1.chinese=100该属性可写

    def chinese(self,value):

        self._chinese = value

 

    @chinese.deleter   #动态的删除属性,慎用,通过del stu1.chinese将自动执行该方法

    def chinese(self):

        # del self._chinese

        print('del chinese')

 

   # def getenglish(self):   #可将此段简写为lambda self: self._english

   #     return self._english

 

   # english = property(getenglish)   #通过stu1.english该属性可读

 

    def setenglish(self,value):

        self._english = value

 

    english = property(lambda self: self._english,setenglish)  #方二,通过stu1.english=120该属性可读可写,类库中使用此方式的多

 

    def __del__(self):

        print('leaving')

 

stu1 = Person(80,90,88)

print(stu1.chinese)   #r

stu1.chinese = 100   #w

print(stu1.chinese)

del stu1.chinese   #del

输出:

80

100

del chinese

90

120

leaving

 

 

 

对象的销毁:

类中可定义__del__方法,称为析构函数(方法);

作用:销毁类的实例时调用,以释放占用的资源;收尾工作,把打开的资源(连接网络、DB、打开文件等操作)关闭掉,不用这些实例时要销毁,同with语句;

由于python实现了垃圾回收机制,会自动执行该方法,不能确定何时执行,有必要请使用del语句手动调用这个方法删除实例;

 

def __del__(self):

         print('leaving')

 

 

 

overload方法重载:

python没有重载;python不需要重载;其它语言都有重载的概念;

所谓重载,即同一个方法名,但参数数量、类型不一样,就是同一个方法的重载;

python中,方法(函数)定义里,形参非常灵活,不需要指定类型,就算指定了也只是一个说明而非约束,参数个数也不固定(可变参数),一个函数的定义可实现很多种不同形式实参的调用,所以python不需要方法重载;

 

注:

标识符覆盖,override重写;

静态编译型语言,标识符一样的两个可同时用,多态;

python天生就支持多态(多种类型),如函数级的多态,def add(x,y),int和str都支持,会自动识别,一个函数对多种形态(多个数据类型)进行处理,甚至返回多种形态;

面向对象的多态,继承和覆盖override;

继承,盖住,不是有你没我,有我没你,而是我在我优先,我不在你重见天日,类似实例属性和类属性,有优先问题;

 

encapsulation封装:

面向对象的三要素之一;

将数据和操作组织到类中,即属性和方法;

将数据隐藏起来,给使用者提供操作,使用者通过操作就可获取或修改数据,getter,setter;

通过访问控制,暴露适当的数据和操作给用户,该隐藏的隐藏起来,保护成员或私有成员;

 

 

 

习题:

1、随机整数生成类,可以指定一批生成的个数,可指定数值的范围,可调整每批生成数字的个数;

import random

 

class RandomNums:

    def __init__(self,nums=10,min=0,max=100):

        self.nums = nums

        self.min = min

        self.max = max

 

    def create(self):

        return [random.randint(self.min,self.max) for _ in range(self.nums)]

 

rn = RandomNums(10,0,100)

print(rn.create())

 

#####

#作为工具类实现,提供类方法

 

class RandomNums:

    @classmethod

    def create(cls,nums=12,min=1,max=100):

        return [random.randint(min,max) for _ in range(nums)]

 

print(RandomNums.create())

 

#####

#使用生成器实现

 

class RandomGenerator:

    def __init__(self,count=10,start=1,stop=100):

        self.count = count

        self.start = start

        self.stop = stop

        self.gen = self._generator()

 

    def _generator(self):

        while True:

            yield random.randint(self.start,self.stop)

 

    def generate(self):

        return [next(self.gen) for _ in range(self.count)]

 

rg = RandomGenerator(10,1,100)

print(rg.generate())

 

#####

 

class RandomGenerator:

    def __init__(self,count=10,start=1,stop=10):

        self.count = count

        self.start = start

        self.stop = stop

        self.gen = self._generate()

 

    def _generate(self):

        while True:

            yield [random.randint(self.start,self.stop) for _ in range(self.count)]

 

    def generate(self,count):

        self.count = count

        return next(self.gen)

 

rg = RandomGenerator()

lst = rg.generate(15)

print(lst)

 

2、使用上题中的类,随机生成20个数字,两两配对形成二维坐标系的坐标,把这些坐标组织起来,并打印输出;

import random

 

class RandomGenerator:

    def __init__(self,count=10,start=1,stop=100):

        self.count = count

        self.start = start

        self.stop = stop

        self.gen = self._generate()

 

    def _generate(self):

        while True:

            yield [random.randint(self.start,self.stop) for _ in range(self.count)]

 

    def generate(self,count):

        self.count = count

        return next(self.gen)

 

class Point:

    def __init__(self,x,y):

        self.x = x

        self.y = y

 

    def __repr__(self):

        return '{}:{}'.format(self.x,self.y)

 

rg = RandomGenerator()

 

lst = [Point(x,y) for x,y in zip(rg.generate(12),rg.generate(12))]

# for p in lst:   #此方式打印,不需要Point类中的__repr__方法

#     print('{}:{}'.format(p.x,p.y))

print(Point(4,5))

print(lst)

 

3、记录车的品牌mark、color颜色、price价格、speed速度等特征,并实现增加车辆信息,显示全部信息的功能;

 

class Car:

    def __init__(self,mark,color,price,speed):

        self.mark = mark

        self.color = color

        self.price = price

        self.speed = speed

 

class CarInfo:

    def __init__(self):

        self.info = []   #数据在哪,方法就在哪

 

    def addcar(self,car:Car):

        self.info.append(car)

 

    def getall(self):

        return self.info

 

ci = CarInfo()

car = Car('audi','red',100,400)

ci.addcar(car)

print(ci.getall())

注:

修改车辆信息在Car中;

 

4、实现温度的处理;

摄氏温度和华氏温度的转换:

C = 5 * (F-32) / 9

F = 9 * C / 5 + 32

摄氏温度与开氏温度的转换:

K = C + 273.15

 

class Temperature:

    def __init__(self,t,unit='c'):

        self._c = None

        self._f = None

        self._k = None

 

        if unit == 'f':

            self._f = t

            self._c = self.f2c(t)

        elif unit == 'k':

            self._k = t

            self._c = self.k2c(t)

        else:

            self._c = t

 

    @property

    def c(self):

        return self._c

 

    @property

    def f(self):

        if self._f == None:

            self._f = self.c2f(self._c)

        return self._f

 

    @property

    def k(self):

        if self._k == None:

            self._k = self.c2k(self._c)

        return self._k

 

    @classmethod

    def f2c(cls,f):

        return 5*(f-32)/9

 

    @classmethod

    def f2k(cls,f):

        return cls.c2k(cls.f2c(f))

 

    @classmethod

    def k2c(cls,k):

        return k-273.15

 

    @classmethod

    def k2f(cls,k):

        return cls.c2f(cls.k2c(k))

 

    @classmethod

    def c2k(cls,c):

        return c+273.15

 

    @classmethod

    def c2f(cls,c):

        return 9*c/5+32

 

t = Temperature(100)   #实例化

print(t.c,t.f,t.k)   #实例属性访问

print(t.f2c(212.0))   #实例也可以用类方法

 

t = Temperature(373.15,unit='k')

print(t.c,t.f,t.k)

 

print(Temperature.c2f(100))   #如果只是工具,就用类方法或静态方法,不用实例化;如果需要为用户保存数据,且该实例会发生变化,就要实例化

print(Temperature.c2k(100))

print(Temperature.f2k(212))

print(Temperature.f2c(212))

print(Temperature.k2c(373.15))

print(Temperature.k2f(373.15))

 

5、模拟购物车购物;

 

class Color:

    RED = 0

    GREEN = 1

    BLUE = 2

    GOLDEN = 3

    BLACK = 4

    OTHER = 1000

 

class Item:

    def __init__(self,**kwargs):

        self.__spec = kwargs

 

    def __repr__(self):

        return str(sorted(self.__spec.items()))

 

class Cart:

    def __init__(self):

        self.items = []

 

    def additem(self,item:Item):

        self.items.append(item)

 

    def getall(self):

        return self.items

 

mycart = Cart()

myphone = Item(mark = 'huawei',color = Color.GOLDEN,price=3000)

mycart.additem(myphone)

print(mycart.getall())

 


网页名称:27面向对象2_属性装饰器
文章位置:http://ybzwz.com/article/pegpdi.html