Python中的@property Decorator:其用例,优点和语法

 2023-09-06 阅读 28 评论 0

摘要:🔶聚会 (🔶 Meet Properties) Welcome! In this article, you will learn how to work with the @property decorator in Python. 欢迎! 在本文中,您将学习如何在Python中使用@property装饰器。 You will learn: 您将学习: The a

🔶聚会 (🔶 Meet Properties)

Welcome! In this article, you will learn how to work with the @property decorator in Python.

欢迎! 在本文中,您将学习如何在Python中使用@property装饰器。

You will learn:

您将学习:

  • The advantages of working with properties in Python.

    在Python中使用属性的优点。
  • The basics of decorator functions: what they are and how they are related to @property.

    装饰器功能的基础:它们是什么以及它们与@property的关系。
  • How you can use @property to define getters, setters, and deleters.

    如何使用@property定义getter,setter和Deleters。

1️⃣Python属性的优势 (1️⃣ Advantages of Properties in Python)

Let's start with a little bit of context. Why would you use properties in Python?

让我们从一些上下文开始。 为什么要在Python中使用属性?

Properties can be considered the "Pythonic" way of working with attributes because:

可以将属性视为使用属性的“ Pythonic”方式,因为:

  • The syntax used to define properties is very concise and readable.

    用于定义属性的语法非常简洁易读。
  • You can access instance attributes exactly as if they were public attributes while using the "magic" of intermediaries (getters and setters) to validate new values and to avoid accessing or modifying the data directly.

    您可以完全使用实例属性访问实例属性,就像它们是公共属性一样,同时使用中介的“魔术”(获取程序和设置程序)来验证新值并避免直接访问或修改数据。
  • By using @property, you can "reuse" the name of a property to avoid creating new names for the getters, setters, and deleters.

    通过使用@property,您可以“重用”属性的名称,以避免为getter,setter和Deleters创建新名称。

These advantages make properties a really awesome tool to help you write more concise and readable code. 👍

这些优点使属性成为一个非常了不起的工具,可以帮助您编写更简洁易读的代码。 👍

2️⃣ 装饰者简介 (2️⃣ Intro to Decorators)

A decorator function is basically a function that adds new functionality to a function that is passed as argument. Using a decorator function is like adding chocolate sprinkles to an ice cream 🍨. It lets us add new functionality to an existing function without modifying it.

装饰器函数基本上是一种向作为参数传递的函数添加新功能的函数。 使用装饰器功能就像在冰淇淋adding中添加巧克力一样。 它使我们无需修改即可向现有功能添加新功能。

In the example below, you can see what a typical decorator function looks like in Python:

在下面的示例中,您可以看到Python中典型的装饰器函数的外观:

def decorator(f):def new_function():print("Extra Functionality")f()return new_function@decorator
def initial_function():print("Initial Functionality")initial_function()

Let's analyze these elements in detail:

让我们详细分析这些元素:

  • We first find the decorator function def decorator(f) (the sprinkles ✨) that takes a function f as an argument.

    我们首先找到将函数f作为参数的装饰函数def decorator(f) (撒上✨)。

def decorator(f):def new_function():print("Extra Functionality")f()return new_function
  • This decorator function has an nested function, new_function . Notice how f is called inside new_function to achieve the same functionality while adding new functionality before the function call (we could also add new functionality after the function call).

    此装饰器函数具有一个嵌套函数new_function 。 注意在new_function内部如何调用f来实现相同的功能,同时在函数调用之前添加新功能(我们也可以在函数调用之后添加新功能)。

  • The decorator function itself returns the nested function new_function.

    装饰器函数本身返回嵌套函数new_function

  • Then (below), we find the function that will be decorated (the ice cream 🍦) initial_function. Notice the very peculiar syntax (@decorator) above the function header.

    然后(在下面),我们将找到要装饰的功能(冰淇淋🍦) initial_function 。 请注意函数标@decorator非常特殊的语法( @decorator )。

@decorator
def initial_function():print("Initial Functionality")initial_function()

If we run the code, we see this output:

如果运行代码,我们将看到以下输出:

Extra Functionality
Initial Functionality

