使用 getter 和 setter 的 Python 方式是什么?

发布于 2024-08-28 11:06:04 字数 236 浏览 12 评论 0原文

我这样做是这样的:

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

或者

object.property = value  
value = object.property

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

I'm doing it like:

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

or

object.property = value  
value = object.property

What's the pythonic way to use getters and setters?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

妞丶爷亲个 2024-09-04 11:06:04

试试这个: 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

Try this: Python Property

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
满意归宿 2024-09-04 11:06:04

使用 getter 和 setter 的 Python 方式是什么?

“Pythonic”方式是使用“getters”和“setters”,而是使用普通属性,就像问题演示的那样,以及del用于删除(但名称被更改以保护无辜...内置):

value = 'something'

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

如果稍后您想要修改设置和获取,您可以通过使用 property 装饰器来完成此操作,而无需更改用户代码:(

class Obj:
    """property demo"""
    #
    @property            # first decorate the getter method
    def attribute(self): # This getter method name is *the* name
        return self._attribute
    #
    @attribute.setter    # the property decorates with `.setter` now
    def attribute(self, value):   # name, e.g. "attribute", is the same
        self._attribute = value   # the "value" name isn't special
    #
    @attribute.deleter     # decorate with `.deleter`
    def attribute(self):   # again, the method name is the same
        del self._attribute

每个装饰器用法会复制并更新之前的属性对象,因此请注意,每个设置、获取和删除函数/方法应该使用相同的名称。)

定义上述内容后,原来的设置、获取和删除代码是相同的:

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

你应该避免这种情况:

def set_property(属性,值):  
def get_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 装饰器用于创建 getter 和 setter。

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

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 之间的整数,并防止其被删除,并使用适当的消息来通知用户其正确用法:(

class Protective(object):
    """protected property demo"""
    #
    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")

请注意,__init__ 指的是到 self.protected_value ,但属性方法引用 self._protected_value ,这样 __init__ 通过公共 API 使用该属性,确保它。是“受保护的”。)

和用法:

>>> 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_... 的函数 - 这就是属性的用途。

What's the pythonic way to use getters and setters?

The "Pythonic" way is not to use "getters" and "setters", but to use plain attributes, like the question demonstrates, and del for deleting (but the names are changed to protect the innocent... builtins):

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:

class Obj:
    """property demo"""
    #
    @property            # first decorate the getter method
    def attribute(self): # This getter method name is *the* name
        return self._attribute
    #
    @attribute.setter    # the property decorates with `.setter` now
    def attribute(self, value):   # name, e.g. "attribute", is the same
        self._attribute = value   # the "value" name isn't special
    #
    @attribute.deleter     # decorate with `.deleter`
    def attribute(self):   # again, the method name is the same
        del self._attribute

(Each decorator usage copies and updates the prior property object, so note that you should use the same name for each set, get, and delete function/method.)

After defining the above, the original setting, getting, and deleting code 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:

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

Thirdly, we also have the setattr and getattr builtin functions.

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

The @property decorator is for creating getters and setters.

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.

This is what is expected by users of 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:

class Protective(object):
    """protected property demo"""
    #
    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")

(Note that __init__ refers to self.protected_value but the property methods refer to self._protected_value. This is so that __init__ uses the property through the public API, ensuring it is "protected".)

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

丑疤怪 2024-09-04 11:06:04
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
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
ぽ尐不点ル 2024-09-04 11:06:04

使用 @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")

通过这种方式,您实际上对客户端开发人员“隐藏”_name 属性,并对 name 属性类型执行检查。请注意,通过遵循此方法,即使在启动期间也会调用 setter。所以:

p = Person(12)

将导致:

Exception: Invalid value for name

但是:

>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception

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.

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. 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
智商已欠费 2024-09-04 11:06:04

这是一个老问题,但这个话题非常重要并且始终是最新的。如果有人想要超越简单的 getters/setters,我写了一篇关于 python 中超级属性的文章,支持插槽、可观察性和减少样板代码。

from objects import properties, self_properties


