#Python3中property与setter

Python3中property和setter

下面通过列子进行讲解:

1._下划线属性
Python3中 没有进行标记的内容就是公开的public
而_ (单下划线)进行标记的属性就是受保护的protected
__(双下划线)进行标记的属性就是私有的 private

class Person:
    def __init__(self, name,  code):
        self.name = name
        self.code = code
        self.age = 2018-int(code[6:10])			#这里因为age 是可以通过身份证来获取age的
								#所以,我们在init后面就没有在进行接收参数age
zhangsan = Person("张三","110101200010100909")
print(zhangsan.age)
#(输出)18
zhangsan.age = 30							
print(zhangsan.age)
#(输出)30						#这里我们就可以看出,上面这种写法,age的值可以随意的更改
								#但是一个人的年纪是不可以任意更改的

根据上面的问题,所以我做出如下操作:

class Person:
    def __init__(self, name,  code):
        self.name = name
        self.code = code
        self._age = 2018-int(code[6:10])			#加入了下划线,

zhangsan = Person("张三","110101200010100909")
print(zhangsan.age)
zhangsan.age = 30
print(zhangsan.age)
#(输出)AttributeError: 'Person' object has no attribute 'age'
#报错了,没有找到age

print(zhangsan._age)	#这里同样啊 加个下划线,发现输出了18,
#(输出18)				#就相当于我们做了一个简单的隐藏,并能进行警告提示
zhangsan.age = 30		#但是你会发现没有下划线的zhangsan.age = 30是没有做出修改的
print(zhangsan._age)
#(输出)18		

zhangsan._age = 30				#如果我们在这里也加入下划线,你就会发现,值还是修改了
print(zhangsan._age)		    #(输出)30			
								#数据不是绝对的安全,总有办法可以对其进行修改


而当我们对于age 进行__如下操作后

class Person:
    def __init__(self, name,  code):
        self.name = name
        self.code = code
        self.__age = 2018-int(code[6:10])
        return self.__age

zhangsan = Person("张三","110101200010100909")
print(zhangsan.__age)
zhangsan.__age = 30
print(zhangsan.__age)
#(输出)AttributeError: 'Person' object has no attribute '__age'
#你会发现啊,即使外面我们也用__ 来调用,age 还是报错,找不到__age.
#那么我们要怎么拿到age

怎么样拿到__双下划线的内容

class Person:
    def __init__(self, name,  code):
        self.name = name
        self.code = code
        self.__age = 2018-int(code[6:10])


zhangsan = Person("张三","110101200010100909")
print(dir(zhangsan))					#dir 进行查看参数的属性列表
#(输出)['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'code', 'name']
									#这里就看一看到可以查看的属性,会发现里面并没有__age属性
									#但是会发现'_Person__age'这个属性,
									#这个就是__age属性进行了一个简单加密
print(zhangsan._Person__age)		#这里就可以输出age的值了
#(输出)18

在父类和子类中,父类如果有一个下划线的_属性,就是表明是收保护的,子类也可以进行调用,
但是对于有两个__的属性,表明是私有的属性,只有父类才可以进行操作,子类和外界不可以进行操作和调用。
但是有时候我们是想让外界能用和查看,但是不能进行一个修改,所以我们进行如下操作

class Person:
    def __init__(self, name,  code):
        self.name = name
        self.code = code
        self._age = 2018-int(code[6:10])

    def getage(self):					#用函数进行封装,然后用return返回出去
        return self._age

zhangsan = Person("张三","110101200010100909")
print(zhangsan.getage())
#(输出)18

#但是我们实际上是调用的def getage(self):这个方法,并不是调用数据zhangsan.age
#那么我们怎做呢?

这里就要用到我们@Property进行一个装饰了

class Person:
    def __init__(self, name, code):
        self.name = name
        self.code = code
        self._age = 2018-int(code[6:10])

    @property						#装饰器
    def age(self):					#将age函数 进行一个装饰 ,
    								#可以让age像调用数据(zhangsan.age)一样调用
    							#而不用像前面讲的那样调用方法,主要就是见名知意
        return self._age		# def age(self): 有人会问为什么这里用age命名啊?
							#因为我们要用zhangsan.age的语法进行调用,我们只是将
							#调用方法 def getage(self):的形式装饰成赋值zhangsan.age= 的形式
							#如果不用age命名,不能达到我们想要的效果
