Python 什么是「;元类;如何做到这一点?

Python 什么是「;元类;如何做到这一点?,python,metaclass,Python,Metaclass,我想写一个程序,它接受一个数字p作为输入,并为一个服从整数算术模p的数字生成一个类型构造函数作为输出 到目前为止我有 def IntegersModP(p): N = type('IntegersMod%d' % p, (), {}) def __init__(self, x): self.val = x % p def __add__(a, b): return N(a.val + b.val) ... (more functions) ... att

我想写一个程序,它接受一个数字p作为输入,并为一个服从整数算术模p的数字生成一个类型构造函数作为输出

到目前为止我有

def IntegersModP(p):
   N = type('IntegersMod%d' % p, (), {})

   def __init__(self, x): self.val = x % p
   def __add__(a, b): return N(a.val + b.val)
   ... (more functions) ...    

   attrs = {'__init__': __init__, '__add__': __add__, ... }

   for name, f in attrs.items():
      setattr(N, name, f)

   return N
这很好,但我想知道python的方法是什么,我知道它会使用元类。

像这样:

def IntegerModP(p):  # class factory function
    class IntegerModP(object):
        def __init__(self, x):
            self.val = x % p
        def __add__(a, b):
            return IntegerModP(a.val + b.val)
        def __str__(self):
            return str(self.val)
        def __repr__(self):
            return '{}({})'.format(self.__class__.__name__, self.val)

    IntegerModP.__name__ = 'IntegerMod%s' % p  # rename created class
    return IntegerModP

IntegerMod4 = IntegerModP(4)
i = IntegerMod4(3)
j = IntegerMod4(2)
print i + j        # 1
print repr(i + j)  # IntegerMod4(1)

元类适用于您的类需要与普通类不同的行为,或者您想要更改
语句的行为时。这两种方法都不适用于这里,因此实际上没有必要使用元类。事实上,您可以只使用一个带有实例的
ModularInteger
类来记录它们的值和模数,但假设您不想这样做,那么使用普通的class语句仍然很容易做到这一点:

def integers_mod_p(p):
    class IntegerModP(object):
        def __init__(self, n):
            self.n = n % IntegerModP.p
        def typecheck(self, other):
            try:
                if self.p != other.p:
                    raise TypeError
            except AttributeError:
                raise TypeError
        def __add__(self, other):
            self.typecheck(other)
            return IntegerModP(self.n + other.n)
        def __sub__(self, other):
            ...
    IntegerModP.p = p
    IntegerModP.__name__ = 'IntegerMod{}'.format(p)
    return IntegerModP

我不确定您为什么要在这里使用元类,您可以使用一个简单的class语句并将
p
传递到
\uuuuuu init\uuuuu
@AshwiniChaudhary。这是不可接受的,因为您不能添加具有不同模块的两个实例。(您将使用哪个模数?@JeremyKun您可以将模数存储在实例本身中,然后在实际对两个实例执行操作之前检查它们的模数。@AshwiniChaudhary这是一个非常不雅观的解决方案。@JeremyKun:您的答案根本不检查模数。添加两个具有不同模块的数字会产生无意义的结果。您可能希望将
p
存储在类中,而不是作为闭包变量,以便于内省,并添加一些类型检查,以便在不同模块中使用数字进行数学运算时不会只给出错误的结果。@user2357112:我只是概述了一个“Pythonic”为OP构造这样一个类的方法并没有实现问题中定义得很模糊的东西——此外,类的最终名称应该足以用于内省。@AshwiniChaudhary:的确如此。我本来打算让它用一个更复杂的
类型检查来处理这个问题,但是我分心了,忘记了。我认为我对这个问题不太满意,因为我希望尽可能避免错误(最终我计划使这个类更通用,所以我想在可能的情况下进行一些无声类型转换)。但我想你已经告诉我,我只需要更加认真地思考我想如何组织事情,这是对我前面提到的问题的一个很好的回答。