python - UserMixin 继承干扰了 python list.count() 方法

标签 python sqlalchemy

我正在使用 list.count() 方法来检查关系是否具有元素。

虽然它在测试代码中工作得很好,但当计数的类继承flask_login UserMixin 类时,它就不再起作用了。

为什么,以及如何解决它?

class Element(UserMixin):
    id=1
    name="default"
    def __init__(self, name):
        name=name

elementsList=[]


elt1=Element(name="1")
elt2=Element(name="2")
elt3=Element(name="3")

elementsList.append(elt1)
elementsList.append(elt2)


print("Counting Element2 should return 1: ", elementsList.count(elt2)) # returns 2
print("Counting Element3 should return 0: ", elementsList.count(elt3)) # returns 2

我应该获取列表中的元素数量(1 或 0)。

相反,我得到了整个列表的长度(2,即使我附加了更多整数)。

就好像它正在计算列表中类的出现次数,而不是对象。

最佳答案

首先让我们了解如何list.count作品。从cpython源代码list.count具有以下定义。

static PyObject *
list_count(PyListObject *self, PyObject *value)
{
    Py_ssize_t count = 0;
    Py_ssize_t i;

    for (i = 0; i < Py_SIZE(self); i++) {
        int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
        if (cmp > 0)
            count++;
        else if (cmp < 0)
            return NULL;
    }
    return PyLong_FromSsize_t(count);
}

所以当你执行some_list.count(some_element)时, Python will iterate over every object in the list, and perform a rich comparison (即 PyObject_RichCompareBool )。

来自C-API文档丰富的比较(即 PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid) )将 比较 o1 的值和o2使用 opid 指定的操作,必须是 Py_LT 之一, Py_LE , Py_EQ , Py_NE , Py_GT ,或Py_GE ,对应< , <= , == , != , > ,或>=分别。返回-1出错时,0如果结果为假,1否则。

如果值为 1 (即 true )计数器将增加。迭代结束后,计数器将返回给调用者。

list_count在CPython中大致相当于Python层中的以下内容,

def list_count(list_, item_to_count):
   counter = 0
   for iterm in list_:
      if item == item_to_count:
          counter += 1
   return counter

现在让我们回到你的问题。

While it works pretty well in a test code, it doesnt anymore when the counted class inherits the flask_login UserMixin class.

让我们看一个示例类(不继承 UserMixin )

class Person
   def __init__(self, name):
       self.name = name

p1 = Person("Person1")
p2 = Person("Person2")
p3 = Person("Person3")

print([p1, p2, p3].count(p1))

这将打印 1正如我们所预期的。但是python这里是如何进行比较的呢???默认情况下,python 将比较 id p1(即对象的内存地址) ID 为 p1 , p2 , p3 。由于每个新对象都有不同的 id ,因此 count 方法将返回 1 .

好吧,如果名字相等的话我们想把这个人算作一个怎么办???

让我们举同样的例子。

p1 = Person("Person1")
p2 = Person("Person1")

print([p1, p2].count(p1)) # I want this to be return 2

但这仍然返回1因为 python 仍在与它的对象 ID 进行比较。那么我该如何定制呢?您可以覆盖 __eq__的对象。即,

class Person(object):
   def __init__(self, name):
       self.name = name

   def __eq__(self, other):
       if isinstance(other, self.__class__):
           return self.name == other.name
       return NotImplemented

p1 = Person("Person1")
p2 = Person("Person1")

print([p1, p2].count(p1))

哇现在它回来了2正如预期的那样。

现在让我们考虑继承自 UserMixin 的类.

class Element(UserMixin):
    id=1
    def __init__(self, name):
        self.name=name

elementsList=[]
elt1=Element(name="1")
elt2=Element(name="2")
elt3=Element(name="3")
elementsList.append(elt1)
elementsList.append(elt2)
print(elementsList.count(elt2)) 

这将打印 2 。为什么?。如果根据 ids 进行比较本来应该是 1 。所以就会有__eq__在某处实现。因此,如果您查看 UserMixin类实现它实现 __eq__ 方法。

def __eq__(self, other):
    '''
    Checks the equality of two `UserMixin` objects using `get_id`.
    '''
    if isinstance(other, UserMixin):
        return self.get_id() == other.get_id()
    return NotImplemented

def get_id(self):
    try:
        return text_type(self.id)
    except AttributeError:
        raise NotImplementedError('No `id` attribute - override `get_id`')

如您所见,比较是根据其 id 进行的。属性。在这种情况下Element类设置id类级别的属性,因此对于所有实例来说都是相同的。

How to fix this,

从逻辑角度来看,每个对象都有唯一的 id。因此id应该是实例级属性。请参阅 flask-login 中的一个示例代码库本身。

class User(UserMixin):
    def __init__(self, name, id, active=True):
        self.id = id
        self.name = name
        self.active = active

    def get_id(self):
        return self.id

    @property
    def is_active(self):
        return self.active

关于python - UserMixin 继承干扰了 python list.count() 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54146830/

相关文章:

python - 如何检查 SQLAlchemy session 是否脏

python - SQLAlchemy 中的跨服务器选择

python - 使用 SQLAlchemy 如何在使用 db.create_all() 创建数据库后填充行

python - 带空格的 SQLAlchemy 列名

python - opencv cv2.calibrateCamera错误

python - Flask 服务器在 macbook 上托管时可见,但在 Windows 桌面上托管时不可见? (什么都试过了?)

python - 为什么我的 PyArrayObject* 数据​​被截断?

python - 按未排序列表中的出现顺序对列表项进行分组

python - 使用 beautifulsoup4 从 html 表中提取值(第 2 行开始,第 1 和第 6 列)

python - Flask SQLAlchemy 外键关系