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

  本篇主要介绍类中定义的各种属性,例如类属性、实例属性、类的私有属性,以及各种方法,例如实例方法、类方法、静态方法以及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--修改成功
实例修改类属性

扫描二维码关注公众号,回复: 2317086 查看本文章

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

  实例方法: 通常由对象调用,必须传入实例对象,执行实例方法时,自动将调用该方法的实例对象本身传给该方法的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,复杂的都封装了,给你看的都是简单易理解的,下篇介绍 类的魔法方法。

 

猜你喜欢

转载自www.cnblogs.com/littlefivebolg/p/9351948.html