030.Python面向对象_类&补充_只读属性

本文介绍了Python编程的入门教程,包括虚拟环境配置、PyQt5GUI开发以及Oracle数据库教程。重点讲解了如何在类中使用只读属性和装饰器property,分别展示了新式类和经典类中的应用实例。
摘要由CSDN通过智能技术生成

无奋斗不青春

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈

分隔线

只读属性

概念

  • 一个属性(一般指实例属性),只能读取,不能写入

应用场景

  • 有些属性,只限在内部根据不同场景进行修改,对外界来说,不能修改,只能读取

实现方法

方式一:使用property装饰器
  • 步骤
    • 1、通过私有化全部隐藏(既不能读,也不能写)
    • 2、通过方法部分公开(公开读的操作)
  • 示例
    class Person:
        def __init__(self):
            self.__age = 18
    
        def getAge(self):
            return self.__age
    
    
    p = Person()
    
    # print(p.__age)          # 报错,通过属性私有化,隐藏了读操作
    # p.__age = 22            # 并不是修改的私有属性,而是新增了__age属性。通过属性私有化,隐藏了写操作
    
    print(p.getAge())       # 通过指定方法,公开读操作
    
  • 存在问题
    • 1、获取属性的时候需要通过调用方法获取p.getAge(),而不是通过属性获取方式获取p.age
    • 2、在外部直接使用赋值p.age = 22 并不会报错(虽然没有修改内部的私有属性,而是给实例添加了一个age属性,但是给人的感觉就是修改了)
  • 优化
    class Person:
        def __init__(self):
            self.__age = 18
    
        # @property的作用:装饰器,可以使用属性的方式调用这个方法
        @property
        def age(self):
            return self.__age
    
    
    p = Person()
    
    print(p.age)        # 18
    # p.age = 22          # 报错,AttributeError: can't set attribute
    
  • 通过优化之后,就可以通过调用属性的方式调用读属性方法了。并且,外部也不能对这个属性方法进行赋值
  • 缺陷
    • 通过装饰器的方式设置的只读属性,其实还是可以通过 _Person__age 这种改名之后的方式进行修改
    • 也可以通过 实例.__dict__['_Person__age'] = 新值 的方式修改这个只读属性的值
方式二:使用__setattr__方法进行判断
  • 步骤
    • 当通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值时候,会自动调用该方法
    • 在这个方法内部,增加判定方法,满足条件后才把这个属性添加到 __dict__ 这个字典中
  • 代码说明
    class Person(object):
        # 当通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值时候,会自动调用该方法
        # 在这个方法内部,才会真正的把这个属性添加到 __dict__ 这个字典中
        def __setattr__(self, key, value):
            # key:属性   value:属性值
            print(key, value)
    
    
    p = Person()
    p.age = 12          # age 12
    
  • 使用__setattr__设置只读属性
    class Person(object):
        def __init__(self):
            self.__age = 18
            pass
    
        @property
        def age(self):
            return self.__age
    
        # 当通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值时候,会自动调用该方法
        # 在这个方法内部,才会真正的把这个属性添加到 __dict__ 这个字典中
        def __setattr__(self, key, value):
            # key:属性   value:属性值
            # print(key, value)
            if key == 'age':
                print('隐藏属性,不可修改', key)
                return
    
            # self.key = value
            # 不能这么写,这样写也是通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值,会循环调用__setattr__方法,出现死循环
            # 只能通过下面的方法给实例添加/修改属性
            self.__dict__[key] = value
    
    
    p = Person()
    print(p.age)            # 18
    p.age = 22              # 隐藏属性,不可修改 age
    print(p.age)            # 18
    
    
    

补充_装饰器property详解

property作用

  • 将一些“属性的操作方法(删、改、查)”关联到某一个属性中
class Person(object):
    def __init__(self):
        self.__age = 18
    
    @property    
    def age(self, num):
        """属性的操作方法:获取属性值"""
        return self.__age

property源码

  • preoperty源码说明
    class property(object):
        """
        Property attribute.
        
        property(fget=None, fset=None, fdel=None, doc=None) -> property ottribute
        # 调用property函数,传入四个参数,返回一个属性
        # 作用:将一个属性的几个操作方法(删、改、查)关联到返回的这个属性里面
        # 读取这个属性的时候会自动调用第一个参数:fget方法
        # 设置这个属性的值会自动调用第二个参数:fset方法
        # 删除合格属性的时候会自动调用第三个参数:fdel方法
        
          fget
            function to be used for getting an attribute value
            # 用于获取属性值的函数
          fset
            function to be used for setting an attribute value
            # 用于设置属性值的函数
          fdel
            function to be used for del'ing an attribute
            # 用于删除属性值的函数
          doc
            docstring
        
        Typical use is to define a managed attribute x:
        # 典型的用法是定义一个定义和管理一个属性x:
        
        class C(object):
            def getx(self): return self._x
            def setx(self, value): self._x = value
            def delx(self): del self._x
            x = property(getx, setx, delx, "I'm the 'x' property.")
        
        Decorators make defining new properties or modifying existing ones easy:
        # 装饰器使定义新属性或修改现有属性变得容易:
        
        class C(object):
            @property
            def x(self):
                "I am the 'x' property."
                return self._x
                
            # 必须先开启上面的@property装饰器
            @x.setter
            def x(self, value):
                self._x = value
            @x.deleter
            def x(self):
                del self._x
        """
    