Notice how the decorator function runs even if we are only calling initial_function(). This is the magic of adding @decorator 🔮.

注意装饰器函数如何运行,即使我们仅调用initial_function() 。 这是添加@decorator the的魔力。

🔔 Note: In general, we would write @<decorator_function_name>, replacing the name of the decorator function after the @ symbol.

🔔 注意:通常,我们将编写@<decorator_function_name> ,在@符号后替换装饰器函数的名称。

I know you may be asking: how is this related to @property? @property is a built-in decorator for the property() function in Python. It is used to give "special" functionality to certain methods to make them act as getters, setters, or deleters when we define properties in a class.

我知道您可能会问:这与@property有什么关系? @property是Python中property()函数的内置装饰器。 当我们在类中定义属性时,它用于为某些方法提供“特殊”功能,以使它们充当获取器,设置器或删除器。

Now that you are familiar with decorators, let's see a real scenario of the use of @property!

既然您已经熟悉装饰器,那么让我们看看使用@property的真实场景!

🔶现实场景:@property (🔶 Real-World Scenario: @property)

Let's say that this class is part of your program. You are modeling a house with a House class (at the moment, the class only has a price instance attribute defined):

假设此类是您程序的一部分。 您正在使用House类对房屋进行建模(目前,该类仅定义了price实例属性):

class House:def __init__(self, price):self.price = price

This instance attribute is public because its name doesn't have a leading underscore. Since the attribute is currently public, it is very likely that you and other developers in your team accessed and modified the attribute directly in other parts of the program using dot notation, like this:

此实例属性是公共的,因为其名称没有下划线。 由于该属性当前是公共属性,因此您和团队中的其他开发人员很可能使用点符号直接在程序的其他部分访问和修改了该属性,如下所示:

# Access value
obj.price# Modify value
obj.price = 40000

💡 Tip: obj represents a variable that references an instance of House.

提示: obj代表引用House实例的变量。

So far everything is working great, right? But let's say that you are asked to make this attribute protected (non-public) and validate the new value before assigning it. Specifically, you need to check if the value is a positive float. How would you do that? Let's see.

到目前为止,一切都很好,对吗? 但是, 假设要求您将此属性设置为保护状态(非公共),并在分配新值之前对其进行验证 。 具体来说,您需要检查该值是否为正浮点数。 你会怎么做? 让我们来看看。

更改代码 (Changing your Code)

At this point, if you decide to add getters and setters, you and your team will probably panic 😱. This is because each line of code that accesses or modifies the value of the attribute will have to be modified to call the getter or setter, respectively. Otherwise, the code will break ⚠️.

此时,如果您决定添加getter和setter,您和您的团队可能会感到恐慌😱。 这是因为访问或修改属性值的每一行代码都必须进行修改,以分别调用getter或setter。 否则,代码将破坏⚠️。

# Changed from obj.price
obj.get_price()# Changed from obj.price = 40000
obj.set_price(40000)

But... Properties come to the rescue! With @property, you and your team will not need to modify any of those lines because you will able to add getters and setters "behind the scenes" without affecting the syntax that you used to access or modify the attribute when it was public.

但是...抢救财产! 使用@property ,您和您的团队将不需要修改任何这些行,因为您将能够在“幕后”添加getter和setter,而不会影响公共属性时用于访问或修改属性的语法。

Awesome, right? 🎉

太好了吧? 🎉

🔶@property:语法和逻辑 (🔶 @property: Syntax and Logic)

If you decide to use @property, your class will look like the example below:

如果决定使用@property ,则类将类似于以下示例:

class House:def __init__(self, price):self._price = price@propertydef price(self):return self._price@price.setterdef price(self, new_price):if new_price > 0 and isinstance(new_price, float):self._price = new_priceelse:print("Please enter a valid price")@price.deleterdef price(self):del self._price

Specifically, you can define three methods for a property:

具体来说,您可以为属性定义三种方法

  • A getter - to access the value of the attribute.

    吸气剂 -访问属性的值。

  • A setter - to set the value of the attribute.

    setter-设置属性的值。

  • A deleter - to delete the instance attribute.

    删除器 -删除实例属性。

