Python-使用getter和setter的pythonic方法是什么?

发布于 2021-02-02 23:21:39

我这样做:

def set_property(property,value):  
def get_property(property):  

要么

object.property = value  
value = object.property

我是Python的新手,所以我仍在探索语法,并且我想在此方面提供一些建议。

关注者
0
被浏览
159
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    试试这个:Python属性

    示例代码是:

    class C(object):
        def __init__(self):
            self._x = None
    
        @property
        def x(self):
            """I'm the 'x' property."""
            print("getter of x called")
            return self._x
    
        @x.setter
        def x(self, value):
            print("setter of x called")
            self._x = value
    
        @x.deleter
        def x(self):
            print("deleter of x called")
            del self._x
    
    
    c = C()
    c.x = 'foo'  # setter called
    foo = c.x    # getter called
    del c.x      # deleter called
    


  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    使用getter和setter的pythonic方法是什么?

    “ Pythonic”方式不是使用“ getters”和“ setters”,而是使用简单的属性(如问题演示所示)并del取消引用(但名称已更改以保护无辜的内建……):

    value = 'something'
    
    obj.attribute = value  
    value = obj.attribute
    del obj.attribute
    

    如果以后要修改设置并获取,则可以通过使用property装饰器来进行,而无需更改用户代码:

    class Obj:
        """property demo"""
        #
        @property
        def attribute(self): # implements the get - this name is *the* name
            return self._attribute
        #
        @attribute.setter
        def attribute(self, value): # name must be the same
            self._attribute = value
        #
        @attribute.deleter
        def attribute(self): # again, name must be the same
            del self._attribute
    

    (每个装饰器都会复制并更新先前的属性对象,因此请注意,对于每个设置,获取和删除功能/方法,你可能应该使用相同的名称。)

    定义完上述内容后,原始设置,获取和删除是相同的:

    obj = Obj()
    obj.attribute = value  
    the_value = obj.attribute
    del obj.attribute
    

    你应该避免这种情况:

    def set_property(property,value):  
    def get_property(property):  
    

    首先,上面的方法不起作用,因为你没有为该属性设置为实例的实例提供参数(通常为self),该参数为:

    class Obj:
    
        def set_property(self, property, value): # don't do this
            ...
        def get_property(self, property):        # don't do this either
            ...
    

    其次,这种复制的两个特殊方法的目的,__setattr____getattr__

    第三,我们还具有setattrgetattr内置功能。

        setattr(object, 'property_name', value)
        getattr(object, 'property_name', default_value)  # default is optional
    

    @property装饰是创建gettersetter方法。

    例如,我们可以修改设置行为以限制要设置的值:

        class Protective(object):
    
            @property
            def protected_value(self):
                return self._protected_value
    
            @protected_value.setter
            def protected_value(self, value):
                if acceptable(value): # e.g. type or range check
                    self._protected_value = value
    

    通常,我们要避免property使用直接属性,而只使用直接属性。

    这是Python用户所期望的。遵循最小惊奇规则,除非你有非常令人信服的相反理由,否则应尝试向用户提供他们期望的结果。

    示范

    例如,假设我们需要将对象的protected属性设置为0到100之间的整数(包括0和100),并防止其删除,并通过适当的消息通知用户其正确用法:
    
    class Protective(object):
        def __init__(self, start_protected_value=0):
            self.protected_value = start_protected_value
        @property
        def protected_value(self):
            return self._protected_value
        @protected_value.setter
        def protected_value(self, value):
            if value != int(value):
                raise TypeError("protected_value must be an integer")
            if 0 <= value <= 100:
                self._protected_value = int(value)
            else:
                raise ValueError("protected_value must be " +
                                 "between 0 and 100 inclusive")
        @protected_value.deleter
        def protected_value(self):
            raise AttributeError("do not delete, protected_value can be set to 0")
    

    和用法:

    >>> p1 = Protective(3)
    >>> p1.protected_value
    3
    >>> p1 = Protective(5.0)
    >>> p1.protected_value
    5
    >>> p2 = Protective(-5)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in __init__
      File "<stdin>", line 15, in protected_value
    ValueError: protectected_value must be between 0 and 100 inclusive
    >>> p1.protected_value = 7.3
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 17, in protected_value
    TypeError: protected_value must be an integer
    >>> p1.protected_value = 101
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 15, in protected_value
    ValueError: protectected_value must be between 0 and 100 inclusive
    >>> del p1.protected_value
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 18, in protected_value
    AttributeError: do not delete, protected_value can be set to 0
    

    名称重要吗?

    是的,他们愿意。.setter并.deleter复制原始财产。这允许子类在不更改父级行为的情况下正确修改行为。

    class Obj:
        """property demo"""
        #
        @property
        def get_only(self):
            return self._attribute
        #
        @get_only.setter
        def get_or_set(self, value):
            self._attribute = value
        #
        @get_or_set.deleter
        def get_set_or_delete(self):
            del self._attribute
    

    现在要使它起作用,你必须使用相应的名称:

    obj = Obj()
    # obj.get_only = 'value' # would error
    obj.get_or_set = 'value'  
    obj.get_set_or_delete = 'new value'
    the_value = obj.get_only
    del obj.get_set_or_delete
    # del obj.get_or_set # would error
    

    我不确定这在哪里有用,但是用例是你是否需要获取,设置和/或仅删除属性。最好坚持使用具有相同名称的语义上相同的属性。

    结论
    从简单的属性开始。

    如果以后需要围绕设置,获取和删除的功能,则可以使用属性装饰器添加它。

    避免将函数命名为set_...get_...-这就是属性的作用。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看