Можно ли деконструировать self при использовании методов класса в Python? - PullRequest
3 голосов
/ 10 июля 2020

Я хочу очистить свой код, чтобы он использовал меньше self.attribute экземпляров и его было легче читать.

Пример стандартной функциональности:

class Car:
    brand = None
    color = None
    model = None

    def __init__(self, color, brand, model):
        self.brand = brand
        self.color = color
        self.model = model
    
    def print_car(self):
        print(f"This is a {self.color} {self.brand} manufactured in {self.model}"
car_a = Car(color='red', brand='audi', model=2001)
car_a.print_car()
# output: This is a red audi manufactured in 2001

Как бы я хотел бы изменить его:

Я хотел бы деконструировать аргумент self на print_car, чтобы он был немного чище, но достиг той же функциональности. что-то вроде этого:

def print_car({color, brand, model}):
    print(f"This is a {color} {brand} manufactured in {model}"

Это возможно? Обычный? В основном это просто более чистый код, но, может быть, это не лучший подход?

1 Ответ

3 голосов
/ 10 июля 2020

Вы можете использовать встроенную функцию vars, чтобы получить атрибуты большинства экземпляров в виде словаря. Это позволяет вызывать вызываемые объекты с атрибутами, например, используя ** -unpacking, чтобы использовать их в качестве аргументов ключевого слова:

class Car:
    def __init__(self, color=None, brand=None, model=None):
        self.brand = brand
        self.color = color
        self.model = model

    def print_car(self):
        print(
           "This is a {color} {brand} manufactured in {model}".format(
               **vars(self)  # get and unpack attributes to keyword arguments
        ))

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

Однако классы, предназначенные исключительно для хранения определенного c набора атрибутов, могут быть безопасно разрушить. Например, классы данных напрямую поддерживают преобразование экземпляров в сопоставления и последовательности . Это позволяет деструктурировать атрибуты по имени или порядку.

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

def destruct(method):
    """Mark a method to destructure ``self`` into its arguments"""
    @wraps(method)
    def wrapper(self, **kwargs):
        return method(**vars(self), **kwargs)
    return wrapper

Его можно применять, как и другие декораторы методов, например classmethod, непосредственно в определении class. Затем метод принимает каждый атрибут в качестве отдельного аргумента вместо одного аргумента self.

class Car:
    def __init__(self, color=None, brand=None, model=None):
        self.brand = brand
        self.color = color
        self.model = model

    @destruct
    def print_car(color, brand, model):
        print(f"This is a {color} {brand} manufactured in {model}")


Car(color='red', brand='audi', model=2001).print_car()
# This is a red audi manufactured in 2001

Обратите внимание, что destruct является демонстратором. Например, vars не работает для классов, использующих __slots__ - при необходимости можно использовать некоторые запасные варианты или при проверке класса '__annotations__. Кроме того, метод больше не поддерживает позиционные аргументы - проверка подписи или иная нормализация аргументов позволят это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...