class Car:
    with properties(locals(), 'meta') as meta:

        @meta.prop(read_only=True)
        def brand(self) -> str:
            """Brand"""

        @meta.prop(read_only=True)
        def max_speed(self) -> float:
            """Maximum car speed"""

        @meta.prop(listener='_on_acceleration')
        def speed(self) -> float:
            """Speed of the car"""
            return 0  # Default stopped

        @meta.prop(listener='_on_off_listener')
        def on(self) -> bool:
            """Engine state"""
            return False

    def __init__(self, brand: str, max_speed: float = 200):
        self_properties(self, locals())

    def _on_off_listener(self, prop, old, on):
        if on:
            print(f"{self.brand} Turned on, Runnnnnn")
        else:
            self._speed = 0
            print(f"{self.brand} Turned off.")

    def _on_acceleration(self, prop, old, speed):
        if self.on:
            if speed > self.max_speed:
                print(f"{self.brand} {speed}km/h Bang! Engine exploded!")
                self.on = False
            else:
                print(f"{self.brand} New speed: {speed}km/h")
        else:
            print(f"{self.brand} Car is off, no speed change")

这个类可以这样使用:

mycar = Car('Ford')

# Car is turned off
for speed in range(0, 300, 50):
    mycar.speed = speed

# Car is turned on
mycar.on = True
for speed in range(0, 350, 50):
    mycar.speed = speed

此代码将产生以下输出:

Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Turned on, Runnnnnn
Ford New speed: 0km/h
Ford New speed: 50km/h
Ford New speed: 100km/h
Ford New speed: 150km/h
Ford New speed: 200km/h
Ford 250km/h Bang! Engine exploded!
Ford Turned off.
Ford Car is off, no speed change

有关如何以及为什么的更多信息,请参见:https://mnesarco.github.io/blog/2020/07/23/python-metaprogramming-properties-on-steroids

This is an old question but the topic is very important and always current. In case anyone wants to go beyond simple getters/setters i have wrote an article about superpowered properties in python with support for slots, observability and reduced boilerplate code.

from objects import properties, self_properties


class Car:
    with properties(locals(), 'meta') as meta:

        @meta.prop(read_only=True)
        def brand(self) -> str:
            """Brand"""

        @meta.prop(read_only=True)
        def max_speed(self) -> float:
            """Maximum car speed"""

        @meta.prop(listener='_on_acceleration')
        def speed(self) -> float:
            """Speed of the car"""
            return 0  # Default stopped

        @meta.prop(listener='_on_off_listener')
        def on(self) -> bool:
            """Engine state"""
            return False

    def __init__(self, brand: str, max_speed: float = 200):
        self_properties(self, locals())

    def _on_off_listener(self, prop, old, on):
        if on:
            print(f"{self.brand} Turned on, Runnnnnn")
        else:
            self._speed = 0
            print(f"{self.brand} Turned off.")

    def _on_acceleration(self, prop, old, speed):
        if self.on:
            if speed > self.max_speed:
                print(f"{self.brand} {speed}km/h Bang! Engine exploded!")
                self.on = False
            else:
                print(f"{self.brand} New speed: {speed}km/h")
        else:
            print(f"{self.brand} Car is off, no speed change")

This class can be used like this:

mycar = Car('Ford')

# Car is turned off
for speed in range(0, 300, 50):
    mycar.speed = speed

# Car is turned on
mycar.on = True
for speed in range(0, 350, 50):
    mycar.speed = speed

This code will produce the following output:

Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Turned on, Runnnnnn
Ford New speed: 0km/h
Ford New speed: 50km/h
Ford New speed: 100km/h
Ford New speed: 150km/h
Ford New speed: 200km/h
Ford 250km/h Bang! Engine exploded!
Ford Turned off.
Ford Car is off, no speed change

More info about how and why here: https://mnesarco.github.io/blog/2020/07/23/python-metaprogramming-properties-on-steroids

撕心裂肺的伤痛 2024-09-04 11:06:04

属性非常有用,因为您可以将它们与赋值一起使用,但也可以包含验证。您可以在使用装饰器 @property 和 @.setter 来创建方法的地方看到此代码:

