功能不同,结果相同

时间:2017-03-06 10:26:23

标签: python setattr

因此,我尝试将属性动态设置为具有不同名称的类,其中每个属性对我的数据库进行唯一调用。但是,当我访问属性对象时,尽管查找每个具有完全不同值的不同列,但它们都返回相同的结果。这是代码:

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仍然是最后一个元素。阵列。

2 个答案:

答案 0 :(得分:1)

您的错误印象是定义函数会在定义时将函数绑定到变量值。听起来很复杂,抱歉。我试着解释一下。

您正在循环中定义函数(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()

答案 1 :(得分:0)

如果我按照您要执行的操作进行操作,那么您在调用属性时会非常正确地使用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))