zhangsan = Person("lisi", "110101200010100909")
print(zhangsan.age)
#(输出)18

zhangsan.age = 10							#但是外界这样是不可以修改的	
print(zhangsan.age)
#(输出)	AttributeError: can't set attribute		#报错了,不能设置属性

zhangsan._age = 10
print(zhangsan.age)				#但是还是用下划线进行修改的话还是可以进行修改的
#(输出)18						#只是说 用了障眼法的效果,简单的处理一下
#(输出)10							

@property 就是用来装饰函数,变成了属性,我们可以使用正常的点符号访问它,
property取代setter和getter方法。把get方法变为属性只需要加上@property装饰器即可,此时@property本身又会创建另外一个装饰器@age.setter,负责把set方法变成给属性赋值,这么做完后,我们调用起来既可控又方便.

setter的用法

下面通过列子进行讲解:


class Person:
    def __init__(self, name, code):
        self.name = name
        self.code = code
        self._age = 2018-int(code[6:10])

    @property
    def age(self):
        return self._age

zhangsan = Person("lisi", "110101200010100909")
print(zhangsan.age)
#(输出)18
zhangsan.code = "110101200210100909"			#我们预想的是age自动通过省份证code进行自我更改
print(zhangsan.age)								#但是这里可以看出age并没有进行预期的效果
#(输出)18										#因为这里self._age = 2018-int(code[6:10])
												#只计算了一次,因为你只是修改了code,
												#并没有执行self._age = 2018-int(code[6:10])
												#而调用zhangsan.age还是返回的是原来的age18

那么我们怎么操作?

class Person:
    def __init__(self, name, code):
        self.name = name
        self.code = code
        self._age = 2018-int(code[6:10])

    @property
    def age(self):
        return self._age

    def setcode(self,code):						#这里我们添加一个setcode方法,接收self,code,
        self.code = code						#修改init里面的self.code
        self._age = 2018 - int(code[6:10])		#修改init里面的self._age


zhangsan = Person("lisi", "110101200010100909")
print(zhangsan.age)				#(输出)18
zhangsan.code = "110101200210100909"
print(zhangsan.age)				#(输出)18
zhangsan.setcode("110101200210100909")			
print(zhangsan.age)				#(输出)16				#可以看出age按照预想的输出了

#zhangsan.setcode("110101200210100909")但是这种操作不是很直观,并不能看出是进行一个赋值修改的操作。

那么这里,我们就要用到setter了

class Person:
    def __init__(self, name, code):
        self.name = name
        self._code = code
        self._age = 2018-int(code[6:10])

    @property
    def age(self):
        return self._age

    # def setcode(self,code):           #这里注释了上面的情况,方便对照
    #     self.code = code
    #     self._age = 2018 - int(code[6:10])
                                    # 这里return self._code如果是return self.code你就会发现
    @property                       #他会是一个死循环,因为你返回一个self.code
    def code(self):                 #是不是又调用了 def code(self, code):
        return self._code           #导致又进入这个函数,上面的age也是一个道理
                                    # 所以我们进行一个self._code的处理,init里面也对应修改
    @code.setter                    #为什么又写一个@property  def code(self, code):
    def code(self,code):            #因为既然我们要写入一个数据,首先要进行读取一个数据
        self._code = code           #一个@property 对应一个@code.setter,并且是同样的对code进行操作
        self._age = 2018 - int(code[6:10])

zhangsan = Person("lisi", "110101200010100909")
print(zhangsan.age)			#(输出)18
zhangsan.code = "110101200210100909"
print(zhangsan.age)			#(输出)16

#一个@property 对应一个@code.setter,并且是同样的相同的属性进行操作
@property 进行对属性的装饰,让下划线的属性(只读属性)可以正常用 .(属性) 的方式进行调取,
@code.setter对数据进行修改并装饰,让 下划线的属性 (只读属性)可以正常用 .(属性) = 的方式进行赋值

你可能感兴趣的:(Python)