简体   繁体   English

从内置类型派生时如何设置“the”值?

[英]how do you set "the" value when deriving from built-in type?

I'm (trying) to do some meta programming and things seem to be working until I try to do a set.我正在(尝试)做一些元编程,在我尝试做一组之前,事情似乎一直在工作。

class MetaField(type):

    def __new__(meta, clsname, bases, attrs):
        bases = (Field,) + bases
        return super(MetaField, meta).__new__(meta, clsname, bases, attrs)

    def __call__(cls, *args, **kw):
        cls._primary_key = kw.pop('primary_key', False)
        return super(MetaField, cls).__call__(*args, **kw)

class Field(object):

    def __new__(cls, *args, **kw):
        return super(Field, cls).__new__(cls, *args)

    #def __set__(self, instance, value):
    #    magic needs to go here

    #def __get__(self, instance, owner):
    #    more magic here

    @property
    def primary_key(self):
        return self._primary_key

class IntField(int):
    __metaclass__ = MetaField

class SomeObject(object):
    # trying with descriptors here
    i = IntField(10, primary_key=True, foo='set')


obj = SomeObject()
assert obj.i == 10
assert obj.i.primary_key == True

obj.i = 11
assert obj.i == 11

assert obj.i.primary_key == True
AttributeError: 'int' object has no attribute 'primary_key'

Which makes sense since obj.i is no longer a IntField but a plain int .这是有道理的,因为obj.i不再是一个IntField而是一个普通的int

So in Field.__set__ if I could do something along the lines of super(self) = value but have self still be a IntField that'd be super duper.因此,在Field.__set__如果我可以按照super(self) = value做一些事情,但让self仍然是一个IntField ,那将是超级IntField

I've tried to implement a ProxyFieldDescriptor as described at http://blog.kevinastone.com/django-model-descriptors.html but when you return from __get__ you loose all your supplementary info like _primary_key .我试图实现一个ProxyFieldDescriptor ,如http://blog.kevinastone.com/django-model-descriptors.html所述,但是当您从__get__返回时,您会丢失所有补充信息,例如_primary_key

How do you set the actual value of int from within a derived class?如何从派生类中设置int的实际值?

First and foremost, you should probably burn in developer hell if you ever do this on production code.首先,如果你曾经在生产代码上这样做,你可能应该在开发人员地狱中燃烧。 Secondly, here's what you're trying to do:其次,这是你想要做的:

class MetaField(type):
    def __new__(meta, clsname, bases, attrs):
        bases = (Field,) + bases
        return super(MetaField, meta).__new__(meta, clsname, bases, attrs)

    def __call__(cls, *args, **kw):
        cls._primary_key = kw.pop('primary_key', False)
        cls._name = kw.pop('name')
        return super(MetaField, cls).__call__(*args, **kw)


class Field(object):

    def __getattr__(self, item):
        if item == 'primary_key':
            return self._primary_key
        else:
            return self.__dict__[item]

    def __set__(self, instance, value):
        instance.__dict__[self._name] = IntField(value, primary_key=self.primary_key, name=self._name)


class IntField(int):
    __metaclass__ = MetaField


class SomeObject(object):
    # trying with descriptors here
    i = IntField(10, primary_key=True, name='i')


if __name__ == '__main__':
    obj = SomeObject()
    assert obj.i == 10
    assert obj.i.primary_key == True

    obj.i = 11
    assert obj.i == 11

    assert obj.i.primary_key == True
# g2g

The key here is, as is often the case with descriptors, you need to name them.这里的关键是,就像描述符的情况一样,您需要为它们命名。 If you don't name them, there's no way to access the instance variable in the event you need to set/get with it.如果您不命名它们,则在需要设置/获取实例变量时无法访问实例变量。 If that's not an issue, you don't need a name.如果这不是问题,则不需要名称。 But in this case you do.但在这种情况下,你会这样做。 I made the necessary adjustments.我做了必要的调整。

Although I'm sure you're well aware of this there are way easier ways to do what you're trying to accomplish... this is the path of the dark side.虽然我相信你很清楚这一点,但有更简单的方法来完成你想要完成的事情……这是黑暗面的道路。

This is a job for the __init__ method.这是__init__方法的工作。 It acts as a constructor and is called when your class is instantiated as an object.它充当构造函数,并在您的类实例化为对象时调用。

  class A:
    def __init__(self, x, y):
      self.x = x
      self.y = y

  a = A(5, 6)
  assert a.x == 5 and a.y == 6

The way you were defining things, those were class attributes and were not associated with particular instances.您定义事物的方式是类属性,与特定实例无关。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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