def test_errors(self):
        class MyMeta(type):
            pass

        with self.assertRaises(TypeError):
            class MyClass(metaclass=MyMeta, otherarg=1):
                pass

        with self.assertRaises(TypeError):
            types.new_class("MyClass", (object,),
                            dict(metaclass=MyMeta, otherarg=1))
        types.prepare_class("MyClass", (object,),
                            dict(metaclass=MyMeta, otherarg=1))

        class MyMeta(type):
            def __init__(self, name, bases, namespace, otherarg):
                super().__init__(name, bases, namespace)

        with self.assertRaises(TypeError):
            class MyClass(metaclass=MyMeta, otherarg=1):
                pass

        class MyMeta(type):
            def __new__(cls, name, bases, namespace, otherarg):
                return super().__new__(cls, name, bases, namespace)

            def __init__(self, name, bases, namespace, otherarg):
                super().__init__(name, bases, namespace)
                self.otherarg = otherarg

        class MyClass(metaclass=MyMeta, otherarg=1):
            pass

        self.assertEqual(MyClass.otherarg, 1)
Exemple #2
0
def create_class(
    name: str,
    bases: Iterable = (),
    attrs: dict = {},
    metaclass: Optional[Callable[..., Type[T]]] = None,
    **kwargs: Any
) -> Type[T]:
    """
    Creates a new class. This is similar to :func:`types.new_class`, except it
    calls :func:`resolve_bases` even in python versions <= 3.7. (And it has a
    different interface.)

    :param name: The name of the new class
    :param bases: An iterable of bases classes
    :param attrs: A dict of class attributes
    :param metaclass: The metaclass, or ``None``
    :param kwargs: Keyword arguments to pass to the metaclass
    :return: A new class
    """
    if metaclass is not None:
        kwargs.setdefault('metaclass', metaclass)

    resolved_bases = resolve_bases(bases)
    meta, ns, kwds = types.prepare_class(name, resolved_bases, kwargs)

    ns.update(attrs)

    # Note: In types.new_class this is "is not" rather than "!="
    if resolved_bases != bases:
        ns['__orig_bases__'] = bases

    return meta(name, resolved_bases, ns, **kwds)
Exemple #3
0
    def new_class(name, bases=(), kwds=None, exec_body=None):
        """Create a class object dynamically using the appropriate metaclass.

        """
        import sys
        meta, ns, kwds = prepare_class(name, bases, kwds)
        if exec_body is not None:
            exec_body(ns)
        if sys.version_info >= (3, 0):
            return meta(name, bases, ns, **kwds)
        else:
            return meta(name, bases, ns)
Exemple #4
0
    def test_prepare_class(self):
        # Basic test of metaclass derivation
        expected_ns = {}
        class A(type):
            def __new__(*args, **kwargs):
                return type.__new__(*args, **kwargs)

            def __prepare__(*args):
                return expected_ns

        B = types.new_class("B", (object,))
        C = types.new_class("C", (object,), {"metaclass": A})

        # The most derived metaclass of D is A rather than type.
        meta, ns, kwds = types.prepare_class("D", (B, C), {"metaclass": type})
        self.assertIs(meta, A)
        self.assertIs(ns, expected_ns)
        self.assertEqual(len(kwds), 0)
Exemple #5
0
    def test_prepare_class(self):
        # Basic test of metaclass derivation
        expected_ns = {}
        class A(type):
            def __new__(*args, **kwargs):
                return type.__new__(*args, **kwargs)

            def __prepare__(*args):
                return expected_ns

        B = types.new_class("B", (object,))
        C = types.new_class("C", (object,), {"metaclass": A})

        # The most derived metaclass of D is A rather than type.
        meta, ns, kwds = types.prepare_class("D", (B, C), {"metaclass": type})
        self.assertIs(meta, A)
        self.assertIs(ns, expected_ns)
        self.assertEqual(len(kwds), 0)
def prepare_class():
    # Basic test of metaclass derivation
    expected_ns = {}

    class A(type):
        def __new__(*args, **kwargs):
            return type.__new__(*args, **kwargs)

        def __prepare__(*args):
            return expected_ns

    B = types.new_class("B", (object, ))
    C = types.new_class("C", (object, ), {"metaclass": A})

    meta, ns, kwds = types.prepare_class("D", (B, C), {"metaclass": type})
    print(meta is A)
    print(ns is expected_ns)
    print(len(kwds) == 0)
Stock.__module__ = __name__
print(type(Stock))  # <class 'abc.ABCMeta'>

Stock = collections.namedtuple('Stock', ['name', 'shares', 'price'])
print(Stock)  # <class '__main__.Stock'>


def named_tuple(classname, fieldnames):
    # Populate a dictionary of field property accessors
    cls_dict = {
        name: property(operator.itemgetter(n))
        for n, name in enumerate(fieldnames)
    }

    # Make a __new__ function and add to the class dict
    def __new__(cls, *args):
        if len(args) != len(fieldnames):
            raise TypeError('Expected {} arguments'.format(len(fieldnames)))
        return tuple.__new__(cls, args)

    cls_dict['__new__'] = __new__
    # Make the class
    cls = types.new_class(classname, (tuple, ), {},
                          lambda ns: ns.update(cls_dict))
    # Set the module to that of the caller
    cls.__module__ = sys._getframe(1).f_globals['__name__']
    return cls


metaclass, kwargs, ns = types.prepare_class('Stock', (), {'metaclass': type})
Exemple #8
0
 def update_event(self, inp=-1):
     self.set_output_val(
         0, types.prepare_class(self.input(0), self.input(1),
                                self.input(2)))
Exemple #9
0
print(p.x)
# 4
print(p.y)
# 5
# p.x = 2
# AttributeError: can't set attribute

print('%s %s' % p)
# 4 5

"""
这项技术一个很重要的方面是它对于元类的正确使用。你可能像通过直接实例化一
个元类来直接创建一个类:

Stock = type('Stock', (), cls_dict)
这种方法的问题在于它忽略了一些关键步骤,比如对于元类中 prepare () 方法
的调用。通过使用 types.new class() ,你可以保证所有的必要初始化步骤都能得到
执行。比如,types.new class() 第四个参数的回调函数接受 prepare () 方法返回
的映射对象。

如果你仅仅只是想执行准备步骤,可以使用 types.prepare class() 。例如:
"""
import types
metaclass, kwargs, ns = types.prepare_class('Stock', (), {'metaclass':type})

"""
它会查找合适的元类并调用它的 prepare () 方法。然后这个元类保存它的关键
字参数,准备命名空间后被返回。
"""

    def __new__(cls, *args):
        if len(args) != len(field_names):
            raise TypeError(f'Expected {len(field_names)} arguments')
        return tuple.__new__(cls, args)

    cls_dict['__new__'] = __new__

    # Make the class
    cls = types.new_class(class_name, (tuple, ), {},
                          lambda ns: ns.update(cls_dict))

    # Set the module to that of the caller
    cls.__module__ = sys._getframe(1).f_globals['__name__']
    return cls


Point = named_tuple('Point', ['x', 'y'])
print(f'point object: {Point}')
p = Point(5, 8)
print(f'p length = {len(p)}')
print(f'p.x = {p.x}')
print(f'p.y = {p.y}')
# p.x = 3
print(f'p is: {p}')

Course = type('Course', (), cls_dict)

import types

metaclass, kwargs, ns = types.prepare_class('Course', (), {'metaclass': type})