提取分配的变量名称

发布于 2024-12-05 22:55:46 字数 1730 浏览 8 评论 0原文

请参阅下面的更新

我什至不知道如何为我的问题制作一个简短的标题。

在一个类中,我有 StringField 类的一些类属性:

class Authors(Table):
    # id field is already present 
    first_name = StringField(maxLength=100)
    last_name = StringField(maxLength=100)

StringField 构造函数可能会接收一个名为 name 的参数。如果没有给出,我希望它等于类属性的名称(上面示例中的first_namelast_name)。

是否可以提取创建的实例将分配给的变量的名称? 我想我必须使用 inspect 模块?

我看到 Django 是这样做的:

每种字段类型,除了ForeignKey、ManyToManyField 和 OneToOneField,采用可选的第一个位置参数 - a 详细的名称。如果没有给出详细名称,Django 将 使用字段的属性名称自动创建它,转换 下划线改为空格。

在此示例中,详细名称是“人的名字”:

first_name = models.CharField("人的名字", max_length=30)

在此示例中,详细名称是“first name”:

first_name = models.CharField(max_length=30)

但我在 Django 1.3.1 源代码中找不到正在执行我需要的部分。

更新:

简化:

class Field():
    def __init__(self, field_name=None):
        if not field_name:
            field_name = ??? # some magic here to determine the name
        print(field_name)

class Table():
    first_name = Field()
    last_name = Field()

运行此命令应打印 first_namelast_name

解决方案

class Field():
    def __init__(self, name=None):
        self._name = name

class Table():
    first_name = Field()
    last_name = Field()



for attrName, attr in Table.__dict__.items():
    if isinstance(attr, Field):
        if attr._name is None:
            attr._name = attrName

print(Table.first_name._name)
print(Table.last_name._name)

See the update below

I even don't know how to make a short title for my problem.

In a class I have some class attributes of StringField class:

class Authors(Table):
    # id field is already present 
    first_name = StringField(maxLength=100)
    last_name = StringField(maxLength=100)

StringField constructor may receive an argument called name. If it's not given, i want it to be equal to class attribute's name (first_name, last_name in the example above).

Is it possible to extract the name of the variable the created instance is going to be assigned to?
I guess i have to use inspect module?

I see Django does this:

Each field type, except for ForeignKey, ManyToManyField and
OneToOneField, takes an optional first positional argument -- a
verbose name. If the verbose name isn't given, Django will
automatically create it using the field's attribute name, converting
underscores to spaces.

In this example, the verbose name is "person's first name":

first_name = models.CharField("person's first name", max_length=30)

In this example, the verbose name is "first name":

first_name = models.CharField(max_length=30)

But i don't find in Django 1.3.1 source code the part which is doing what i need.

UPDATE:

To simplify:

class Field():
    def __init__(self, field_name=None):
        if not field_name:
            field_name = ??? # some magic here to determine the name
        print(field_name)

class Table():
    first_name = Field()
    last_name = Field()

Running this should print first_name and last_name

SOLUTION:

class Field():
    def __init__(self, name=None):
        self._name = name

class Table():
    first_name = Field()
    last_name = Field()



for attrName, attr in Table.__dict__.items():
    if isinstance(attr, Field):
        if attr._name is None:
            attr._name = attrName

print(Table.first_name._name)
print(Table.last_name._name)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

风渺 2024-12-12 22:55:46

我不知道姜戈是怎么做到的。但您可以这样做:

class WantFixup(object):
    def new_instance(self, name, derived_name):
        cls = type(self)
        if name is None:
            name = derived_name.replace('_', ' ')
        return cls(name)

class Container(WantFixup):
    def __init__(self, name=None):
        self.name = name
    def __repr__(self):
        return "Container('%s')" % str(self.name)

class WillFixup(object):
    def __init__(self):
        cls = type(self)
        for name in cls.__dict__:
            o = cls.__dict__[name] # look up object from name
            if not isinstance(o, WantFixup):
                continue
            print("calling %s.new_instance('%s', '%s')" % (o, o.name, name))
            self.__dict__[name] = o.new_instance(o.name, name)

class Name(WillFixup):
    first_name = Container("given name")
    last_name = Container()

下面是上述代码的实际运行示例:

>>> import auto_name
>>> n = auto_name.Name()
calling Container('None').new_instance('None', 'last_name')
calling Container('given name').new_instance('given name', 'first_name')
>>> print(n.__dict__)
{'first_name': Container('given name'), 'last_name': Container('last name')}
>>> print(auto_name.Name.__dict__)
{'__module__': 'auto_name', 'last_name': Container('None'), 'first_name': Container('given name'), '__doc__': None}
>>> 

WantFixup 类有两个用途。首先,所有继承自它的类都可以使用 isinstance() 来检测;如果我们的对象实例名为 o,我们可以像 isinstance(o, WantFixup) 一样测试它。其次,它为继承它的任何类提供了 .new_instance() 方法函数。

Container 类是可能需要修复的容器的示例。请注意,它继承自 WantFixup

WillFixup 类包含一个 .__init__() 方法,该方法对从其继承的所有类执行修复。这只是循环遍历类字典中的所有内容,并为每个内容调用 .new_instance() 方法函数,并传入名称。

最后,Name 类继承自 WillFixup,并包含两个 Container 实例。因为它继承自 WillFixup,所以会调用 WillFixup.__init__() 方法。从示例中可以看出,first_name.name 属性设置为 'given name',但 last_name未设置,因此对其进行了修补,将其 .name 属性设置为 'last name'

.__init__() 函数应该设置新的类实例。只要所有特殊的 WantFixup 类实例都在父类中,.__init__() 方法就会自动循环遍历它们并设置它们。

这里令人困惑的部分是,该实例已将 first_name 设置为已修补名称的 Container 实例,并且实际上将用于存储内容。但是类 Name 包含一个 Container 实例,它仅用于存储类的名称,并作为 .__init__() 的标记。代码>方法来查找。

好的部分是魔法隐藏在基类中。 ContainerName 类只需要从它们继承,但它们本身并不混乱。

使用元编程可能有一种更灵活的方法来解决问题。

http://www.ibm.com/developerworks/linux/library /l-pymeta/index.html

此解决方案不是元类编程,但它是经过测试的工作代码。

编辑:这是代码的更改版本。原始代码旨在展示总体思路,但实际上并未初始化 Name 对象。实际上执行 init 并不难,所以我改变了它。

I don't know how Django does it. But you could do it this way:

class WantFixup(object):
    def new_instance(self, name, derived_name):
        cls = type(self)
        if name is None:
            name = derived_name.replace('_', ' ')
        return cls(name)

class Container(WantFixup):
    def __init__(self, name=None):
        self.name = name
    def __repr__(self):
        return "Container('%s')" % str(self.name)

class WillFixup(object):
    def __init__(self):
        cls = type(self)
        for name in cls.__dict__:
            o = cls.__dict__[name] # look up object from name
            if not isinstance(o, WantFixup):
                continue
            print("calling %s.new_instance('%s', '%s')" % (o, o.name, name))
            self.__dict__[name] = o.new_instance(o.name, name)

class Name(WillFixup):
    first_name = Container("given name")
    last_name = Container()

Here is an example of the above code in action:

>>> import auto_name
>>> n = auto_name.Name()
calling Container('None').new_instance('None', 'last_name')
calling Container('given name').new_instance('given name', 'first_name')
>>> print(n.__dict__)
{'first_name': Container('given name'), 'last_name': Container('last name')}
>>> print(auto_name.Name.__dict__)
{'__module__': 'auto_name', 'last_name': Container('None'), 'first_name': Container('given name'), '__doc__': None}
>>> 

The class WantFixup serves two purposes. First, all classes that inherit from it can be detected using isinstance(); if our object instance is named o, we can test it like isinstance(o, WantFixup). Second, it provided the .new_instance() method function to any class that inherits from it.

The class Container is an example of a container that might need fixup. Note that it inherits from WantFixup.

The class WillFixup contains a .__init__() method that performs fixup on all classes that inherit from it. This simply loops over everything in the class dictionary, and calls the .new_instance() method function for each one, passing in the name.

Finally, class Name inherits from WillFixup and contains two instances of Container. Because it inherits from WillFixup, the method WillFixup.__init__() is called. As you can see from the example, first_name has a .name attribute set to 'given name' but last_name wasn't set, so it is patched to have its .name attribute set to 'last name'.

The .__init__() function is supposed to set up the new class instance. As long as all the special WantFixup class instances are in the parent class, the .__init__() method will automatically loop over them and set them up.