# Python program displaying the use of @property 
class AgeSet:
    def __init__(self):
        self._age = 0

    # using property decorator a getter function
    @property
    def age(self):
        print("getter method called")
        return self._age

    # a setter function
    @age.setter
    def age(self, a):
        if(a < 18):
            raise ValueError("Sorry your age is below eligibility criteria")
        print("setter method called")
        self._age = a

pkj = AgeSet()

pkj.age = int(input("set the age using setter: "))

print(pkj.age)

我在这篇文章中也写了更多详细信息:https://pythonhowtoprogram.com/how-to-create-getter-setter-class-属性-in-python-3/

Properties are pretty useful since you can use them with assignment but then can include validation as well. You can see this code where you use the decorator @property and also @<property_name>.setter to create the methods:

# Python program displaying the use of @property 
class AgeSet:
    def __init__(self):
        self._age = 0

    # using property decorator a getter function
    @property
    def age(self):
        print("getter method called")
        return self._age

    # a setter function
    @age.setter
    def age(self, a):
        if(a < 18):
            raise ValueError("Sorry your age is below eligibility criteria")
        print("setter method called")
        self._age = a

pkj = AgeSet()

pkj.age = int(input("set the age using setter: "))

print(pkj.age)

There are more details in this post I wrote about this as well: https://pythonhowtoprogram.com/how-to-create-getter-setter-class-properties-in-python-3/

分開簡單 2024-09-04 11:06:04

您可以使用访问器/修改器(即@attr.setter@property),但最重要的是保持一致!

如果您使用@property来简单地访问属性,例如

class myClass:
    def __init__(a):
        self._a = a

    @property
    def a(self):
        return self._a

使用它来访问每个*属性!使用 @property 访问某些属性并保留一些其他属性 public (即不带下划线的名称)而不使用访问器,这将是一种不好的做法,例如 do not do

class myClass:
    def __init__(a, b):
        self.a = a
        self.b = b

    @property
    def a(self):
        return self.a

请注意,self.b 这里没有显式访问器,即使它是公共的。

setters(或mutators)类似,请随意使用@attribute.setter,但保持一致! do 例如

class myClass:
    def __init__(a, b):
        self.a = a
        self.b = b 

    @a.setter
    def a(self, value):
        return self.a = value

我很难猜测你的意图。一方面,你说 ab 都是公共的(它们的名称中没有前导下划线),所以理论上我应该被允许访问/变异(获取/设置) 两个都。但随后您仅为 a 指定了一个显式变元,这告诉我也许我不应该能够设置 b。由于您提供了显式变元,我不确定缺少显式访问器 (@property) 是否意味着我不应该能够访问这些变量中的任何一个,或者您只是在使用 <代码>@属性。

*例外情况是,您明确希望使某些变量可访问或可变但不是两者,或者您希望在访问或更改属性时执行一些附加逻辑。这是我个人使用 @property@attribute.setter 的时候(否则公共属性没有显式的访问器/修改器)。

最后,PEP8 和 Google 风格指南建议:

PEP8、为继承而设计 说:

对于简单的公共数据属性,最好只公开属性名称,而不需要复杂的访问器/修改器方法。请记住,如果您发现简单的数据属性需要扩展功能行为,Python 提供了一条未来增强的简单路径。在这种情况下,请使用属性将功能实现隐藏在简单的数据属性访问语法后面。

另一方面,根据 Google 风格指南 Python 语言规则/属性 建议:

在新代码中使用属性来访问或设置通常使用简单、轻量级访问器或设置器方法的数据。应使用 @property 装饰器创建属性。

这种方法的优点:

通过消除简单属性访问的显式 get 和 set 方法调用,提高了可读性。允许计算变得懒惰。考虑使用 Pythonic 方式来维护类的接口。就性能而言,当直接变量访问合理时,允许属性绕过需要的琐碎访问器方法。这还允许将来添加访问器方法而不会破坏接口。

和缺点:

必须从 Python 2 中的 object 继承。可以隐藏副作用,就像运算符重载一样。子类可能会造成混淆。

