首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python中的多重继承(特定问题)

Python中的多重继承(特定问题)
EN

Stack Overflow用户
提问于 2010-01-25 18:07:56
回答 3查看 1.3K关注 0票数 1

这里有人能确定为什么在下面这个例子的底部引发TypeError吗?

代码语言:javascript
复制
>>> import threading
>>> class SessionManager(threading.Thread, threading._RLock, dict):

    UPDATE = 60 * 60

    def run(self):
        while True:
            time.sleep(self.UPDATE)
            with self:
                for key in tuple(self):
                    if not self[key]:
                        del self[key]

    def __getitem__(self, key):
        session = super()[key]
        session.wakeup()
        return session

>>> SM = SessionManager()
>>> SM.daemon = True
>>> SM.start()
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    SM.start()
TypeError: unhashable type: 'SessionManager'
>>> 

编辑:

下面是上面启动的模块的最终版本。它在VerseMatch程序中得到了应用。

代码语言:javascript
复制
#! /usr/bin/env python
"""Oversee the timely destruction of unused sessions.

The two classes in this module allow automated memory cleanup to be regularly
performed and timed actions to be executed within reasonable time periods."""

################################################################################

__author__ = 'Stephen "Zero" Chappell <Noctis.Skytower@gmail.com>'
__date__ = '11 February 2010'
__version__ = '$Revision: 3 $'

################################################################################

import threading
import time

################################################################################

class SessionManager(threading.Thread, threading._RLock, dict):

    """Manage session objects along with associated data.

    This class acts as dictionary with a data-protection mutex.
    It can run a cleanup routine at regular intervals if needed."""

    def __init__(self, sleep_interval):
        """Initialize variables in SessionManager's parent classes."""
        threading.Thread.__init__(self)
        threading._RLock.__init__(self)
        self.__sleep_interval = sleep_interval

    def run(self):
        """Remove old sessions from memory as needed.

        This method is executed by calling .start() on a SessionManager
        object. The "daemon" attribute may need be set to True before
        activating this feature. Please note that once this cleanup
        routine begins, it must run until the program terminates."""
        while True:
            time.sleep(self.__sleep_interval)
            with self:
                for key in tuple(self):
                    if not super().__getitem__(key):
                        del self[key]

    def __setitem__(self, key, value):
        """Add manager attribute to value before storing it."""
        value.manager = self
        super().__setitem__(key, value)

    def __getitem__(self, key):
        """Retrieve the session specified by the given key.

        Like a normal dictionary, the value is returned to the caller
        if it was found. However, the wakeup method on the session is
        called first. This effectively delays the session's deletion."""
        session = super().__getitem__(key)
        session.wakeup()
        return session

    def __hash__(self):
        """Compute a hash as required by Thread objects."""
        return id(self)

################################################################################

class Session:

    """Store session variables for a limited time period.

    The only functionality this class directly supports is calling an event
    handler when the instance is destroyed. Session objects given to a
    SessionManager are automatically cleared out of memory when their "time to
    live" is exceeded. The manager must be started for such functionality."""

    def __init__(self, time_to_live, on_destroyed=None):
        """Initialize timeout setting and deletion handler."""
        self.__time_to_live = time_to_live
        self.__on_destroyed = on_destroyed
        self.wakeup()

    def wakeup(self):
        """Refresh the last-accessed time of this session object.

        This method is automatically called by the class initializer.
        Instances also get a wakeup call when retrieved from a manager."""
        self.__time = time.time()

    def __bool__(self):
        """Calculate liveliness of object for manager."""
        return time.time() - self.__time <= self.__time_to_live

    def __del__(self):
        """Call deletion event handler if present.

        Completely optional: an on_destroyed handler may be specified
        when the object is created. Exception handling is non-existent."""
        if self.__on_destroyed is not None:
            self.__on_destroyed()
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-01-25 18:13:33

这个问题来自于threading.py,可以更简单地再现如下:

代码语言:javascript
复制
>>> import threading
>>> class SessionManager(threading.Thread, threading._RLock, dict): pass
... 
>>> s = SessionManager()
>>> s.start()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 469, in start
    _limbo[self] = self
TypeError: unhashable type: 'SessionManager'

您可以研究threading.py来确切地了解为什么线程对象需要是可哈斯的,但修复也很简单:只需重写另外两个方法即可。

代码语言:javascript
复制
def __eq__(self, other): return self is other
def __hash__(self): return hash(id(self))

这使您的类实例具有可理解性。

票数 3
EN

Stack Overflow用户

发布于 2010-01-25 19:08:29

尽管Alex对这个问题进行了点诊断,但我仍然强烈认为,在这种情况下,您不应该多继承从dict继承的遗产(或者在一般情况下,就是这样)。虽然从它中子类并自动继承所有dict行为似乎很方便,但是dicts (以及一般的内置类型)通常在内部受到快捷方式的限制。例如,' get‘方法将不会调用修改过的__getitem__,即使它确实获得了该项:

代码语言:javascript
复制
>>> class MyDict(dict):
...     def __getitem__(self, key):
...         print("in __getitem__(%r)" % (key,))
...         return super(MyDict, self).__getitem__(key)
... 
>>> d = MyDict({'a': 'b', 'c': 'd'})
>>> d['a']
in __getitem__('a')
'b'
>>> d.get('c')
'd'
>>>

(这类案件不胜枚举。)

此外,涉及内置类型的多重继承要求所有类型的实例的内存中布局是兼容的。恰好threading.Threadthreading._Rlock是Python (这意味着它们有一个非常简单的内存中布局,与dict兼容),但是如果这种情况在将来发生变化,或者您想要包含其他类型,它就会失败。

这确实是个坏主意。

票数 1
EN

Stack Overflow用户

发布于 2021-06-23 11:58:46

在班级一级宣布以下内容是否充分和合理:

代码语言:javascript
复制
__hash__ = threading.Thread.__hash__
__eq__ = threading.Thread.__eq__
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2134452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档