第十一篇:面向对象之属性方法
Posted littlefivebolg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十一篇:面向对象之属性方法相关的知识,希望对你有一定的参考价值。
本篇主要介绍类中定义的各种属性,例如类属性、实例属性、类的私有属性,以及各种方法,例如实例方法、类方法、静态方法以及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,复杂的都封装了,给你看的都是简单易理解的,下篇介绍 类的魔法方法。
以上是关于第十一篇:面向对象之属性方法的主要内容,如果未能解决你的问题,请参考以下文章