Доступ к атрибутам и связанные методы

PythonPythonBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом практическом занятии (лабораторной работе) вы узнаете о доступе к атрибутам в Python. Вы изучите, как использовать такие функции, как getattr() и setattr(), для эффективной манипуляции атрибутами объектов.

Кроме того, вы будете экспериментировать с связанными методами. В рамках практического занятия (лабораторной работы) вы пройдете через эти концепции, и в процессе вы создадите файл с именем tableformat.py.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ModulesandPackagesGroup(["Modules and Packages"]) python(("Python")) -.-> python/ObjectOrientedProgrammingGroup(["Object-Oriented Programming"]) python(("Python")) -.-> python/PythonStandardLibraryGroup(["Python Standard Library"]) python/FunctionsGroup -.-> python/function_definition("Function Definition") python/FunctionsGroup -.-> python/build_in_functions("Build-in Functions") python/ModulesandPackagesGroup -.-> python/using_packages("Using Packages") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("Classes and Objects") python/PythonStandardLibraryGroup -.-> python/data_collections("Data Collections") subgraph Lab Skills python/function_definition -.-> lab-132491{{"Доступ к атрибутам и связанные методы"}} python/build_in_functions -.-> lab-132491{{"Доступ к атрибутам и связанные методы"}} python/using_packages -.-> lab-132491{{"Доступ к атрибутам и связанные методы"}} python/classes_objects -.-> lab-132491{{"Доступ к атрибутам и связанные методы"}} python/data_collections -.-> lab-132491{{"Доступ к атрибутам и связанные методы"}} end

Понимание доступа к атрибутам в Python

В Python объекты являются фундаментальным концептом. Они могут хранить данные в атрибутах, которые можно рассматривать как именованные контейнеры для значений. Атрибуты можно представить себе как переменные, принадлежащие объекту. Существует несколько способов доступа к этим атрибутам. Самым простым и часто используемым методом является точковая (.) нотация. Однако Python также предоставляет специальные функции, которые дают больше гибкости при работе с атрибутами.

Точковая нотация

Начнем с создания объекта Stock и посмотрим, как можно манипулировать его атрибутами с помощью точковой нотации. Точковая нотация представляет собой простой и интуитивно понятный способ доступа и изменения атрибутов объекта.

Сначала откройте новый терминал и запустите интерактивную оболочку Python. Именно здесь вы можете по одной строке писать и выполнять код на 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. Затем создаем экземпляр класса Stock с именем s. Чтобы получить значение атрибута name, используем s.name. Чтобы изменить значение атрибута shares, просто присваиваем ему новое значение s.shares. А если нужно удалить атрибут, используем ключевое слово del, за которым следует имя атрибута.

Функции доступа к атрибутам

Python предоставляет четыре встроенные функции, которые очень полезны для манипуляции атрибутами. Эти функции дают больше контроля при работе с атрибутами, особенно когда необходимо обрабатывать их динамически.

  1. getattr() - Эта функция используется для получения значения атрибута.
  2. setattr() - Позволяет установить значение атрибута.
  3. delattr() - Можно использовать эту функцию для удаления атрибута.
  4. 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, если вы закрыли предыдущую. Вы можете сделать это, запустив следующую команду в терминале:

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

Этот вывод показывает, что мы смогли получить доступ и вывести значения нескольких атрибутов объекта Stock с помощью функции getattr().

Значения по умолчанию с 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'

В этом случае, так как атрибут symbol не существует в объекте Stock, функция getattr() возвращает значение по умолчанию 'N/A'.

Теперь сравним это с получением доступа к существующему атрибуту. Мы получим доступ к атрибуту name, который существует в объекте Stock.

## Compare with an existing attribute
print(getattr(s, 'name', 'N/A'))    ## Output: 'GOOG'

Здесь функция getattr() возвращает фактическое значение атрибута name, которое равно 'GOOG'.

Обработка коллекции объектов

Функция getattr() становится еще более мощной, когда вам нужно обработать коллекцию объектов. Посмотрим, как можно использовать ее для обработки портфеля акций.

Сначала импортируем функцию read_portfolio из модуля stock. Эта функция считывает портфель акций из CSV-файла и возвращает список объектов Stock.

## Import the portfolio reading function
from stock import read_portfolio

Затем используем функцию read_portfolio для чтения портфеля из CSV-файла с именем portfolio.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. Этот файл будет содержать код нашего форматировщика таблиц.

Для создания файла следуйте этим шагам:

  1. В WebIDE нажмите на меню "File".
  2. Из выпадающего списка выберите "New File".
  3. Сохраните только что созданный файл как tableformat.py в директории /home/labex/project/.

Теперь, когда у нас есть файл, напишем код для функции print_table() внутри tableformat.py. Эта функция будет отвечать за форматирование и вывод наших объектов в виде таблицы.

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

Разберем, что делает эта функция:

  1. Она принимает два аргумента: последовательность объектов и список имен атрибутов. Последовательность объектов - это данные, которые мы хотим отобразить, а список имен атрибутов сообщает функции, какие свойства объектов нужно показать.
  2. Она выводит строку заголовка. Строка заголовка содержит имена атрибутов, которые нас интересуют.
  3. Она выводит разделительную строку. Эта строка помогает визуально отделить заголовок от данных.
  4. Для каждого объекта в последовательности она выводит значение каждого указанного атрибута. Она использует функцию 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

В 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 и создаем его экземпляр. Затем мы обращаемся к методу cost объекта s, не вызывая его. Это дает нам связанный метод. Когда мы вызываем этот связанный метод, он вычисляет стоимость на основе данных объекта. Вы также можете напрямую вызвать метод у объекта за один шаг.

Использование 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() для получения метода cost из объекта s. Как и раньше, мы можем вызвать связанный метод, чтобы получить результат. И вы даже можете получить и вызвать метод в одной строке.

Связанный метод и его объект

Связанный метод всегда хранит ссылку на объект, из которого он был получен. Это означает, что даже если вы сохраняете метод в переменной, он все еще знает, к какому объекту он принадлежит, и может получить доступ к данным этого объекта.

## 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(), он вычисляет стоимость на основе текущих данных объекта. Затем мы изменяем атрибут shares объекта s. Когда мы вызываем 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())

Здесь мы обращаемся к атрибутам __self__ и __func__ связанного метода c. Мы видим, что __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 как связанный метод. Когда мы вызываем его с аргументом, он обновляет атрибут shares объекта s. Мы также можем вручную вызвать метод, используя атрибуты __func__ и __self__, передав также аргумент.

Понимание связанных методов помогает понять, как работает объектная система Python "под капотом", что может быть полезно для отладки, метапрограммирования и создания сложных программистских шаблонов.

Резюме

В этом практическом занятии вы изучили систему доступа к атрибутам в Python и ее внутренние механизмы. Теперь вы знаете, как обращаться к атрибутам объектов с помощью точечной нотации и функций, таких как getattr(), setattr(), delattr() и hasattr(). Кроме того, вы понимаете, как использовать getattr() для универсальной и гибкой обработки объектов и как создать форматировщик таблиц для любой коллекции объектов.

Вы также поняли концепцию связанных методов и то, как они сохраняют связь с своими объектами. Эти фундаментальные концепции являются важными для продвинутых методов программирования на Python, таких как интроспекция, рефлексия и метапрограммирование. Понимание доступа к атрибутам позволяет вам писать более гибкий и мощный код, способный обрабатывать различные типы объектов.