You can use accessors/mutators (i.e. @attr.setter and @property) or not, but the most important thing is to be consistent!

If you're using @property to simply access an attribute, e.g.

class myClass:
    def __init__(a):
        self._a = a

    @property
    def a(self):
        return self._a

use it to access every* attribute! It would be a bad practice to access some attributes using @property and leave some other properties public (i.e. name without an underscore) without an accessor, e.g. do not do

class myClass:
    def __init__(a, b):
        self.a = a
        self.b = b

    @property
    def a(self):
        return self.a

Note that self.b does not have an explicit accessor here even though it's public.

Similarly with setters (or mutators), feel free to use @attribute.setter but be consistent! When you do e.g.

class myClass:
    def __init__(a, b):
        self.a = a
        self.b = b 

    @a.setter
    def a(self, value):
        return self.a = value

It's hard for me to guess your intention. On one hand you're saying that both a and b are public (no leading underscore in their names) so I should theoretically be allowed to access/mutate (get/set) both. But then you specify an explicit mutator only for a, which tells me that maybe I should not be able to set b. Since you've provided an explicit mutator I am not sure if the lack of explicit accessor (@property) means I should not be able to access either of those variables or you were simply being frugal in using @property.

*The exception is when you explicitly want to make some variables accessible or mutable but not both or you want to perform some additional logic when accessing or mutating an attribute. This is when I am personally using @property and @attribute.setter (otherwise no explicit acessors/mutators for public attributes).

Lastly, PEP8 and Google Style Guide suggestions:

PEP8, Designing for Inheritance says:

For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.

On the other hand, according to Google Style Guide Python Language Rules/Properties the recommendation is to:

Use properties in new code to access or set data where you would normally have used simple, lightweight accessor or setter methods. Properties should be created with the @property decorator.

The pros of this approach:

Readability is increased by eliminating explicit get and set method calls for simple attribute access. Allows calculations to be lazy. Considered the Pythonic way to maintain the interface of a class. In terms of performance, allowing properties bypasses needing trivial accessor methods when a direct variable access is reasonable. This also allows accessor methods to be added in the future without breaking the interface.

and cons:

Must inherit from object in Python 2. Can hide side-effects much like operator overloading. Can be confusing for subclasses.

她说她爱他 2024-09-04 11:06:04

您可以使用魔术方法 __getattribute____setattr__

class MyClass:
    def __init__(self, attrvalue):
        self.myattr = attrvalue
    def __getattribute__(self, attr):
        if attr == "myattr":
            #Getter for myattr
    def __setattr__(self, attr):
        if attr == "myattr":
            #Setter for myattr

请注意,__getattr____getattribute__ 不同。 __getattr__ 仅在未找到属性时调用。

You can use the magic methods __getattribute__ and __setattr__.

class MyClass:
    def __init__(self, attrvalue):
        self.myattr = attrvalue
    def __getattribute__(self, attr):
        if attr == "myattr":
            #Getter for myattr
    def __setattr__(self, attr):
        if attr == "myattr":
            #Setter for myattr

Be aware that __getattr__ and __getattribute__ are not the same. __getattr__ is only invoked when the attribute is not found.

别靠近我心 2024-09-04 11:06:04
class ChangingPassword(object):
    def __init__(self, username, password):
        """use _ for change to read only type(protected)."""
        self.username = username
        self._password = password

    def username(self):
        return self.username

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, new_password: int):
        if isinstance(new_password, int):
            if self._password != new_password:
                self._password = new_password
            else:
                raise ValueError('Enter different value!')


user01 = ChangingPassword('Herment', 1321)
print(user01.password)
user01.password = 6301
print(user01.password)
class ChangingPassword(object):
    def __init__(self, username, password):
        """use _ for change to read only type(protected)."""
        self.username = username
        self._password = password

    def username(self):
        return self.username

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, new_password: int):
        if isinstance(new_password, int):
            if self._password != new_password:
                self._password = new_password
            else:
                raise ValueError('Enter different value!')


user01 = ChangingPassword('Herment', 1321)
print(user01.password)
user01.password = 6301
print(user01.password)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文