Price is now "Protected"Please note that the price attribute is now considered "protected" because we added a leading underscore to its name in self._price:

价格现在处于“受保护”状态,请注意,由于我们在self._price名称中添加了下划线,因此price属性现在被视为“受保护”。

self._price = price

In Python, by convention, when you add a leading underscore to a name, you are telling other developers that it should not be accessed or modified directly outside of the class. It should only be accessed through intermediaries (getters and setters) if they are available.

按照惯例 ,在Python中,当您在名称中添加下划线时,您是在告诉其他开发人员不应在类外部直接访问或修改它。 如果存在中介,则只能通过中介机构(getter和setter)进行访问。

📌吸气剂 (📌 Getter)

Here we have the getter method:

这里有getter方法:

@property
def price(self):return self._price

Notice the syntax:

注意语法:

  • @property - Used to indicate that we are going to define a property. Notice how this immediately improves readability because we can clearly see the purpose of this method.

    @property property-用于指示我们将定义一个属性。 请注意,这可以立即提高可读性,因为我们可以清楚地看到此方法的目的。

  • def price(self) - The header. Notice how the getter is named exactly like the property that we are defining: price. This is the name that we will use to access and modify the attribute outside of the class. The method only takes one formal parameter, self, which is a reference to the instance.

    def price(self) -标头。 注意,getter的命名方式与我们定义的属性完全相同: price 。 这是我们将用来在类外部访问和修改属性的名称。 该方法仅采用一个形式参数self,该参数是对实例的引用。

  • return self._price - This line is exactly what you would expect in a regular getter. The value of the protected attribute is returned.

    return self._price这行是您在常规getter中所期望的。 返回protected属性的值。

Here is an example of the use of the getter method:

这是使用getter方法的示例:

>>> house = House(50000.0) # Create instance
>>> house.price            # Access value
50000.0

Notice how we access the price attribute as if it were a public attribute. We are not changing the syntax at all, but we are actually using the getter as an intermediary to avoid accessing the data directly.

注意我们如何访问价格属性,就像它是公共属性一样。 我们根本没有更改语法,但实际上是使用getter作为中介,以避免直接访问数据。

📌二传手 (📌 Setter)

Now we have the setter method:

现在我们有了setter方法:

@price.setter
def price(self, new_price):if new_price > 0 and isinstance(new_price, float):self._price = new_priceelse:print("Please enter a valid price")

Notice the syntax:

注意语法:

  • @price.setter - Used to indicate that this is the setter method for the price property. Notice that we are not using @property.setter, we are using @price.setter. The name of the property is included before .setter.

    @price.setter用于指示这是price属性的设置方法。 注意,我们没有使用@ property .setter ,我们正在使用@ price .setter 。 属性的名称包含在.setter之前。

  • def price(self, new_price): - The header and the list of parameters. Notice how the name of the property is used as the name of the setter. We also have a second formal parameter (new_price), which is the new value that will be assigned to the price attribute (if it is valid).

    def price(self, new_price): -标头和参数列表。 注意如何将属性名称用作设置器的名称。 我们还有第二个形式参数( new_price ),它是将分配给price属性的新值(如果有效)。

  • Finally, we have the body of the setter where we validate the argument to check if it is a positive float and then, if the argument is valid, we update the value of the attribute. If the value is not valid, a descriptive message is printed. You can choose how to handle invalid values according the needs of your program.

    最后,我们具有setter的主体,在其中验证参数以检查它是否为正浮点,然后,如果参数有效,则更新属性的值。 如果该值无效,则会显示一条描述性消息。 您可以根据程序需要选择如何处理无效值。

This is an example of the use of the setter method with @property:

这是在@property中使用setter方法的示例:

>>> house = House(50000.0)  # Create instance
>>> house.price = 45000.0   # Update value
>>> house.price             # Access value
45000.0

Notice how we are not changing the syntax, but now we are using an intermediary (the setter) to validate the argument before assigning it. The new value (45000.0) is passed as an argument to the setter :

请注意,我们如何不更改语法,但是现在我们使用中介程序(setter)在分配参数之前验证参数。 新值(45000.0)作为参数传递给setter:

house.price = 45000.0

