python学习笔记 day26 私有属性 和 property

1. 私有属性

class Student():
    def __init__(self,name,password):
        self.name=name
        self.__password=password  # 定义了一个私有属性
    def get_password(self):  # 定义了一个get_paasword的方法,里面是类内定义的私有属性
        return self.__password
    def set_password(self,newpassword):  # 修改私有属性的函数,需要传一个参数,也就是新的password值
        self.__password=newpassword
student=Student('璇璇',123)
print(student.name)  # 查看普通属性name
print(student.get_password()) # 调用get_password方法来查看类内定义的私有属性(因为方法内返回了私有属性的值)
student.set_password(234)  # 使用set_password方法修改私有属性的值
print(student.get_password()) # 再次调用get_password方法查看私有属性的值(刚才被修改过)

运行结果:

2. 子类不能继承父类定义的私有方法

class Animal():
    def __init__(self,name,weight):
        self.name=name
        self.__weight=weight  # 定义一个私有属性
        print(Animal.__dict__)  # 可以查看Animal类的属性,方法等(这里的私有属性__weight其实真实:_Animal__weight)
class Tiger(Animal):
    print(Animal.__weight)   # 这里的私有属性__weight其实是指_Tiger__weight,所以是调不到的
tiger=Tiger('老虎',120)

运行结果:

 

其实如果真的使用暴力方法也是可以调到的~只是不建议这样做:就好比在类外面直接使用对象名._类名__私有属性名 直接可以拿到类内定义的私有属性一样~

自己写的,不知道这样算不算子类调用父类的私有属性~

class Animal():
    def __init__(self,name,weight):
        self.name=name
        self.__weight=weight  # 定义私有属性
class Tiger(Animal):
    def __init__(self,name,weight,kind):
        Animal.__init__(self,name,weight)  # 在子类的同名方法中直接调用父类的同名方法
        self.kind=kind
    def get_weight(self):
        return self._Animal__weight  # 直接在子类中调用父类的私有属性

tiger=Tiger('老虎',123,'动物')
print(tiger.get_weight())

运行结果:

 

总结:

只要是在类内定义的私有属性是不可以被子类调用的,只可以在类内调用(我上面的不太推荐,就好像不推荐在类外面使用对象名._类名__私有属性名 调用私有属性一样,尽管你能做到)

会用到私有属性的地方:

1. 隐藏其属性,不想被外部调用;

2.保护属性,不想被外部随意修改,比如可以定义一个set_password()方法,里面直接可以self.__password=new__password 但是在这一步之前可以判断传入的passsword是否符合要求,符合才修改,则海洋就可以进行约束,而不是在外面随意修改;

3. 保护属性,不想被子类继承;

 

 3. property----内置函数(本质是装饰器)可以把一些应该当作属性来用的方法,“变”为属性;

property装饰的方法不能有参数!!

比如之前计算圆面积和周长的类:

from math import pi
class Circle():
    def __init__(self,r):
        self.r=r
    def perimeter(self):
        return 2*pi*self.r
    def area(self):
        return pi*self.r**2
c1=Circle(3)
print(c1.perimeter()) # 查看圆周长
print(c1.area())  # 查看圆面积

但其实这里的area()方法和perimeer()方法看起来更应该是一个属性才对,因为方法一般都是和动作相关的,面积,周长这种名词,应该看起来更像是属性,所以我们可以借助property这个装饰器内置函数,来把方法变得像一个属性:

from math import pi
class Circle():
    def __init__(self,r):
        self.r=r
    @property  # 把方法perimeter()方法当成属性来用
    def perimeter(self):
        return 2*pi*self.r
    @property # 把方法area()当作属性来用
    def area(self):
        return pi*self.r**2
c1=Circle(3)
print(c1.perimeter) # 借助property就可以直接像调用属性的方式一样求调用方法perimeter()查看圆周长
print(c1.area)  # 借助property就可以直接像调用属性的方式一样求调用方法area()查看圆面积

运行结果:

再来看一个计算BMI指数的例子,也是借助property来把一个看似属性的方法,变成更像属性,操作的时候就把被property装饰的方法当成属性调用就可以了~

