所谓私有属性及私有方法,可以简单理解为不想让其他人看到的一些属性和方法,例如:
class Students(object):
def __init__(self):
self.age = 18
self.weight = 120
Amy = Students()
print(Amy.weight)
Amy老脸一红,这体重的属性咋还能被人从外部调出来……尴尬
于是就把它变成私有属性好了,不让别人看见……这么改下
class Students(object):
def __init__(self):
self.age = 18
self.__weight = 120
Amy = Students()
print(Amy.weight)
在weight
前面加俩杠,再次打印输出就报错了,说找不到该项属性,好使!
但是有时候Amy也要自己看一下自己的体重数据呀,这从外部调不出来咋整,那就设置方法,从外部调用内部方法查看!
我们可以在类里面加一个方法:
class Students(object):
def __init__(self):
self.age = 18
self.__weight = 120
def find_weight(self):
print(self.__weight)
Amy = Students()
Amy.find_weight()
这样就可以查看私有属性了!那如果要修改私有属性呢,可以这么写:
class Students(object):
def __init__(self):
self.age = 18
self.__weight = 120
def find_weight(self):
print(self.__weight)
def change_weight(self,new):
self.__weight = new
Amy = Students()
Amy.change_weight(140)
Amy.find_weight()
这里插一个知识点,.__dir__()
内置方法可以查看类里面的方法名和属性名。
属性既然有私有的,方法也有私有的,有些方法不想公开,同样的,在方法前面加两个杠就可以了,比如:
class Demo(object):
def __init__(self):
pass
def test1(self):
print('1')
def __test2(self):
print('2')
a = Demo()
a.__test2() #这样执行会报错
其中,__test2(self)
就是一个私有方法,私有方法如何调用呢?
class Demo(object):
def __init__(self):
pass
def test1(self):
print('1')
def __test2(self):
print('2')
a = Demo()
a._Demo__test2()
在私有方法前面需要加上一个下划线及类名才可以调用私有方法。
静态属性可以理解为类的属性,比如我建立了一个类为中国的省份,那么中国就属于所有省份的共有属性,也就是这一类的属性:
class Province(object):
country_belong = 'China'
def __init__(self,position):
self.position = position
pass
def test(self):
pass
Guangdong = Province('South')
在这里country_belong = 'China'
就属于静态属性,是属于类的属性,我们可以通过语句print(Province.country_belong)
输出我们的类属性。
而这里的self.position
就属于实例属性,是由每一次给对象实例化的时候需要输入的参数决定的。
先说一下实例方法:
举个例子来说:
class Demo(object):
def __init__(self,a):
self.age = a
def test(self):
print(f'{self.age}')
Tom = Demo(18)
Tom.test()
在Demo类里面的test()就是一个实例方法,它内部的代码块会用到实例化对象的属性,并且我们在调用的时候得通过Tom这个对象访问。
再说一下静态方法:
比如,举个例子:
import time
class TimeTest(object):
@staticmethod
def show_time():
print(time.strftime('%Y%m%d %H:%M:%S',time.localtime()))
TimeTest.show_time()
我们一点点来看这一小段代码,首先time.strftime(format,p_tuple=None)
是调用time模块中的方法来返回可读字符串来表示当地时间的,括号内的format是输入你想要返回的时间格式,这里可以自行去ctrl加鼠标左键来看一下不同时间的格式的输入规则,后面p_tuple是要求你输入时间元组,这里的time.localtime()
是可以返回本地时间的方法,它返回的数据类型就是一个元组。
我们设定的TimeTest类中定义了一个方法show_time,这个方法的作用就是打印输出一个格式化的本地时间,但是注意,这里并没有参数self的出现,也就是说该方法不需要实例化对象,就算是把show_time方法单独拿出来作为一个函数,功能是一样的,只不过我们放在TimTest类里面假设方便我们管理。但重点在于,我们在该方法上面加了一个装饰器@staticmethod
,这一步是不可省略的,如果省略,pycharm会自动在你缺失self的地方报错。
静态方法可以直接通过类的引用来访问,不需要通过对象,就是这么个意思。
所谓类方法,就是直接保存在类中的方法,通过类进行访问:
class Demo(object):
@classmethod
def test(cls):
print('Hello')
Demo.test()
以上是简单的一个类方法,注意@classmethod
要加上,另外cls指的就是当前类。
首先我们先做一下简单的总结:
类中有个成员的概念,所谓成员就是包括属性和方法(不要介意这个成员的说法,我也不想去管它,着重属性和方法两个角度就好)。
接下来讲property,其实这里我们需要学的是@property
装饰器,放在类里面的,等下就知道,没啥深刻含义,纯属为了更加省事儿,同时还要讲的是@func.setter
以及@func.deleter
。
现在我们有这么一串代码:
class Egg_Money(object):
def __init__(self, num):
self.__money = num
def get_money(self): #查看自己还剩多少私房钱
return self.__money
def change_money(self,num1): #如果有额外的私房钱,就修改一下数量
self.__money = num1
def remove_info(self): #一旦被发现,赶紧触发求生机制
self.__money = 0
print('This guy dare not to save egg money~')
Tom = Egg_Money(1000)
print(Tom.get_money()) #1000
Tom.change_money(2000)
print(Tom.get_money()) #2000
Tom.remove_info() #触发求生机制
print(Tom.get_money()) #0
这是一个成年男性对于私房钱的渴望……为了不让别人看见,已经将私房钱的数目设置成了私有属性,只有通过内部方法才能访问及修改。
而我们可以如何通过property、setter、deleter装饰器来使其变得简便呢?
class Egg_Money(object):
def __init__(self, num):
self.__money = num
@property
def get_money(self):
return self.__money
@get_money.setter
def change_money(self,num1):
self.__money = num1
@get_money.deleter
def remove_info(self):
self.__money = 0
print('This guy dare not to save egg money~')
Tom = Egg_Money(1000)
print(Tom.get_money) #1000
Tom.change_money = 2000
print(Tom.get_money) #2000
del Tom.remove_info #触发求生机制
print(Tom.get_money) #0
我们一个一个来看:
@property
,我们需要注意一下,在使用该装饰器后,对应装饰的方法必须有返回值,否则会报错,比如这里的get_money(self)最后是以return结尾的。其次,使用这个装饰器可以让我们在调用其装饰的方法的时候,不用再加括号了,如之前的Tom.get_money()
在这里直接可以变成Tom.get_money
,效果是一样的,这种装饰器就是让调用方法改成调用属性。@func.setter
装饰器,func是方法名,需要注意的是,func名对应的是@property
装饰器所装饰的方法名,例如这里func名就应该写get_money。setter装饰器一般用来装饰修改属性的方法,这里change_money方法就是为了修改私房钱数目,调用方法的时候我们还得同时输入数量参数,比如之前的Tom.change_money(2000)
,而用了setter装饰器之后,我们可以直接这么写,Tom.change_money = 2000
,直接给属性赋值就相当于修改了。@func.deleter
装饰器,一般用来修饰删除属性数据的方法(当然,被修饰的方法具体要起什么作用自己根据需求来写,不一定非是删除的功能)。未装饰之前,我们输入Tom.remove_info()
来调用该方法,而装饰之后,则需要通过del Tom.remove_info
来调用该方法。请仔细阅读上面的分析,有几点需要总结一下:
@property
表示只读;@property
和@func.setter
表示可读可写;@property
和@func.setter
和@func.deleter
表示可读可写可删除;@property
,才可以使用@func.setter
和@func.deleter
装饰器,否则会报错;@property
装饰器是用来装饰访问私有属性的类内部方法的,如果是非私有属性,直接在外部修改就可以了,不用内部方法,还用什么装饰器?最后,我们需要来对上述的代码做一个优化,我们可以看到,当使用装饰器后,我们的一些操作是这样的:
Tom = Egg_Money(1000)
print(Tom.get_money) #1000
Tom.change_money = 2000
print(Tom.get_money) #2000
del Tom.remove_info #触发求生机制
print(Tom.get_money) #0
来,看一下,当你想知道自己还有多少私房钱的时候,你写的是Tom.get_money
;当你要修改私房钱数目的时候,你写的是Tom.change_money
;当你想删除数据,出发求生机制的时候,你写的是Tom.remove_info
。明明都是和私房钱有关的操作,却出现了三个不同的名称,多么的不直观啊!
这是由于我们在类的内部建立方法的时候是采用了三个不同的方法名,我们不希望这样,即便私房钱的数量是个私有属性,当我们想知道具体数额的时候,我就想直接这么写print(Tom.Money)
来输出结果查看;当我想修改它的数额,变成2000块钱,我就想直接写Tom.Money = 2000
来进行修改;当我们想删除有关数据,触发求生机制的时候,我就想直接写del Tom.Money
,这样不才符合我们正常人的直观感受吗?因而,我们有必要修改内部的方法名称,来达到这样的效果:
class Egg_Money(object):
def __init__(self, num):
self.__money = num
@property
def Money(self):
return self.__money
@Money.setter
def Money(self,num1):
self.__money = num1
@Money.deleter
def Money(self):
self.__money = 0
print('This guy dare not to save egg money~')
Tom = Egg_Money(1000)
print(Tom.Money)
Tom.Money = 2000
print(Tom.Money)
del Tom.Money
print(Tom.Money)
一般在其它场景下,我们不会让类内部的方法名称相同,因为会造成混乱,但在案例中给定的场景情况下,相同的方法名会让我们的操作更加便捷,理解更加直观。有的人可能会有疑问,如果方法名相同,那你在调用该方法的时候不会发生错误吗?
在这里我们来看一下,当代码写的是print(Tom.Money)
时,程序会自动指向property装饰器装饰的函数,返回一个值再输出;当代码写的是Tom.Money = 2000
,这是一个赋值修改操作,程序会自动指向setter装饰器装饰的函数,执行该函数设定的赋值操作;当代码写的是del Tom.Money
,这是一个删除操作,程序会自动指向deleter装饰器装饰的函数,执行该函数的内部方法。
接着上面的案例讲,我们在上面的案例中,三种不同的装饰器分别装饰着三个不同功能的函数,我们其实有更加便捷的写法来实现相同的功能:
class Egg_Money(object):
def __init__(self, num):
self.__money = num
@property
def get_money(self):
return self.__money
@get_money.setter
def change_money(self,num1):
self.__money = num1
@get_money.deleter
def remove_money(self):
self.__money = 0
print('This guy dare not to save egg money~')
money = property(fget=get_money,fset=change_money,fdel=remove_money)
#这里的money是self.__money的money
Tom = Egg_Money(1000)
print(Tom.money)
Tom.money = 2000
print(Tom.money)
del Tom.money
print(Tom.money)
精髓就在于最后的property内置函数上面。采用语句私有属性名(去掉前面的下划线) = property(fget=None,fset=None,fdel=None)
,参数fget是获得类成员的属性值;参数fset是设置类成员的属性值;参数fdel是删除类成员。通过property内置方法可以更加便捷的实现上述功能。