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

本文翻译自:What's the pythonic way to use getters and setters?

I'm doing it like: 我这样做:

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

or 要么

object.property = value  
value = object.property

I'm new to Python, so i'm still exploring the syntax, and i'd like some advice on doing this. 我是Python的新手,所以我仍在探索语法,并且我想在此方面提供一些建议。


#1楼

参考:https://stackoom.com/question/B1P0/使用getter和setter的pythonic方法是什么


#2楼

查看@property装饰器


#3楼

In [1]: class test(object):
    def __init__(self):
        self.pants = 'pants'
    @property
    def p(self):
        return self.pants
    @p.setter
    def p(self, value):
        self.pants = value * 2
   ....: 
In [2]: t = test()
In [3]: t.p
Out[3]: 'pants'
In [4]: t.p = 10
In [5]: t.p
Out[5]: 20

#4楼

Try this: Python Property 试试这个: Python属性

The sample code is: 示例代码是:

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

#5楼

What's the pythonic way to use getters and setters? 使用getter和setter的pythonic方法是什么?

The "Pythonic" way is not to use "getters" and "setters", but to use plain attributes, like the question demonstrates, and del for dereferencing (but the names are changed to protect the innocent... builtins): “ Pythonic”方式不是使用“ getters”和“ setters”,而是使用简单的属性(如问题演示所示)和del进行取消引用(但名称已更改以保护无辜的内建……):

value = 'something'

obj.attribute = value  
value = obj.attribute
del obj.attribute

If later, you want to modify the setting and getting, you can do so without having to alter user code, by using the property decorator: 如果以后要修改设置并获取,则可以通过使用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

(Each decorator copies and updates the prior property object, so note that you should probably use the same name for each set, get, and delete function/method.) (每个装饰器都会复制并更新先前的属性对象,因此请注意,对于每个设置,获取和删除功能/方法,您可能应该使用相同的名称。)

After defining the above, the original setting, getting, and deleting is the same: 定义完上述内容后,原始设置,获取和删除是相同的:

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

You should avoid this: 您应该避免这种情况:

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

Firstly, the above doesn't work, because you don't provide an argument for the instance that the property would be set to (usually self ), which would be: 首先,上面的方法不起作用,因为您没有为该属性设置为实例的实例提供参数(通常为self ),即:

class Obj:

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

Secondly, this duplicates the purpose of two special methods, __setattr__ and __getattr__ . 其次,这复制了两个特殊方法__setattr____getattr__

Thirdly, we also have the setattr and getattr builtin functions. 第三,我们还有setattrgetattr内置函数。

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

The @property decorator is for creating getters and setters. @property装饰器用于创建getter和setter。

For example, we could modify the setting behavior to place restrictions the value being set: 例如,我们可以修改设置行为以限制要设置的值:

    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

In general, we want to avoid using property and just use direct attributes. 通常,我们要避免使用property而只使用直接属性。

This is what is expected by users of Python. 这是Python用户所期望的。 Following the rule of least-surprise, you should try to give your users what they expect unless you have a very compelling reason to the contrary. 遵循最小惊奇规则,除非您有非常令人信服的相反理由,否则应尝试向用户提供他们期望的结果。

Demonstration 示范

For example, say we needed our object's protected attribute to be an integer between 0 and 100 inclusive, and prevent its deletion, with appropriate messages to inform the user of its proper usage: 例如,假设我们需要将对象的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")

And usage: 和用法:

>>> 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

Do the names matter? 名称重要吗?

Yes they do . 是的,他们愿意 .setter and .deleter make copies of the original property. .setter.deleter复制原始属性。 This allows subclasses to properly modify behavior without altering the behavior in the parent. 这允许子类在不更改父级行为的情况下正确修改行为。

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

Now for this to work, you have to use the respective names: 现在要使它起作用,您必须使用相应的名称:

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

I'm not sure where this would be useful, but the use-case is if you want a get, set, and/or delete-only property. 我不确定这在哪里有用,但是用例是您是否需要获取,设置和/或仅删除属性。 Probably best to stick to semantically same property having the same name. 最好坚持使用具有相同名称的语义上相同的属性。

Conclusion 结论

Start with simple attributes. 从简单的属性开始。

If you later need functionality around the setting, getting, and deleting, you can add it with the property decorator. 如果以后需要围绕设置,获取和删除的功能,则可以使用属性装饰器添加它。

Avoid functions named set_... and get_... - that's what properties are for. 避免使用名为set_...get_...函数-这就是属性的用途。


#6楼

Using @property and @attribute.setter helps you to not only use the "pythonic" way but also to check the validity of attributes both while creating the object and when altering it. 使用@property@attribute.setter不仅可以帮助您使用“ pythonic”方式,而且可以在创建对象和更改对象时检查属性的有效性。

class Person(object):
    def __init__(self, p_name=None):
        self.name = p_name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, new_name):
        if type(new_name) == str: #type checking for name property
            self._name = new_name
        else:
            raise Exception("Invalid value for name")

By this, you actually 'hide' _name attribute from client developers and also perform checks on name property type. 这样,您实际上可以“隐藏”客户端开发人员的_name属性,并且还可以对name属性类型进行检查。 Note that by following this approach even during the initiation the setter gets called. 请注意,即使在启动过程中也遵循此方法,将调用设置程序。 So: 所以:

p = Person(12)

Will lead to: 将导致:

Exception: Invalid value for name

But: 但:

>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值