不同的功能,相同的结果

Different functions, same result

所以我正在尝试将属性动态设置为具有不同名称的 class,其中每个 属性 都对我的数据库进行唯一调用。但是,当我访问 属性 对象时,尽管在每个具有完全不同值的不同列上查找,但所有这些对象都 return 相同的结果。这是代码:

class Configs:

    def __init__(self, guild_id):
        self.guild_id = guild_id

for x in configs:

    def fget(self):
        return cur.execute(f'SELECT {x.name} FROM configs WHERE guild_id = ?', (self.guild_id,)).fetchone()[0], x.name

    def fset(self, value):
        cur.execute(f'UPDATE configs SET {x.name} = ? WHERE guild_id = ?', (value, self.guild_id))
        con.commit()

    setattr(Configs, x.name, property(fget, fset))

configs 变量是一个对象列表,其中每个对象都有一个指向字符串的 name 属性。结果始终是 configs 数组的最后一个元素会产生的结果,我怀疑这是因为 x.name 用于进行调用并且一旦 for 循环完成,x 仍然是数组。

如果我按照你想做的去做,你是完全正确的,当你的属性被调用时,它们将使用 x.name 的当前值(这将是它剩下的任何值)在循环结束时)。

这里有一个可能的修复方法:将 x.name 分配给您的 属性 函数可以访问的另一个变量。默认参数可能适用于此。

for x in configs:

    def fget(self, col_name=x.name):
        return cur.execute(f'SELECT {col_name} FROM configs WHERE guild_id = ?', (self.guild_id,)).fetchone()[0], col_name

    def fset(self, value, col_name=x.name):
        cur.execute(f'UPDATE configs SET {col_name} = ? WHERE guild_id = ?', (value, self.guild_id))
        con.commit()

    setattr(Configs, x.name, property(fget, fset))

您误以为定义函数会在定义时将函数绑定到变量值。这听起来很复杂,抱歉。我会尽力解释。

您正在循环定义函数(fgetfset)。在函数中,您使用循环变量 (x)。这会起作用,但不会以您期望的方式起作用。所有函数都将完全相同,总是在调用 时访问全局变量x 的值。不考虑定义时的值。

例如:

a = []
for i in range(3):
  def f(): return i
  a.append(f)

a[0]()  # will return 2
del i
a[0]()  # will raise a NameError because there is no i anymore

要解决您的问题,您需要将定义时的值传递给函数:

def fget(self, x=x):
    return cur.execute(f'SELECT {x.name} FROM configs WHERE guild_id = ?', (self.guild_id,)).fetchone()[0], x.name

def fset(self, value, x=x):
    cur.execute(f'UPDATE configs SET {x.name} = ? WHERE guild_id = ?', (value, self.guild_id))
    con.commit()