【问题标题】:Create an object given its class name as a dynamic string in Python在 Python 中创建一个给定其类名的对象作为动态字符串
【发布时间】:2014-05-22 22:46:30
【问题描述】:

假设我有这两个类:

tables.py

class Device79table(tables.Table):
    class Meta:
        #link to datasource
        model = Device79
        attrs = {"class": "paleblue"} 

models.py

class Device79(models.Model):
    # data for table  

我有一个引用这两个类的函数。

views.py

def function():
    #makes table of all objects in device 79
    table = Device79table(Device79.objects.all()) 
    table.draw() 

有可能做这样的事情吗?假设参数 'device' = Device79

def function(device)
    table = device+table(device.objects.all())
    table.draw() 

这是为了根据设备的值绘制表格。即,设备可能是 Device79、Device80、Device81 等,程序会自动绘制正确的表格。

【问题讨论】:

  • 有可能,但这可能不是您想要做的。您是否考虑过为所有 device*table 对象创建一个 dict
  • 嘿@mhlester,我没有,但是你知道这种类型的问题是什么,所以我可以用谷歌搜索并更好地理解问题吗?在此期间,我会考虑制作一个 dict,干杯!
  • 我决定把它作为一个答案。见下文

标签: python methods arguments


【解决方案1】:

更新

这是一个新的解决方案,它考虑到您实际上并没有实例化您的类,而是直接使用类对象。

由于Device79 必须在Device79table.Meta 之前定义,您无法告诉Device79 在它自己的定义期间使用哪个表。在Device79table 期间你甚至不能这样做,因为它还不存在。

因此,您需要告诉Device79定义了对应的表之后要使用哪个表。

如您所见,我也选择不使用动态变量名,而是在另一个对象中明确定义的对象。动态变量名称使您的代码更难阅读和维护。

models.py

class Device79(models.Model):
    table = None  # Optional, but cleaner.

tables.py

import models

class Device79table(tables.Table):
    class Meta:
        # link to datasource
        model = models.Device79
        attrs = {"class": "paleblue"} 

# once the table is defined, we can tell Device79 which table to use.
models.Device79.table = Device79table

views.py

import tables  # "from tables import Device79table" would work too.
from models import Device79
# You need to import tables, even if you access the tables from the models,
# because this is where we tell the device which table to use.

def function(device)
    table = device.table(device.objects.all())
    table.draw() 

function(Device79)

通常,循环导入不是问题,只要您导入模块而不是单个对象,但由于您需要在定义表期间直接访问模型,因此无法在 @ 中导入表987654330@。这就是为什么我们在tables.py 中更改设备以告诉它使用哪个表,而不是直接在models.py 中设置它。

这样,我们保持这样的导入链:views -> tables -> modelsmodels 从不尝试导入 tables,但这也意味着我们必须在某个地方至少导入一次 tables 才能完成模型定义。

这有点令人惊讶,但我想不出一种更清洁、更简单的方法来做到这一点,同时只使用类对象而不是实例。

【讨论】:

  • 嗨@Fury,非常感谢您的回答!我更新了我的问题,因为我忽略了一些信息。我尝试了您的方法,并以循环导入结束。你认为你能把我推向正确的方向吗? :)
  • 我没有意识到您实际上是在使用类对象而不是这些类的实例。它使循环导入无法解决(循环导入通常不是真正的问题。See here why。但在你的情况下。我找到了解决方案,我会更新我的答案。
【解决方案2】:

Python 特别擅长反射。提供您的描述,以下是您可以执行的操作示例:

models.py:

class Device79:
    objects = "Device79.objects"

tables.py:

class Device79table:
    def __init__(self, devices):
        self.devices = devices

    def draw(self):
        print "%s.draw() called with %s" % (self.__class__, self.devices)

然后在views.py:

import tables

def function(device):
    table = tables.__dict__[device.__name__ + 'table'](device.objects)
    table.draw()

import models
function(models.Device79)

或者:

from models import Device79
function(Device79)

【讨论】:

    【解决方案3】:

    我不知道Device79table 是在哪里定义的,但我会假设它是global

    我对它的假定义:

    def Device79Table(arg):
        print arg
    

    将其与您的功能集成:

    def function(device):
        globals()[device + 'table'](device.objects.all())
        table.draw()
    

    globals() 函数返回所有全局对象的dict,键是它们名称的字符串。所以globals()['Device79table']Device79table是一回事

    【讨论】:

    • 嗨@mhlester,非常感谢您的回答!我已经更新了我的问题,因为我忽略了一些关键信息。我认为您的解决方案可能仍然适用,但我不是 100% 确定
    • 只要所有设备都以相同的方式定义,它应该仍然适用。试试看!
    猜你喜欢
    • 2014-11-22
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    相关资源
    最近更新 更多