浅谈Python中的setter、getter、property

本文深入探讨Python中的setter、getter与property概念,解释如何利用这些特性增强类的封装性和安全性,同时保持代码的简洁性和pythonic风格。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浅谈Python中的setter、getter、property

​ 面向对象三个重要的特性:封装、继承、多态;

​ 封装就意味着一个类或对象内部的属性或方法,不能随意被外部访问或者修改;java等语言中,可以在定义变量前面加上private来声明变量是私有变量,而python中没有关键字用于声明私有变量,但是约定俗成地使用双下划开头的变量作为私有变量;

​ 比如下面的代码:

class Person(object):
    def __init__(self, age, name):
        self.name = name
        self.__age = age
        
        
if __name__ == '__main__':
    p = Person(18, "张三")
    print("p.name: ", p.name)
    
    p.name = "李四"
    print("p.name: ", p.name)  # 可以被随意修改

    print("p.__age: ", p.__age)

​ 运行代码,报错信息如下:

p.name:  张三
Traceback (most recent call last):
    print("p.__age: ", p.__age)
AttributeError: 'Person' object has no attribute '__age'

​ 但是如果有需要访问__age属性的情况要怎么办?如何保证其内部数据的安全性呢?

​ 此时就需要在类的内部实现获取数据和修改数据的方法, 同时可以增加传入参数的判断,以防止类似于年龄这样的数据会出现负数或者几百上千的值:

class Person(object):
    def __init__(self, age, name):
        self.name = name
        self.__age = age
    
    def get_age(self):
        """获取age"""
        return self.__age
    
    def set_age(self, age):
        """设置age"""
        # 可以在这里面做一些判断,比如年龄的范围可以设置在0~120
        self.__age = age if age > 0 and age <= 120 else "年龄有误"


if __name__ == '__main__':
    p = Person(18, "张三")
    print("p.name: ", p.name)

    p.name = "李四"
    print("p.name: ", p.name)  # 可以被随意修改

    # print("p.__age: ", p.__age)
    print("p.get_age(): ", p.get_age())

    p.set_age(100)
    print("p.get_age(): ", p.get_age())

    p.set_age(150)
    print("p.get_age(): ", p.get_age())

​ 每次都要get_age()set_age(age)这样做会显得很繁琐,不够pythonic,此时,就可以用到settergetterproperty的思想了:

class Person(object):
    def __init__(self, age, name):
        self.name = name
        self.__age = age

    @property
    def age(self):
        """获取age"""
        return self.__age

    @age.setter
    def age(self, age):
        """设置age"""
        # 可以在这里面做一些判断,比如年龄的范围可以设置在0~120
        self.__age = age if age > 0 and age <= 120 else "年龄有误"


if __name__ == '__main__':
    
    p = Person(18, "张三")
    print("p.name: ", p.name)
    
    p.name = "李四"
    print("p.name: ", p.name)  # 可以被随意修改

    print("p.age: ", p.age)
    
    p.age = 32
    print("p.age: ", p.age)
    
    p.age = 999
    print("p.age: ", p.age)
    
    p.age = -18
    print("p.age: ", p.age)

    
"""
p.name:  张三
p.name:  李四
p.age:  18
p.age:  32
p.age:  年龄有误
p.age:  年龄有误
"""

​ 这样的话,在外部看来,age属性的获取就和普通的实例属性差不多了,但是修改age属性的值就不是那么随意了。

​ 另外,如果不使用settergetter这种方式,或者之前定义的set_age(age)get_age()方法已经投入使用又不想改变,就可以在类中添加:age = property(get_age, set_age),切记这里的参数是函数名,不是函数调用,所以不能加小括号;代码如下:

class Person(object):
    def __init__(self, age, name):
        self.name = name
        self.__age = age
    
    def get_age(self):
        """获取age"""
        return self.__age
    
    def set_age(self, age):
        """设置age"""
        # 可以在这里面做一些判断,比如年龄的范围可以设置在0~120
        self.__age = age if age > 0 and age <= 120 else "年龄有误"
        
    age = property(get_age, set_age)  # 这里函数名顺序不能错,当然也可以按关键字传参
    # 如: age = property(fset=set_age, fget=get_age) 
    

if __name__ == '__main__':
    
    p = Person(18, "张三")
    print("p.name: ", p.name)
    
    p.name = "李四"
    print("p.name: ", p.name)  # 可以被随意修改

    print("p.age: ", p.age)
    
    p.age = 32
    print("p.age: ", p.age)
    
    p.age = 999
    print("p.age: ", p.age)
    
    p.age = -18
    print("p.age: ", p.age)


"""
p.name:  张三
p.name:  李四
p.age:  18
p.age:  32
p.age:  年龄有误
p.age:  年龄有误
"""

顺便贴上property部分源码:

class property(object):
    """
    Property attribute.
    
      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:
    
    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
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def x(self):
            del self._x
    """
    def deleter(self, *args, **kwargs): # real signature unknown
        """ Descriptor to change the deleter on a property. """
        pass

    def getter(self, *args, **kwargs): # real signature unknown
        """ Descriptor to change the getter on a property. """
        pass

    def setter(self, *args, **kwargs): # real signature unknown
        """ Descriptor to change the setter on a property. """
        pass

    def __delete__(self, *args, **kwargs): # real signature unknown
        """ Delete an attribute of instance. """
        pass

    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __get__(self, *args, **kwargs): # real signature unknown
        """ Return an attribute of instance, which is of type owner. """
        pass

    def __init__(self, fget=None, fset=None, fdel=None, doc=None): # known special case of property.__init__
        """
        Property attribute.
        
          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:
        
        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
            @x.setter
            def x(self, value):
                self._x = value
            @x.deleter
            def x(self):
                del self._x
        # (copied from class doc)
        """
        pass

    @staticmethod # known case of __new__
    def __new__(*args, **kwargs): # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __set__(self, *args, **kwargs): # real signature unknown
        """ Set an attribute of instance to value. """
        pass

    fdel = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

    fget = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

    fset = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

    __isabstractmethod__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default


