• 第十一篇:面向对象之属性方法


      本篇主要介绍类中定义的各种属性,例如类属性、实例属性、类的私有属性,以及各种方法,例如实例方法、类方法、静态方法以及property属性方法等相关知识。

    class Tool(object):
        dog_type = "Huskie"  # 类属性
    
        def __init__(self,name):
            self.name = name  # 实例属性
        
        # 实例方法
        def tell_info(self):
            pass
        
        # 类方法
        @classmethod
        def bar(cls): 
            pass
        
        # 静态方法
        @staticmethod
        def foo(x):
            pass
        
        #属性方法
        @property
        def tell_name(self):
            return self.name

      接下来就这些方法进行介绍,包括对这些属性和方法的详细介绍、以及其具体用途;

    一、类属性和实例属性

      无论是类属性还是实例属性都是定义在类中,但是其根本区别是保存的位置和调用的对象不相同。例如:

    class Dogs(object):
        # 类属性
        belongTo = "Animals"
    
        def __init__(self,name):
            #实例属性
            self.name = name
    
    dog1 = Dogs("alex")
    print(Dogs.belongTo)  # 类属性通过类访问
    print(dog1.name)  # 实例属性通过实例访问
    print(dog1.belongTo) #类属性也可以被实例访问
    # print(Dogs.name)  # 但是实例属性无法被类访问

      通过上述可知:类属性可以被类和属性访问,而实例属性只能被实例访问,这是由于:

      

      这是由于每通过一个类创建一个实例对象,则会开辟一个内存空间,用来存放该实例对象的属性和方法,以及类对象的指针,实例对象之所以可以调用类中的方法,是因为可以通过类对象指针访问类的属性和方法。

      但是若实例对象想修改类的属性和方法,则需要通过特殊的方法。例如:

    class Dogs(object):
        # 类属性
        belongTo = "Animals"
    
        def __init__(self,name):
            #实例属性
            self.name = name
    
    dog1 = Dogs("alex")
    
    dog1.belongTo = "mammal"
    print(Dogs.belongTo)  #Animals
    # 注:通过这种方式是无法修改类属性的,而是在实例的属性字典中重写了该属性
    print(dog1.__dict__)  #{'name': 'alex', 'belongTo': 'mammal'}
    
    dog1.__class__.belongTo = "Mammal"
    print(Dogs.belongTo)  # Mammal--修改成功
    实例修改类属性

    二、实例方法、类方法和静态方法

      实例方法: 通常由对象调用,必须传入实例对象,执行实例方法时,自动将调用该方法的实例对象本身传给该方法的self参数。

      类方法: 通常由类调用,必须传入类对象本身,执行类方法时,自动将调用该方法的类对象赋值给cls参数;

      静态方法: 类和实例对象均可调用,不传实例对象和类对象,无默认参数。

    class Test(object):
    
        def __init__(self,name):
            self.name = name
    
        #实例方法
        def mm(self):
            print("in the mm")
    
        #类方法
        @classmethod
        def tt(cls):
            print("in the tt")
            print(cls)
    
        #静态方法
        @staticmethod
        def gg(a):
            print("in the gg",a)
    
    test1 = Test("alex")
    test1.mm()
    test1.tt()  # 实例可以调用类方法,则默认将该类对象传入 --》<class '__main__.Test'>
    test1.gg(100)
    
    Test.mm(test1)  # 类对象调用实例方法必须传入一个类
    Test.tt()
    Test.gg(100)

      相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

      不同点:方法调用者不同、调用方法时自动传入的参数不同。

      类方法和静态方法的作用:

      类方法:主要使用类方法来管理类属性,无论是私有属性还是普通类属性,在很多类中,可能不需要实例化,仅仅是为了封装,这时候我们就可以通过类方法来管理类属性。 

      静态方法:当我们有许多杂乱且无联系的函数时,我们需要将函数封装在类中,而无法修改函数的代码即参数,仅仅是为了将这些函数通过类的方式封装起来,方便进行管理。例如:

    class Tool(object):
        """
        定义一个工具箱,用来管理这些工具,仅仅是为了封装而不影响这些函数,方便管理
        """
        @staticmethod
        def hammer():  # 锤子
            pass
    
        @staticmethod
        def ax():  # 斧头
            pass
    
        @staticmethod
        def wrench():  # 扳手
            pass
    # 当我们需要使用这些工具是,直接用过类对象调用即可
    # 同时不会传入额外的参数,例如self-实例本身,cls -类本身,仅仅是为了达到封装的效果
    Tool.hammer()
    Tool.ax()

    三、属性方法property

      从字面意思来将就是 使方法变为一种特殊的属性,即一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法。例如:

    class Test(object):
        def foo(self):
            print("in the foo")
    
        # 定义property属性
        @property
        def bar(self):
            # print("in the bar")
            return "in the bar"
    
    tt = Test()
    tt.foo()  # 调用普通实例方法  -- in the foo
    ret = tt.bar  # 调用方式与类属性一样,并且也有返回值  -- in the bar
    print(ret)

      从上述代码可知:

        定义时,在实例方法上加上@property装饰器,同时有且仅有一个self参数;

        调用时,与调用类属性一样,无括号

        # 对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据 这个分页的功能包括:
    
        # 根据用户请求的当前页和总数据条数计算出 m 和 n
        # 根据m 和 n 去数据库中请求数据
    
    lass Pager:
        def __init__(self, current_page):
            # 用户当前请求的页码(第一页、第二页...)
            self.current_page = current_page
            # 每页默认显示10条数据
            self.per_items = 10 
    
        @property
        def start(self):
            val = (self.current_page - 1) * self.per_items
            return val
    
        @property
        def end(self):
            val = self.current_page * self.per_items
            return val
    
    # 调用
    p = Pager(1)
    p.start  # 就是起始值,即:m
    p.end  # 就是结束值,即:n
    页码的实例

       总结:@property,将方法转化为一种特殊的属性的装饰器,故既然既然是属性,自然会有增删改查(调用、修改、删除)等,那么我们来看怎么实现property属性的增删改查。

      property属性的增删改查(两种方式):

      两种方式 : 二、具有三种@property装饰器 ; 

             三、类属性方式,创建值为property对象的类属性

      方式一:三种@property装饰器

    # 方式一:通过装饰器,当执行某操作时,自动触发装饰器及装饰器下方法的执行(copy)
    
    class Goods(object):
    
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
    
        @property
        def price(self): 
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
    
        @price.setter   # func_name.setter
        def price(self, value):
            self.original_price = value
     
        @price.deleter   # func_name.deleter
        def price(self, value):
            del self.original_price
    
    obj = Goods()
    obj.price         # 获取商品价格
    obj.price = 200   # 修改商品原价
    del obj.price     # 删除商品原价
    
    
    # 解析:有点类似于魔法,当执行某操作时,自动触发装饰器的运行
    #   @property -- 当获取price属性时,自动执行 @property 修饰的方法,并获取方法的返回值,例如:obj.func
        @func.setter --当设置修改price属性时,自动执行 @func.setter 修饰的 func 方法,并将值赋值给方法的参数,例如:obj.func = 200
        @func.deleter --当删除price属性时,自动执行 @func.deleter 修饰的func 方法

      方式二:类属性方式,创建值为property对象的类属性

    #coding=utf-8
    class Foo(object):
        num = 100
    
        def get_bar(self):
            return num
    
        def set_bar(self, value): 
            """必须两个参数"""
            num = value
            return num
    
        def del_bar(self):
            del num
            return "deleted this attribute"
    
        #顺序不能错,分别为 获取、修改、删除、描述
        BAR = property(get_bar, set_bar, del_bar, "description...")
    
    obj = Foo()
    
    obj.BAR  # 自动调用第一个参数中定义的方法:get_bar
    obj.BAR = 200  # 自动调用第二个参数中定义的方法:set_bar方法,并将200当作参数传入
    del obj.BAR  # 自动调用第三个参数中定义的方法:del_bar方法
    desc = Foo.BAR.__doc__  # 自动获取第四个参数中设置的值:description...
    print(desc)

      

      其实关于property属性的使用很常见,它的优势十分名:

        为用户提供一个简单的属性,而不再是复杂的函数(不同考虑函数的参数是什么、函数的返回值是什么),仅仅以调用属性的方式得到函数的返回值。本质上也是封装的体现即封装底层复杂的实现方式,给用户提供一个简单、使用的属性接口。以下是大公司的代码:

    #! /usr/bin/env python
    # coding: utf-8
    
    import random
    import time
    
    
    class Message(object):
    
        def __init__(self, msgarr=[], toacc=''):
            self.msgbody = msgarr # 此处为MsgDict对象实例的列表或者空列表
            self.toacc = toacc # toacc为字符串(单发)或者列表(批量发)
            self.msgrandom = random.randint(1, 1000000000)
            self.msgrequest = {
                'To_Account': toacc, # 消息接收方账号
                'MsgRandom': self.msgrandom, # 消息随机数,由随机函数产生
                'MsgBody': [t.msg for t in msgarr]
            }
    
        def del_option(self, option):
            if option in (set(self.msgrequest)-set(['To_Account', 'MsgRandom', 'MsgBody'])):
                self.__dict__.pop(option)
                self.msgrequest.pop(option)
    
        def append_msg(self, msg):
            self.msgbody.append(msg)
            self.msgrequest['MsgBody'].append(msg.msg)
    
        def insert_msg(self, index, msg):
            self.msgbody.insert(index, msg)
            self.msgrequest['MsgBody'].insert(msg.msg)
    
        def del_msg(self, index):
            if index in range(len(self.msgbody)):
                del self.msgbody[index]
                del sel.msgrequest['MsgBody'][index]
    
        def set_from(self, fromacc):
            # 指定消息的发送方,默认为服务器发送
            self.fromacc = fromacc
            self.msgrequest['From_Account'] = fromacc
    
        def set_to(self, toacc):
            # 指定消息的接收方,可以为String(单发),可以为List(批量发送)
            self.toacc = toacc
            self.msgrequest['To_Account'] = toacc
    
        def refresh_random(self):
            self.msgrandom = random.randint(1, 1000000000)
            self.msgrequest['MsgRandom'] = self.msgrandom, # 消息随机数,由随机函数产生
    
        def set_sync(self, sync):
            # 同步选项:1, 把消息同步到From_Account在线终端和漫游上
            #           2, 消息不同步至From_Account
            #           若不填写,默认情况下会将消息同步
            #           仅在单发单聊消息中可调用
            self.sync = sync
            self.msgrequest['SyncOtherMachine'] = sync
    
        def set_timestamp(self):
            # 设置消息时间戳,unix时间, 仅在单发单聊消息中可以调用
            self.timestamp = int(time.time())
            self.msgrequest['MsgTimeStamp'] = self.timestamp
    
        def set_offlinepush(self, pushflag=0, desc='', ext='', sound=''):
            # 仅适用于APNa推送,不适用于安卓厂商推送
            self.msgrequest['OfflinePushInfo'] = {
                'PushFlag': pushflag,
                'Desc': desc,
                'Ext': ext,
                'Sound': sound
            }
    
    
    class MsgDict(object):
    
        def __init__(self, msgtype='', msgcontent={}):
            self.msgtype = msgtype
            self.msgcontent = msgcontent
    
        @property
        def msg(self):
            return {
                'MsgType': self.msgtype,
                'MsgContent': self.msgcontent
            } 
    
        def set_content(self, content):
            self.msgcontent = content
    
    
    class TextMsg(MsgDict):
    
        def __init__(self, text='', msgtype='TIMTextElem'): 
            self.text = text
            content = {'Text': text}
            super(TextMsg, self).__init__(msgtype=msgtype, msgcontent=content)
    
        def set_text(self, text):
            self.text = text
            self.msgcontent['Text'] = text
    
    
    class LocationMsg(MsgDict):
    
        def __init__(self, desc='', latitude=0, longitude=0, msgtype='TIMLocationElem'): 
            self.desc = desc
            self.latitude = latitude
            self.longitude = longitude
            content = {
                'Desc': desc,  # 地理位置描述信息, String
                'Latitude': latitude, # 纬度, Number
                'Longitude': longitude # 经度, Number
            }
            super(LocationMsg, self).__init__(msgtype=msgtype, msgcontent=content)
    
        def set_desc(self, desc):
            self.desc = desc
            self.msgcontent['Desc'] = desc
    
        def set_location(self, latitude, longitude):
            self.latitude = latitude
            self.longitude = longitude
            self.msgcontent['Latitude'] = latitude
            self.msgcontent['Longitude'] = longitude
    
        def set_latitude(self, latitude):
            self.latitude = latitude
            self.msgcontent['Latitude'] = latitude
    
        def set_longitude(self, longitude):
            self.longitude = longitude
            self.msgcontent['Longitude'] = longitude
    
    
    class FaceMsg(MsgDict):
    
        def __init__(self, index=1, data='', msgtype='TIMFaceElem'): 
            self.index = index 
            self.data = data
            content = {
                'Index': index, # 表情索引,用户自定义, Number
                'Data': data # 额外数据, String
            }
            super(TextMsg, self).__init__(msgtype=msgtype, msgcontent=content)
    
        def set_index(self, index):
            self.index = index
            self.msgcontent['Index'] = index
    
        def set_data(self, data):
            self.data = data
            self.msgcontent['Data'] = data
    
    
    class CustomMsg(MsgDict):
    
        def __init__(self, data='', desc='', ext='', sound='', msgtype='TIMCustomElem'): 
            self.data = data
            self.desc = desc
            self.ext = ext
            self.sound = sound
            content = {
                'Data': data, # 自定义消息数据。不作为APNS的payload中字段下发,故从payload中无法获取Data字段, String
                'Desc': desc, # 自定义消息描述,当接收方为iphone后台在线时,做ios离线Push时文本展示
                'Ext': ext, # 扩展字段,当接收方为ios系统且应用处在后台时,此字段作为APNS请求包Payloads中的ext键值下发,Ext的协议格式由业务方确定,APNS只做透传
                'Sound': sound # 自定义APNS推送铃声
            }
            super(CustomMsg, self).__init__(msgtype=msgtype, msgcontent=content)
    
        def set_data(self, data):
            self.data = data
            self.msgcontent['Data'] = data
    
        def set_desc(self, desc):
            self.desc = desc
            self.msgcontent['Desc'] = desc
    
        def set_ext(self, ext):
            self.ext = ext
            self.msgcontent['Ext'] = ext
    
        def set_sound(self, sound):
            self.sound = sound
            self.msgcontent['Sound'] = sound
    
    
    class SoundMsg(MsgDict):
    
        def __init__(self, uuid='', size=0, second=0, msgtype='TIMSoundElem'): 
            self.uuid = uuid 
            self.size = size 
            self.second = second
            content = {
                'UUID': uuid, # 语音序列号,后台用于索引语音的键值,String
                'Size': size, # 语音数据大小, Number 
                'Second': second # 语音时长,单位秒 Number 
            }
            super(SoundMsg, self).__init__(msgtype=msgtype, msgcontent=content)
    
        def set_uuid(self, uuid):
            self.uuid = uuid
            self.msgcontent['UUID'] = uuid
    
        def set_size(self, size):
            self.size = size
            self.msgcontent['Size'] = size
    
        def set_second(self, second):
            self.second = second
            self.msgcontent['Second'] = second
    
    
    class ImageMsg(MsgDict):
    
        def __init__(self, uuid='', imgformat=0, imginfo=[], msgtype='TIMImageElem'): 
            self.uuid = uuid 
            self.imgformat = imgformat 
            self.imginfo = imginfo 
            content = {
                'UUID': uuid, # 图片序列号,后台用于索引语音的键值,String
                'ImageFormat': imgformat, # 图片格式, BMP=1, JPG=2, GIF=3, 其他=0, Number 
                'ImageInfoArray': [t.info for t in imginfo] # 原图,缩略图或者大图下载信息, Array
            }
            super(ImageMsg, self).__init__(msgtype=msgtype, msgcontent=content)
    
        def set_uuid(self, uuid):
            self.uuid = uuid
            self.msgcontent['UUID'] = uuid
    
        def set_format(self, imgformat):
            self.imgformat = imgformat
            self.msgcontent['ImageFormat'] = imgformat
    
        def append_info(self, info):
            # info 为ImageInfo对象实例
            self.imginfo.append(info)
            self.msgcontnet['ImageInfoArray'].append(info.info)
    
        def insert_info(self, index, info):
            self.imginfo.insert(index, info)
            self.msgcontent['ImageInfoArray'].insert(index, info.info)
    
        def del_info(self, index):
            del self.imginfo[index]
            del self.msgcontent['ImageInfoArray'][index]
    
    
    class FileMsg(MsgDict):
    
        def __init__(self, uuid='', size=0, name='', msgtype='TIMFileElem'): 
            self.uuid = uuid 
            self.size = size 
            self.name = name
            content = {
                'UUID': uuid, # 文件序列号,后台用于索引语音的键值,String
                'FileSize': size, # 文件数据大小, Number 
                'FileName': name # 文件名称/路径, String
            }
            super(FileMsg, self).__init__(msgtype=msgtype, msgcontent=content)
    
        def set_uuid(self, uuid):
            self.uuid = uuid
            self.msgcontent['UUID'] = UUID
    
        def set_size(self, size):
            self.size = size
            self.msgcontent['FileSize'] = size
    
        def set_name(self, name):
            self.name = name
            self.msgcontent['FileName'] = name
    
    
    class ImageInfo(object):
    
        def __init__(self, itype=1, size=0, width=0, height=0, url=''):
            #图片类型, 1-原图, 2-大图, 3-缩略图, 0-其他
            self.itype = itype 
            # 图片数据大小,Number
            self.size = size
            # 图片宽度,Number
            self.width = width
            # 图片高度, Number
            self.height = height
            # 图片下载地址,String
            self.url = url
    
        @property
        def info(self):
            return {
                'Type': self.itype, 
                'Size': self.size,  
                'Width': self.width,  
                'Height': self.height, 
                'URL': self.url 
            }
    
        def set_type(self, itype):
            self.itype = itype
    
        def set_size(self, size):
            self.size = size
    
        def set_width(self, width):
            self.width = width
    
        def set_height(self, height):
            self.height = height
    
        def set_url(self, url):
            self.url = url
    腾讯即时通信模块-参考

      over~~~本篇没有复杂的解释,简洁明了,一如property,复杂的都封装了,给你看的都是简单易理解的,下篇介绍 类的魔法方法。

     
  • 相关阅读:
    prim 堆优化+ kruskal 按秩优化
    poj 2679 Adventurous Driving(SPFA 负环)
    poj 1125 Stockbroker Grapevine (dij优化 0ms)
    codevs 4909 寂寞的堆(写的好丑0.0)
    noi 7221 拯救公主 (状态压缩+bfs)
    codevs2059逃出克隆岛(传送门bfs)
    HUD3336
    poj 3974 Palindrome
    疑难杂症
    正则表达 比较两个浮点数
  • 原文地址:https://www.cnblogs.com/littlefivebolg/p/9351948.html
Copyright © 2020-2023  润新知