Цель использования передачи аргумента как *fruit_bowl в документации Pytest [дубликат]

avatar
Jonathan Bechtel
8 августа 2021 в 17:52
22
1
-1

Я просматриваю документацию по pytest и обнаружил небольшую деталь, которая сводит меня с ума.

Сейчас я просматриваю документацию по этой странице и вижу следующий пример:

import pytest


class Fruit:
    def __init__(self, name):
        self.name = name
        self.cubed = False

    def cube(self):
        self.cubed = True


class FruitSalad:
    def __init__(self, *fruit_bowl):
        self.fruit = fruit_bowl
        self._cube_fruit()

    def _cube_fruit(self):
        for fruit in self.fruit:
            fruit.cube()


# Arrange
@pytest.fixture
def fruit_bowl():
    return [Fruit("apple"), Fruit("banana")]


def test_fruit_salad(fruit_bowl):
    # Act
    fruit_salad = FruitSalad(*fruit_bowl)

    # Assert
    assert all(fruit.cubed for fruit in fruit_salad.fruit)

Я получил общее представление о том, что происходит на этой странице, но включение * в аргумент fruit_bowl меня сбивает с толку.

Например, если вы просто хотите инициализировать классы сами по себе, код не будет работать:

fruit_bowl = [Fruit("Apple"), Fruit("Banana")]
fruit_salad = FruitSalad(fruit_bowl)

возвращает сообщение об ошибке:

AttributeError: 'list' object has no attribute 'cube'

В этом случае замена аргумента *fruit_bowl на fruit_bowl работает нормально.

Затем я понял, что fruit_bowl был определен как функция, поэтому я подумал, что это сработает, но снова простой запуск кода вне теста вернул ошибку.

Если я настрою код следующим образом:

def fruit_bowl():
    return [Fruit("Apple"), Fruit("Banana")]

class Fruit():
    def __init__(self, name):
        self.name = name
        self.cubed = False
        
    def cube(self):
        self.cubed = True

class FruitSalad():
    
    def __init__(self, *fruit_bowl):
        self.fruit_bowl = fruit_bowl
        self._cube_fruit()
        
    def _cube_fruit(self):
        for fruit in self.fruit_bowl:
            fruit.cube()

Затем запуск fruit_salad = FruitSalad(fruit_bowl) выдает сообщение об ошибке AttributeError: 'function' object has no attribute 'cube'.

Означает ли это, что использование аргумента *fruit_bowl зависит от того, как работает pytest? Т.е. эти вещи будут работать, только если аргументом является функция с добавленным декоратором @fixture, или есть еще какой-то момент, который я упустил.

На данный момент я нахожу приведенный код запутанным, потому что код, отличный от pytest, не работает как есть, поэтому я изо всех сил пытаюсь понять, как реализовать использование фикстур в моей собственной работе.

Источник
Carcigenicate
8 августа 2021 в 17:55
1

fruit_bowl функция затенена аргументом fruit_bowl. А * известен как "распаковка последовательности". Он превращает последовательность, которая должна быть передана как один аргумент, в каждый из ее элементов, передаваемых как отдельный аргумент.

Ответы (1)

avatar
AKX
8 августа 2021 в 17:56
1

Нет, распаковка аргумента * вообще не является неотъемлемой частью Pytest. Я бы назвал аргумент FruitSalad fruits, избавившись от *s. (как при объявлении, так и при вызове) и аннотируйте его List[Fruit], чтобы сделать его кристально ясным.