补充:经典类和新式类

  • 经典类
    • 概念:没有继承自object的类
  • 新式类
    • 概念:继承自object的类和其派生类
  • 示例
    # 在Python2.x 版本中
    class Person:
        pass
    
    
    class Animal(object):
        pass
    
    
    # 查看基类(父类)
    print(Person.__base__)      # ()
    print(Animal.__base__)      # <class 'object'>
    
    
    # ===================================================
    
    # 在Python3.x 版本中
    class Person:
        pass
    
    
    class Animal(object):
        pass
    
    
    # 查看基类(父类)
    print(Person.__base__)      # <class 'object'>
    print(Animal.__base__)      # <class 'object'>
    
  • 在Python2.x版本中
    • 定义一个类的时候,没有显示的继承自object类,那么这个类就是一个经典类
    • 必须显示的继承自object类,才是一个新式类
  • 在Python3.x版本中
    • 定义一个类的时候,没有显示的继承自pbject类时,会隐式的(默认)继承自object类,这个类就是一个新式类
    • 在通常情况下,我们一般都写成显示继承(即:定义的类继承自object时,也用class Person(object)的方式定义)

property在两种类中的使用方式

property在新式类中的使用方式
  • 使用方式一
    class Person(object):
        def __init__(self):
            # 定义一个属性__age
            self.__age = 18
    
        def get_age(self):
            """定义一个__age属性的操作方法(查)"""
            print('执行get_age方法')
            return self.__age
    
        def set_age(self, num):
            """定义一个__age属性的操作方法(改)"""
            print('执行set_age方法')
            self.__age = num
    
        # 调用property方法,使age属性与get_age、set_age方法进行关联
        # 在获取age属性的值时,自动调用property函数的第一个参数:get_age方法
        # 在设置age属性的值时,自动调用property函数的第二个参数:seg_age方法
        age = property(get_age, set_age)
    
    
    p = Person()
    print(p.age)        # 执行get_age方法  18
    
    p.age = 36          # 执行set_age方法
    print(p.age)        # 执行get_age方法  36
    
    print(p.__dict__)   # {'_Person__age': 36},可以看出来,赋值方式并没有给对象增加新的属性,而是直接修改了原本的属性值
    
  • 使用方式二
    class Person(object):
        def __init__(self):
            self.__age = 18
    
        @property
        def age(self):
            print("执行了@property装饰的age方法")
            return self.__age
    
        @age.setter
        def age(self, num):
            print("执行了@age.setter装饰的age方法")
            self.__age = num
    
        @age.deleter
        def age(self):
            print("执行了@age.deleter装饰的age方法")
            del self.__age
    
    
    
    
    p = Person()
    print(p.age)        # 执行了@property装饰的age方法  18
    
    p.age = 36          # 执行了@age.setter装饰的age方法
    
    print(p.__dict__)   # {'_Person__age': 36}
    
    del p.age           # 执行了@age.deleter装饰的age方法
    
property在经典类中的使用方式(在Python2.x版本中运行)
  • 使用方式一
    # Python2.x版本运行
    # 定义一个经典类,不继承自object类
    class Person:
        def __init__(self):
            self.__age = 18
    
        def get_age(self):
            print '执行了get_age方法'
            return self.__age
    
        def set_age(self, num):
            print '执行了set_age方法'
            self.__age = num
    
        age =property(get_age, set_age)
    
    
    
    p = Person()
    print p.age        # 执行了get_age方法
    
    p.age = 36          # 
    
    print(p.__dict__)   # {'age': 36, '_Person__age': 18}
    
    # 可以看出来,在经典类中,属性的赋值操作并不能关联到property函数的第二个参数
    
  • 使用方式二
    # Python2.x版本运行
    # 定义一个经典类,不继承自object类
    class Person:
        def __init__(self):
            self.__age = 18
    
        @property
        def age(self):
            print '执行了get_age方法'
            return self.__age
    
        @age.setter
        def age(self, num):
            print '执行了set_age方法'
            self.__age = num
    
    
    
    
    p = Person()
    print p.age        # 执行了get_age方法  18
    
    p.age = 36          #
    
    print(p.__dict__)   # {'age': 36, '_Person__age': 18}
    
  • 通过示例可以看出来,在经典类中,虽然我们可以定义装饰属性赋值操作的方法,但是并不能真正的将这个操作方法与赋值操作进行关联
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失心疯_2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值