注:由于本人水平有限,文中难免出现纰漏之处,万望各位批评指正,共同进步!

<think>嗯,用户想了解Pythongettersetter方法的作用和用法。首先,我需要回忆一下这些概念。Python里的gettersetter是用来管理类的属性访问的,对吧?它们通常用于封装,确保数据的安全性和有效性。 首先,用户可能知道在其他语言如Java中,gettersetter是显式定义的方法,但在Python中,通常使用@property装饰器来实现类似的功能。这样可以直接像访问属性一样调用方法,不需要显式调用方法。比如,用户可能想通过obj.name来获取或设置属性,而不是调用obj.getName()或obj.setName()。 然后,我需要解释gettersetter的作用。主要是数据验证、封装内部实现、计算属性等。比如,当设置一个年龄时,可能需要检查是否为负数,这时候可以在setter方法里加入验证逻辑。如果直接暴露属性,用户可能设置不合法的值,而使用setter可以拦截并验证。 接下来,关于用法,应该提到如何使用@property来定义getter,然后使用@属性名.setter来定义setter。例如,在类中定义一个属性x,用@property装饰器修饰x方法作为getter,再用@x.setter修饰另一个方法作为setter。这样,当用户对x赋值时,会自动调用setter方法。 还需要注意,用户可能混淆了Python中的装饰器名称。比如,引用里提到@getter和@setter,但实际上正确的用法是使用@property和@属性名.setter。比如引用5中提到Python提供了@getter,这可能是个误解,需要纠正,正确的方式是通过@property定义getter,然后用@x.setter定义setter。 另外,用户提供的引用中有一些例子,比如引用3中的Dog类,使用了多个@property和@age.setter等,应该参考这些例子来说明实际应用。同时,需要指出使用这些装饰器后,访问属性时不需要括号,而是像普通属性一样使用。 可能用户还会想知道为什么需要gettersetter,而不是直接访问属性。这时候需要强调封装的好处,比如数据验证、惰性计算、访问控制等。例如,在设置年龄时,如果用户输入负数,可以在setter里抛出异常或进行修正。 最后,可能需要提到deleter,虽然用户没问,但作为相关知识,可以简要说明@属性名.deleter的用法,用于删除属性时的操作。 总结一下,回答的结构应该是:作用、基本用法、代码示例、注意事项、相关问题。需要确保示例正确,语法正确,使用中文,并且引用相关的引用资料。比如,在解释@property时,引用4和5中的内容,说明如何使用装饰器,以及它们如何替代显式的gettersetter方法。 另外,用户提供的引用中有一些错误,比如引用5提到的@getter装饰器,实际上Python中并没有这个,正确的做法是通过@property来创建getter,然后使用@x.setter创建setter。需要指出这一点以避免混淆。 最后,生成相关问题,可能包括为什么要用getter/setter而不是直接访问,@property的优势,如何防止属性被修改,以及数据验证的例子等。</think>### Pythongettersetter方法的作用及用法 #### 一、作用 1. **数据验证与控制** 通过setter方法限制属性的赋值范围或格式。例如,设置年龄时禁止负数[^4]。 2. **封装内部实现** 隐藏类的内部属性名,避免外部直接访问或修改敏感数据[^2][^4]。 3. **动态计算属性** 当属性依赖其他变量时,getter方法可实时计算并返回结果(如根据半径自动计算圆的面积)。 4. **访问控制** 可定义私有属性(如`self.__age`),并通过getter/setter间接操作[^3]。 --- #### 二、基本用法 Python通过`@property`和`@属性名.setter`装饰器实现gettersetter: 1. **定义getter** 使用`@property`将方法转换为“属性读取”形式: ```python class Employee: def __init__(self, name): self._name = name # 内部使用私有变量存储 @property def name(self): return self._name.upper() # 返回处理后的值 ``` 调用时直接访问属性:`emp = Employee("Alice"); print(emp.name)`[^4]。 2. **定义setter** 通过`@属性名.setter`添加赋值逻辑: ```python @name.setter def name(self, value): if not isinstance(value, str): raise ValueError("Name must be a string") self._name = value ``` 赋值时触发验证:`emp.name = "Bob"`[^5]。 --- #### 三、完整示例 ```python class Dog: def __init__(self, name, age): self.__name = name # 双下划线定义私有属性 self.__age = age @property def age(self): return self.__age @age.setter def age(self, value): if value < 0: raise ValueError("Age cannot be negative") self.__age = value d = Dog("天道", 20) d.age = 25 # 正确赋值 d.age = -5 # 触发ValueError[^3] ``` --- #### 四、注意事项 1. **避免直接暴露属性** 若直接使用公有属性(如`self.age`),可能被赋予非法值。 2. **装饰器命名规则** setter装饰器需与getter方法同名,格式为`@属性名.setter`。 3. **兼容性** 在继承时,子类可重写父类的@property方法以实现扩展。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值