human
I am working on the file "015 - Breaking Benjamin/meta_alltheway/meta_alltheway.ipynb".
The first task is:
Creating classes dynamically

Remember the function type? The good old function that lets you know what type an object is.
type can also create classes on the fly. type can take the description of a class as parameters, and return a class as type(name, bases, attrs).
name is a string giving the name of the class to be constructed.
bases is a tuple giving the parent classes of the class to be constructed.
attrs is a dictionary of the attributes and methods of the class to be constructed.


For example:
python
class Foo:
    bar = True
is equivalent with:
python
Foo = type('Foo', (), {'bar':True})
What are metaclasses

Metaclasses are the "stuff" that creates classes. You define classes in order to create objects, right?
We learned that Python classes are objects.
Well, metaclasses are what creates these objects. They are the classes' classes, you can picture them this way:

MyClass = MetaClass(), MyObject = MyClass()
<img src="figures/oo_relationships_revisited.png" style="display:block;margin:auto;width:80%;"/>
What can act as a metaclass?

Something that can create a class, i.e. anything that subclasses or uses type.
Any python callable. A callable is an object that can be invoked with the function operator ().
Any Python class. MyClass() calls the __init__() function of the class
Any Python function or instance whose class implements __call__(). foo() is equivalent to foo.__call__(). This is true in both cases (i.e. all functions objects implement __call__).

i.e. a metaclass is something that we call with some parameters and returns a class object

When you write:
python
class A:
    ...
you are actually not creating the class, you describe the class and type creates this class object for you.

Each class can have one metaclass, however this metaclass can subclass multiple metaclasses.

Our example with a function as metaclass
Can you write Python program for it?

=====
Here are metaclasses?
assistant
#Here are metaclasses
.

import re

def convert(name):
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

# the metaclass will automatically get passed the same arguments that we pass to `type`
def camel_to_snake_case(name, bases, attrs):
    """Return a class object, with its attributes from camelCase to snake_case."""
    print("Calling the metaclass camel_to_snake_case to construct class: {}".format(name))
    
    # pick up any attribute that doesn't start with '__' and snakecase it
    snake_attrs = {}
    for attr_name, attr_val in attrs.items():
        if not name.startswith('__'):
            snake_attrs[convert(attr_name)] = attr_val
        else:
            snake_attrs[attr_name] = attr_val
    return type(name, bases, snake_attrs) # let `type` do the class creation

class MyVector(metaclass=camel_to_snake_case):
    def addToVector(self, other): pass
    def subtractFromVector(self, other): pass
    def calculateDotProduct(self, other): pass
    def calculateCrossProduct(self, other): pass
    def calculateTripleProduct(self, other): pass

print([a for a in dir(MyVector) if not a.startswith('__')])