If we try to assign an invalid value, we see the descriptive message. We can also check that the value was not updated:

如果尝试分配无效值,则会看到描述性消息。 我们还可以检查该值是否未更新:

>>> house = House(50000.0)
>>> house.price = -50
Please enter a valid price
>>> house.price
50000.0

💡 Tip: This proves that the setter method is working as an intermediary. It is being called "behind the scenes" when we try to update the value, so the descriptive message is displayed when the value is not valid.

💡 提示:这证明了setter方法正在作为中介。 当我们尝试更新该值时,它被称为“幕后”,因此当该值无效时将显示描述性消息。

📌删除器 (📌 Deleter)

Finally, we have the deleter method:

最后,我们有deleter方法:

@price.deleter
def price(self):del self._price

Notice the syntax:

注意语法:

  • @price.deleter - Used to indicate that this is the deleter method for the price property. Notice that this line is very similar to @price.setter, but now we are defining the deleter method, so we write @price.deleter.

    @price.deleter用于指示这是price属性的删除方法。 注意,这一行与@ price.setter非常相似,但是现在我们定义了deleter方法,因此我们编写@price。 删除器

  • def price(self): - The header. This method only has one formal parameter defined, self.

    def price(self): -标头。 此方法仅定义了一个形式参数self。

  • del self._price - The body, where we delete the instance attribute.

    del self._price主体,我们在其中删除实例属性。

💡 Tip: Notice that the name of the property is "reused" for all three methods.

提示:请注意,所有三种方法的属性名称都被“重用”。

This is an example of the use of the deleter method with @property:

这是在@property中使用deleter方法的示例:

# Create instance
>>> house = House(50000.0)# The instance attribute exists
>>> house.price
50000.0# Delete the instance attribute
>>> del house.price# The instance attribute doesn't exist
>>> house.price
Traceback (most recent call last):File "<pyshell#35>", line 1, in <module>house.priceFile "<pyshell#20>", line 8, in pricereturn self._price
AttributeError: 'House' object has no attribute '_price'

The instance attribute was deleted successfully 👍. When we try to access it again, an error is thrown because the attribute doesn't exist anymore.

实例属性已成功删除👍。 当我们再次尝试访问它时,由于该属性不再存在,将引发错误。

final一些最终提示 (🔔 Some final Tips )

You don't necessarily have to define all three methods for every property. You can define read-only properties by only including a getter method. You could also choose to define a getter and setter without a deleter.

您不必为每个属性都定义所有三种方法。 您可以通过仅包含getter方法来定义只读属性。 您也可以选择定义没有删除程序的getter和setter。

If you think that an attribute should only be set when the instance is created or that it should only be modified internally within the class, you can omit the setter.

如果您认为仅应在创建实例时设置属性,或者仅应在类内部对其进行修改,则可以省略设置器。

You can choose which methods to include depending on the context that you are working with.

您可以根据要使用的上下文选择要包括的方法。

Summary总结 (📣 In Summary)

  • You can define properties with the @property syntax, which is more compact and readable.

    您可以使用@property语法定义属性,该语法更加紧凑和易读。
  • @property can be considered the "pythonic" way of defining getters, setters, and deleters.

    @property可以被视为定义getter,setter和Deleters的“ pythonic”方式。
  • By defining properties, you can change the internal implementation of a class without affecting the program, so you can add getters, setters, and deleters that act as intermediaries "behind the scenes" to avoid accessing or modifying the data directly.

    通过定义属性,您可以在不影响程序的情况下更改类的内部实现,因此可以添加充当“幕后”中介的getter,setter和Deleters,以避免直接访问或修改数据。

I really hope you liked my article and found it helpful. 👍 To learn more about Properties and Object Oriented Programming in Python, check out my online course, which includes 6+ hours of video lectures, coding exercises, and mini projects.

我真的希望您喜欢我的文章并发现它对您有所帮助。 👍要了解有关Python属性和面向对象编程的更多信息, 请查看我的在线课程 ,其中包括6个小时以上的视频讲座,编码练习和小型项目。

翻译自: https://www.freecodecamp.org/news/python-property-decorator/

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/7142.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息