Метаклассы и методы

Добавление метода в метакласс отлично работает в следующем примере.

class Test(object):

    def __init__(self, x):
        self.x = x

    def double(self):
        return self.x*2

# method to add
def quadruple(self):
    return self.x*4

# creating metaclass
TypeTest = type('TypeTest', (Test,), {'triple': triple, 
                                      'quadruple': quadruple})

# prints 8
TypeTest(2).quadruple()

Приведенный ниже пример не работает, и я понятия не имею, почему. Он просто не распознает себя в разобранной функции, и возникает ошибка TypeError.

class Vehicle(object):
    def __init__(self, wheels, door=False):
        self.wheels = wheels
        self.door = door

# method to add
def check_load(self, x):
    if x > self.load:
        return "Load won't fit"
    else:
        return "Load will fit"

# creating metaclass
Truck = type('Truck', (Vehicle,), dict(wheels=4,door=True, load=100,
                                       check_load=check_load))

# TypeError: check_load() missing 1 required positional argument: 'x'
Truck.check_load(10)

1 ответ

Решение

Прежде всего: вы не создаете метакласс, вы создаете обычные классы. type() является (базовым) метаклассом здесь, вызов его создает новый объект класса (тот же тип объекта, что class заявление производит).

Первый type() вызов по сути эквивалентен:

class TypeTest(Test)
    triple = triple
    quadruple = quadruple

и второй пример такой же как:

class Truck(Vehicle)
    wheels = 4
    door = True
    load = 100
    check_load = check_load

Вы забыли создать экземпляр вашего Truck учебный класс:

Truck.check_load(10)

Это оставляет check_load() функция, с которой нечего связать, нет self,

В первом примере вы создали экземпляр:

TypeTest(2).quadruple()

Обратите внимание на звонок, проходящий в 2,

Создать экземпляр для self быть привязанным к:

Truck(4, True).check_load(10)

Если вы хотите, чтобы ваш класс не нуждался в аргументах для создания экземпляра, вам нужно предоставить другой __init__ метод тоже тот, который переопределяет Vehicle.__init__ метод:

def init(self): pass

Truck = type('Truck', (Vehicle,), dict(
    wheels=4,door=True, load=100,
    check_load=check_load, __init__=init))

Теперь вы можете создать экземпляр без аргументов:

Truck().check_load(10)
Другие вопросы по тегам