class Cal_BMI():
    def __init__(self,name,height,weight):
        self.name=name
        self.height=height
        self.weight=weight
    @property
    def BMI(self):
        return self.weight/(self.height**2)
xuan=Cal_BMI('璇璇',1.63,43)
print(xuan.BMI)  # 由于BMI()方法使用property装饰,所以可以使用一个类似属性的形式去调用BMI()方法,使它看起来更像是一个属性

运行结果:

 

 但是你会发现,即使把一个方法使用property去装饰,使它调用时看起来更像是一个属性,但是并不能像修改属性一样去修改该方法,毕竟人家只是调用起来橡属性,本质上还是一个方法!

xuan.BMI=20

当我们试图用修改普通属性的操作去修改一个被property装饰的方法时就会报错:

 

 4.修改使用property装饰的类似属性的方法:

class Student():
    def __init__(self,name,age,sex):
        self.__name=name  # 定义一个私有属性
        self.age=age
        self.sex=sex
    @property  # 被property装饰的方法不可以传参数
    def name(self):  # 把 name方法使用property装饰,可以使用类似属性的方法去调用,使它看起来更像是属性
        return self.__name

    @name.setter  # 可以对刚才被property装饰的方法name进行修改,就好像是对普通属性的修改一样,这里的方法只可以传一个参数
    def name(self,newname):
        self.__name=newname
xuan=Student('xuanxuan',22,'')
print(xuan.name)  # 其实是在调用name()方法,只是被property装饰了,可以像使用调用属性一样的方式去调用方法
xuan.name='璇璇' # 由于name被name.setter装饰了,所以可以像修改普通属性一样去修改方法
print(xuan.name)  # 查看修改之后的

运行结果:

 

 

 

注意事项:

 

 再举一个比较常见的例子:就是商品可能会随着节日等活动会有打折:我们就可以把price私有化,然后借助property把方法变得更像是一个属性

class Goods():
    discount=0.5 # 折扣半价
    def __init__(self,name,price):
        self.name=name
        self.__price=price  # 把price私有化,然后后续使用property把price()方法变的更像是属性price  然后操作起来好像在操作属性proce
    @property
    def price(self):
        return self.__price * self.discount
apple=Goods('苹果',6)
print(apple.price)

运行结果:

后续如果折扣有变化,其实只需修改静态属性discount即可~其实这里的price()是一个方法,用来计算折扣后价格的方法,但是使用property装饰之后使它看起来更像是一个属性,当我们操作对象名.price 好像在操作一个属性,其实内部进行的是计算折扣后价格的方法price,,内部是有计算这一步骤的~

 

 5.删除使用property装饰的类似属性的方法

如果想对使用property装饰过的看起来像属性的方法进行删除操作应该怎么实现呢?

class Student():
    def __init__(self,name,age,sex):
        self.__name=name  # 设置私有属性
        self.age=age
        self.sex=sex
    @property  # 被property装饰的方法不能有参数
    def name(self):
        return self.__name
    @name.setter  # 被name.setter装饰的方法也只能传一个参数,就是想要修改的新值  name.setter中的name必须与被property装饰的方法name()一样!(1)
    def name(self,newname): # 这里的方法名name也必须与被property装饰的方法名name一样(2)
        self.__name=newname

    @name.deleter # 被name.deleter装饰的方法也不能有参数,而且name.deleter中的name也必须与被property装饰的方法名一样(3)
    def name(self): # 这里的方法名也必须与被property装饰的方法名一样(4)
        del self.__name
xuan=Student('xuanxuan',22,'')
print(xuan.name) # 其实是在调用方法name(),只是被property装饰了,可以像调用属性一样调用name方法
xuan.name='璇璇' # 可以对name()方法(被property装饰的看起来像属性的方法)像对普通属性的操作一样完成修改
print(xuan.name)  # 可以打印修改后的
del xuan.name  # 可以像删除属性一样删除方法name()是因为执行了name.deleter装饰的方法name() 里面实现了del self.__name
try:
    print(xuan.name)  # 其实name已经被删了,这里执行会报错
except Exception as error:
    print("name已经被删了",error)

运行结果:

 

posted @ 2018-09-20 22:32  写的BUG代码少  阅读(263)  评论(0编辑  收藏  举报