简体   繁体   中英

Metaclasses and methods

Adding a method to metaclass works perfectly in the below example.

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

The below example doesn't work and I have no idea why. It simply doesn't recognise self in the parsed function and a TypeError occurs.

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)

First of all: You are not creating a metaclass, you are creating regular classes. type() is the (base) metaclass here, calling it creates a new class object (the same type of object that a class statement produces).

The first type() call is essentially equivalent to:

class TypeTest(Test)
    triple = triple
    quadruple = quadruple

and the second example is the same as:

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

You forgot to create an instance of your Truck class:

Truck.check_load(10)

This leaves the check_load() function with nothing to bind to, there is no self .

In your first example you did create an instance:

TypeTest(2).quadruple()

Notice the call, passing in 2 .

Create an instance for self to be bound to:

Truck(4, True).check_load(10)

If you wanted your class to not need arguments to create an instance, you'll need to provide a different __init__ method too, one that overrides the Vehicle.__init__ method:

def init(self): pass

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

Now you can create the instance without arguments:

Truck().check_load(10)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM