zoukankan      html  css  js  c++  java
  • 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)

    运行结果:

    talk is cheap,show me the code
  • 相关阅读:
    当函数中传递的参数数量不定时,获取传递给函数的参数信息
    redis分页摘抄
    redis分页
    返回数组中指定的一列,将键值作为元素键名array_column
    PHP操作Redis常用技巧总结
    php面试中的经典问题
    php 依赖注入的实现
    10分钟快速理解依赖注入
    PHP 依赖注入,依赖反转 (IOC-DI)
    PHP控制反转(IOC)和依赖注入(DI)
  • 原文地址:https://www.cnblogs.com/xuanxuanlove/p/9683779.html
Copyright © 2011-2022 走看看