The confusing part here is that the instance has first_name set to an instance of Container that has the name patched, and will actually be used to store stuff. But the class Name contains an instance of Container that is just used to store the name of the class, and as a marker for the .__init__() method to find.

The good part is that the magic is hidden away in the base classes. The Container and Name classes just need to inherit from them, but are not themselves cluttered with stuff.

There might be a slicker way to solve the problem using metaprogramming.

http://www.ibm.com/developerworks/linux/library/l-pymeta/index.html

This solution isn't metaclass programming, but it is tested, working code.

EDIT: This is a changed version of the code. The original code was intended to show the general idea, but didn't actually init the Name object. It's not hard to actually do the init, so I changed it.

卖梦商人 2024-12-12 22:55:46

为了像示例中那样神奇地发生,Python 需要成为一种上下文相关的语言(据我所知,事实并非如此)。 Django 使用 ModelBase 元类(以及其他任务)为字段设置详细名称。基本上,元类的 __new__ 循环遍历类属性以获取属性名称,并将它们添加到 选项。你可以更直接一点,直接改变字段。这是一个 Python 2 示例:

class Field(object):
    def __init__(self, name=None):
        self.name = name
    def __str__(self):
        if self.name:
            return self.name
        return type(self).__name__
    def __repr__(self):
        return '%s(%s)' % (type(self).__name__, repr(self.name))

class MetaContainer(type):
    @classmethod
    def dub(metacls, name):
        return name.replace('_', ' ').capitalize()

    def __new__(cls, name, bases, attrs):
        for attr in attrs:
            if issubclass(type(attrs[attr]), Field) and attrs[attr].name is None:
                attrs[attr].name = MetaContainer.dub(attr)
        return super(MetaContainer, cls).__new__(cls, name, bases, attrs)

class Container(object):
    __metaclass__ = MetaContainer
    first_name = Field()
    foo = Field('Foobar')

cntr = Container()
cntr.first_name

Python 3 几乎相同,但您使用 metaclass 类参数* 而不是 __metaclass__ 属性

class Container(object, metaclass=MetaContainer):
    first_name = Field()
    foo = Field('Foobar')

您可以编写一个与 Python 2 和 3 中的元类 通过直接使用元类为容器创建中间基类,而不是metaclass 参数或 __metaclass__ 属性:

ContainerBase = MetaContainer('ContainerBase', (object,), {})

class Container(ContainerBase):
    first_name = Field()
    foo = Field('Foobar')

* 有关更改的原因,请参阅 PEP 3115:Python 3000 中的元类

In order for the magic to happen as in the sample, Python would need to be a context-sensitive language (which is isn't, as far as I know, which isn't that far). Django uses the ModelBase meta-class to (among other tasks) set verbose names for the fields. Basically, the metaclass's __new__ loops over the class attributes to get the attribute names, adding them to the options. You can be a little more direct and alter the fields directly. Here's a Python 2 example:

class Field(object):
    def __init__(self, name=None):
        self.name = name
    def __str__(self):
        if self.name:
            return self.name
        return type(self).__name__
    def __repr__(self):
        return '%s(%s)' % (type(self).__name__, repr(self.name))

class MetaContainer(type):
    @classmethod
    def dub(metacls, name):
        return name.replace('_', ' ').capitalize()

    def __new__(cls, name, bases, attrs):
        for attr in attrs:
            if issubclass(type(attrs[attr]), Field) and attrs[attr].name is None:
                attrs[attr].name = MetaContainer.dub(attr)
        return super(MetaContainer, cls).__new__(cls, name, bases, attrs)

class Container(object):
    __metaclass__ = MetaContainer
    first_name = Field()
    foo = Field('Foobar')

cntr = Container()
cntr.first_name

Python 3 is almost the same, but you use the metaclass class argument* rather than the __metaclass__ property:

class Container(object, metaclass=MetaContainer):
    first_name = Field()
    foo = Field('Foobar')

You can write a version that works with metaclasses in in Python 2 and 3 by creating an intermediate base class for the container using the metaclass directly, rather than the metaclass argument or __metaclass__ property:

ContainerBase = MetaContainer('ContainerBase', (object,), {})

class Container(ContainerBase):
    first_name = Field()
    foo = Field('Foobar')

* For the reason for the change, see PEP 3115: Metaclasses in Python 3000.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文