简介
在这个实验中,你将学习 Python 中的属性访问。你将探索如何使用 getattr()
和 setattr()
等函数来有效地操作对象属性。
此外,你还将对绑定方法进行实验。本实验将引导你了解这些概念,并且在这个过程中,你将创建一个名为 tableformat.py
的文件。
This tutorial is from open-source community. Access the source code
💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版
在这个实验中,你将学习 Python 中的属性访问。你将探索如何使用 getattr()
和 setattr()
等函数来有效地操作对象属性。
此外,你还将对绑定方法进行实验。本实验将引导你了解这些概念,并且在这个过程中,你将创建一个名为 tableformat.py
的文件。
在 Python 中,对象是一个基本概念。对象可以将数据存储在属性中,属性就像是存储值的具名容器。你可以把属性看作是属于对象的变量。有几种方法可以访问这些属性。最直接且常用的方法是点号 (.
) 表示法。不过,Python 还提供了一些特定的函数,让你在处理属性时拥有更多的灵活性。
让我们先创建一个 Stock
对象,看看如何使用点号表示法来操作它的属性。点号表示法是一种简单直观的访问和修改对象属性的方式。
首先,打开一个新的终端并启动 Python 交互式 shell。在这里,你可以逐行编写和执行 Python 代码。
## Open a new terminal and run Python interactive shell
python3
## Import the Stock class from the stock module
from stock import Stock
## Create a Stock object
s = Stock('GOOG', 100, 490.1)
## Get an attribute
print(s.name) ## Output: 'GOOG'
## Set an attribute
s.shares = 50
print(s.shares) ## Output: 50
## Delete an attribute
del s.shares
## If we try to access s.shares now, we'll get an AttributeError
在上面的代码中,我们首先从 stock
模块导入 Stock
类。然后创建一个名为 s
的 Stock
类实例。要获取 name
属性的值,我们使用 s.name
。要更改 shares
属性的值,我们只需为 s.shares
赋一个新值。如果我们想删除一个属性,可以使用 del
关键字,后面跟上属性名。
Python 提供了四个非常有用的内置函数,用于属性操作。这些函数在处理属性时能让你拥有更多的控制权,特别是当你需要动态处理属性时。
getattr()
- 此函数用于获取属性的值。setattr()
- 它允许你设置属性的值。delattr()
- 你可以使用此函数删除属性。hasattr()
- 此函数用于检查对象中是否存在某个属性。让我们看看如何使用这些函数:
## Create a new Stock object
s = Stock('GOOG', 100, 490.1)
## Get an attribute
print(getattr(s, 'name')) ## Output: 'GOOG'
## Set an attribute
setattr(s, 'shares', 50)
print(s.shares) ## Output: 50
## Check if an attribute exists
print(hasattr(s, 'name')) ## Output: True
print(hasattr(s, 'symbol')) ## Output: False
## Delete an attribute
delattr(s, 'shares')
print(hasattr(s, 'shares')) ## Output: False
当你需要动态处理属性时,这些函数特别有用。你可以使用变量名,而不是硬编码的属性名。例如,如果你有一个变量存储了属性名,你可以将该变量传递给这些函数,以对相应的属性执行操作。这让你的代码更具灵活性,特别是在以更动态的方式处理不同的对象和属性时。
getattr()
进行通用对象处理getattr()
函数是 Python 中的一个强大工具,它允许你以动态方式访问对象的属性。当你想以通用方式处理对象时,这尤其有用。你可以使用 getattr()
处理任何具有所需属性的对象,而不是编写特定于某一对象类型的代码。这种灵活性使你的代码更具可复用性和适应性。
让我们先学习如何使用 getattr()
函数访问对象的多个属性。当你需要从对象中提取特定信息时,这是一种常见的场景。
首先,如果你关闭了之前的 Python 交互式 shell,请重新打开它。你可以在终端中运行以下命令来实现:
## Open a Python interactive shell if you closed the previous one
python3
接下来,我们将导入 Stock
类并创建一个 Stock
对象。Stock
类表示一支股票,具有 name
、shares
和 price
等属性。
## Import the Stock class and create a stock object
from stock import Stock
s = Stock('GOOG', 100, 490.1)
现在,我们将定义一个要访问的属性名列表。这个列表将帮助我们遍历这些属性并打印它们的值。
## Define a list of attribute names
fields = ['name', 'shares', 'price']
最后,我们将使用 for
循环遍历属性名列表,并使用 getattr()
访问每个属性。每次迭代时,我们将打印属性名及其值。
## Access each attribute using getattr()
for name in fields:
print(f"{name}: {getattr(s, 'name')}" if name == 'name' else f"{name}: {getattr(s, name)}")
运行这段代码时,你将看到以下输出:
name: GOOG
shares: 100
price: 490.1
这个输出表明,我们能够使用 getattr()
函数访问并打印 Stock
对象的多个属性的值。
getattr()
的默认值getattr()
函数还提供了一个有用的特性:当你尝试访问的属性不存在时,你可以指定一个默认值。这可以防止你的代码引发 AttributeError
,使代码更加健壮。
让我们看看这是如何工作的。首先,我们将尝试访问 Stock
对象中不存在的属性。我们将使用 getattr()
并提供一个默认值 'N/A'
。
## Try to access an attribute that doesn't exist
print(getattr(s, 'symbol', 'N/A')) ## Output: 'N/A'
在这种情况下,由于 Stock
对象中不存在 symbol
属性,getattr()
返回默认值 'N/A'
。
现在,让我们将其与访问现有属性进行比较。我们将访问 Stock
对象中确实存在的 name
属性。
## Compare with an existing attribute
print(getattr(s, 'name', 'N/A')) ## Output: 'GOOG'
在这里,getattr()
返回 name
属性的实际值,即 'GOOG'
。
当你需要处理对象集合时,getattr()
函数会变得更加强大。让我们看看如何使用它来处理股票投资组合。
首先,我们将从 stock
模块导入 read_portfolio
函数。这个函数从 CSV 文件中读取股票投资组合,并返回一个 Stock
对象列表。
## Import the portfolio reading function
from stock import read_portfolio
接下来,我们将使用 read_portfolio
函数从名为 portfolio.csv
的 CSV 文件中读取投资组合。
## Read the portfolio from CSV file
portfolio = read_portfolio('portfolio.csv')
最后,我们将使用 for
循环遍历投资组合中的 Stock
对象列表。对于每支股票,我们将使用 getattr()
访问 name
和 shares
属性并打印它们的值。
## Print the name and shares of each stock
for stock in portfolio:
print(f"Stock: {getattr(stock, 'name')}, Shares: {getattr(stock, 'shares')}")
这种方法使你的代码更具灵活性,因为你可以将属性名作为字符串处理。这些字符串可以作为参数传递或存储在数据结构中,这样你就可以轻松更改要访问的属性,而无需修改代码的核心逻辑。
在编程中,属性访问是一个基本概念,它允许我们与对象的属性进行交互。现在,我们将把所学的属性访问知识付诸实践。我们将创建一个实用工具:表格格式化器。这个格式化器会接收一组对象,并以表格形式显示它们,使数据更易于阅读和理解。
tableformat.py
模块首先,我们需要创建一个新的 Python 文件。这个文件将包含我们表格格式化器的代码。
要创建该文件,请按照以下步骤操作:
/home/labex/project/tableformat.py
。现在我们有了文件,让我们在 tableformat.py
中编写 print_table()
函数的代码。这个函数将负责以表格形式格式化并打印我们的对象。
def print_table(objects, fields):
"""
Print a collection of objects as a formatted table.
Args:
objects: A sequence of objects
fields: A list of attribute names
"""
## Print the header
headers = fields
for header in headers:
print(f"{header:>10}", end=' ')
print()
## Print the separator line
for header in headers:
print("-" * 10, end=' ')
print()
## Print the data
for obj in objects:
for field in fields:
value = getattr(obj, field)
print(f"{value:>10}", end=' ')
print()
让我们来详细分析这个函数的功能:
getattr()
函数来访问每个对象的属性值。现在,让我们测试一下 print_table()
函数,看看它是否按预期工作。
## Open a Python interactive shell
python3
## Import our modules
from stock import read_portfolio
import tableformat
## Read the portfolio data
portfolio = read_portfolio('portfolio.csv')
## Print the portfolio as a table with name, shares, and price columns
tableformat.print_table(portfolio, ['name', 'shares', 'price'])
当你运行上述代码时,你应该会看到以下输出:
name shares price
---------- ---------- ----------
AA 100 32.2
IBM 50 91.1
CAT 150 83.44
MSFT 200 51.23
GE 95 40.37
MSFT 50 65.1
IBM 100 70.44
我们的 print_table()
函数的一大优点是它的灵活性。我们只需更改 fields
列表,就可以更改显示的列。
## Just show shares and name
tableformat.print_table(portfolio, ['shares', 'name'])
运行这段代码将得到以下输出:
shares name
---------- ----------
100 AA
50 IBM
150 CAT
200 MSFT
95 GE
50 MSFT
100 IBM
这种方法的强大之处在于它的通用性。只要我们知道要显示的属性名称,就可以使用同一个 print_table()
函数为任何类型的对象打印表格。这使得我们的表格格式化器成为编程工具包中非常实用的工具。
在 Python 中,方法是一种特殊类型的属性,你可以调用它们。当你通过对象访问方法时,你得到的是所谓的“绑定方法”。绑定方法本质上是与特定对象绑定的方法。这意味着它可以访问对象的数据并对其进行操作。
让我们使用 Stock
类开始探索绑定方法。首先,我们将了解如何将方法作为对象的属性进行访问。
## Open a Python interactive shell
python3
## Import the Stock class and create a stock object
from stock import Stock
s = Stock('GOOG', 100, 490.10)
## Access the cost method without calling it
cost_method = s.cost
print(cost_method) ## Output: <bound method Stock.cost of <stock.Stock object at 0x...>>
## Call the method
result = cost_method()
print(result) ## Output: 49010.0
## You can also do this in one step
print(s.cost()) ## Output: 49010.0
在上面的代码中,我们首先导入 Stock
类并创建一个实例。然后,我们在不实际调用的情况下访问 s
对象的 cost
方法。这会得到一个绑定方法。当我们调用这个绑定方法时,它会根据对象的数据计算成本。你也可以一步直接在对象上调用该方法。
getattr()
访问方法另一种访问方法的方式是使用 getattr()
函数。这个函数允许你通过名称获取对象的属性。
## Get the cost method using getattr
cost_method = getattr(s, 'cost')
print(cost_method) ## Output: <bound method Stock.cost of <stock.Stock object at 0x...>>
## Call the method
result = cost_method()
print(result) ## Output: 49010.0
## Get and call in one step
result = getattr(s, 'cost')()
print(result) ## Output: 49010.0
在这里,我们使用 getattr()
从 s
对象获取 cost
方法。和之前一样,我们可以调用绑定方法来获取结果。你甚至可以在一行代码中完成获取和调用方法的操作。
绑定方法始终会保留对其所属对象的引用。这意味着即使你将方法存储在变量中,它仍然知道自己属于哪个对象,并可以访问该对象的数据。
## Store the cost method in a variable
c = s.cost
## Call the method
print(c()) ## Output: 49010.0
## Change the object's state
s.shares = 75
## Call the method again - it sees the updated state
print(c()) ## Output: 36757.5
在这个例子中,我们将 cost
方法存储在变量 c
中。当我们调用 c()
时,它会根据对象的当前数据计算成本。然后,我们更改 s
对象的 shares
属性。当我们再次调用 c()
时,它会使用更新后的数据计算新的成本。
绑定方法有两个重要的属性,它们能为我们提供更多关于该方法的信息。
__self__
:这个属性引用方法所绑定的对象。__func__
:这个属性是表示该方法的实际函数对象。## Get the cost method
c = s.cost
## Examine the bound method attributes
print(c.__self__) ## Output: <stock.Stock object at 0x...>
print(c.__func__) ## Output: <function Stock.cost at 0x...>
## You can manually call the function with the object
print(c.__func__(c.__self__)) ## Output: 36757.5 (same as c())
在这里,我们访问绑定方法 c
的 __self__
和 __func__
属性。我们可以看到,__self__
是 s
对象,而 __func__
是 cost
函数。我们甚至可以通过将对象作为参数传递来手动调用该函数,其结果与直接调用绑定方法相同。
让我们看看绑定方法如何与带参数的方法(如 sell()
方法)一起工作。
## Get the sell method
sell_method = s.sell
## Examine the method
print(sell_method) ## Output: <bound method Stock.sell of <stock.Stock object at 0x...>>
## Call the method with an argument
sell_method(25)
print(s.shares) ## Output: 50
## Call the method manually using __func__ and __self__
sell_method.__func__(sell_method.__self__, 10)
print(s.shares) ## Output: 40
在这个例子中,我们将 sell
方法作为绑定方法获取。当我们使用参数调用它时,它会更新 s
对象的 shares
属性。我们也可以使用 __func__
和 __self__
属性手动调用该方法,并传递参数。
理解绑定方法有助于你深入了解 Python 对象系统的工作原理,这对于调试、元编程和创建高级编程模式非常有用。
在本次实验中,你学习了 Python 的属性访问系统及其底层机制。你现在知道如何使用点号表示法以及 getattr()
、setattr()
、delattr()
和 hasattr()
等函数来访问对象属性。此外,你还了解了如何使用 getattr()
进行通用且灵活的对象处理,以及如何为任意对象集合创建表格格式化器。
你还掌握了绑定方法的概念,以及它们如何与所属对象保持关联。这些基础概念对于高级 Python 编程技术(如内省、反射和元编程)至关重要。理解属性访问能让你编写更灵活、更强大的代码,以处理各种类型的对象。