Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 通过SqlAlchemy使用从dict()扩展而来的自定义集合_Python_Inheritance_Collections_Sqlalchemy - Fatal编程技术网

Python 通过SqlAlchemy使用从dict()扩展而来的自定义集合

Python 通过SqlAlchemy使用从dict()扩展而来的自定义集合,python,inheritance,collections,sqlalchemy,Python,Inheritance,Collections,Sqlalchemy,我试图使用一个自定义集合来“连接”(或关联)两个类,但我一直无法做到这一点。也许我完全理解错了,但让我解释一下我在做什么(看看有没有人能给我一个提示,或者其他什么) 我有一个父类(你们中的一些人会从其他问题中记住),其中有几个连接器字段(类似于列表)。其中一个连接器将存储类型为“VR”的Child()类的实例,另一个连接器将存储类型为“CC”的子类 我并不真的需要用于存储子级的集合的持久性,但我需要它是一个特殊的类,这样它就会有一些我已经实现的方法,需要在那里。这将是“ZepConnector”

我试图使用一个自定义集合来“连接”(或关联)两个类,但我一直无法做到这一点。也许我完全理解错了,但让我解释一下我在做什么(看看有没有人能给我一个提示,或者其他什么)

我有一个父类(你们中的一些人会从其他问题中记住),其中有几个连接器字段(类似于列表)。其中一个连接器将存储类型为“VR”的Child()类的实例,另一个连接器将存储类型为“CC”的子类

我并不真的需要用于存储子级的集合的持久性,但我需要它是一个特殊的类,这样它就会有一些我已经实现的方法,需要在那里。这将是“ZepConnector”类(在本例中,我需要使用它的foo()方法)。正如您在下面几行中所看到的,我在父对象的addChild1()方法中随机测试了它的可用性

---------------------Parent.py-----------------

from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import and_
from sqlalchemy.orm import relationship
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Child import Child
from mylibraries.database.tests.Tables import testMetadata
from mylibraries.database.tests.ZepConnector import ZepConnector

class Parent(rdb.Model):
    rdb.metadata(testMetadata)
    rdb.tablename("parents_table")
    rdb.tableargs(schema='test2', useexisting=False)

    id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
    _whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
    _whateverField2 = Column("whatever_field2", String(16)) #Irrelevant

    child1 = relationship(
        "Child",
        uselist=True,
        primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "VR")),
        collection_class=ZepConnector("VR")
        )

    child2 = relationship(
        "Child",
        uselist=True,
        primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "CC")),
        collection_class=ZepConnector("CC")
        )

    def __init__(self):
        print "Parent __init__"
        self._whateverField1 = "Whatever1"
        self._whateverField2 = "Whatever2"
        self.child1 = ZepConnector("VR")
        self.child2 = ZepConnector("CC")

    def addChild1(self, child):
        if isinstance(child, Child):
            print("::addChild1 > Testing .foo method: " + str(self.child1.foo()))
            # The line above doesn't really makes much 
            # but testing the accessibility of the .foo() method.
            # As I'll explain later, it doesn't work
            self.child1.append(child)

    def addChild2(self, child):
        if isinstance(child, Child):
            self.child2.append(child)
import random

from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Tables import testMetadata

class Child(rdb.Model):
    rdb.metadata(testMetadata)
    rdb.tablename("children_table")
    rdb.tableargs(schema='test2', useexisting=False)

    parent_id = Column("parent_id", Integer, ForeignKey("test2.parents_table.id"), primary_key=True)
    type = Column("type", String(2), nullable=True, primary_key=True)
    hasher = Column("hasher", String(5))

    def __init__(self):
        self.type = None
        self.hasher = self.generateHasher()

    def setType(self, typeParameter):
        if typeParameter in set(["VR", "CC"]):
            self.type = typeParameter

    @staticmethod
    def generateHasher():
        retval = str()
        for i in random.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 5):
            retval += i
        return retval
from sqlalchemy.orm.collections import collection

class ZepConnector(dict):
    __emulates__ = list

    def __init__(self, type):
        self.type = type 
        # The 'type' will be "VR" or "CC" and it will be stamped
        # on every Child() class added through this ZepConnector

    def foo(self):
        return True

    @collection.appender
    def append(self, item):
        #Appends a child to itself
        if self.foo():
            item.setType(self.type)
            self[item.hasher] = item

    @collection.remover
    def remove(self, item):
        try:
            del self[item.hasher]
        except ValueError, e:
            print("::remove > Got exception when trying to remove entry=" + str(item.hasher) + ". The exception is: " + str(e))

    def extend(self, items):
        pass

请注意,我使用的是megrok。对于那些不熟悉它的人,请允许我解释一下,它只是一个将Python类映射到SqlAlchemy映射器本身的工具,并且在使用

我猜常规SqlAlchemy中Parent()类的映射类似于:

mapper(Parent, parents_table, properties={
    id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
    _whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
    _whateverField2 = Column("whatever_field2", String(16)) #Irrelevant
    child1 = relationship( # etc, etc, etc
})
#
但我是100%。。。嗯。。。90%... 嗯。。。70%的人确信,使用该工具并不是我想问的问题(我的意思是:我不认为这会干扰SqlAlchemy自定义集合)

儿童是一个非常简单的班级:

---------------Child.py--------------------------

from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import and_
from sqlalchemy.orm import relationship
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Child import Child
from mylibraries.database.tests.Tables import testMetadata
from mylibraries.database.tests.ZepConnector import ZepConnector

class Parent(rdb.Model):
    rdb.metadata(testMetadata)
    rdb.tablename("parents_table")
    rdb.tableargs(schema='test2', useexisting=False)

    id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
    _whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
    _whateverField2 = Column("whatever_field2", String(16)) #Irrelevant

    child1 = relationship(
        "Child",
        uselist=True,
        primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "VR")),
        collection_class=ZepConnector("VR")
        )

    child2 = relationship(
        "Child",
        uselist=True,
        primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "CC")),
        collection_class=ZepConnector("CC")
        )

    def __init__(self):
        print "Parent __init__"
        self._whateverField1 = "Whatever1"
        self._whateverField2 = "Whatever2"
        self.child1 = ZepConnector("VR")
        self.child2 = ZepConnector("CC")

    def addChild1(self, child):
        if isinstance(child, Child):
            print("::addChild1 > Testing .foo method: " + str(self.child1.foo()))
            # The line above doesn't really makes much 
            # but testing the accessibility of the .foo() method.
            # As I'll explain later, it doesn't work
            self.child1.append(child)

    def addChild2(self, child):
        if isinstance(child, Child):
            self.child2.append(child)
import random

from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Tables import testMetadata

class Child(rdb.Model):
    rdb.metadata(testMetadata)
    rdb.tablename("children_table")
    rdb.tableargs(schema='test2', useexisting=False)

    parent_id = Column("parent_id", Integer, ForeignKey("test2.parents_table.id"), primary_key=True)
    type = Column("type", String(2), nullable=True, primary_key=True)
    hasher = Column("hasher", String(5))

    def __init__(self):
        self.type = None
        self.hasher = self.generateHasher()

    def setType(self, typeParameter):
        if typeParameter in set(["VR", "CC"]):
            self.type = typeParameter

    @staticmethod
    def generateHasher():
        retval = str()
        for i in random.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 5):
            retval += i
        return retval
from sqlalchemy.orm.collections import collection

class ZepConnector(dict):
    __emulates__ = list

    def __init__(self, type):
        self.type = type 
        # The 'type' will be "VR" or "CC" and it will be stamped
        # on every Child() class added through this ZepConnector

    def foo(self):
        return True

    @collection.appender
    def append(self, item):
        #Appends a child to itself
        if self.foo():
            item.setType(self.type)
            self[item.hasher] = item

    @collection.remover
    def remove(self, item):
        try:
            del self[item.hasher]
        except ValueError, e:
            print("::remove > Got exception when trying to remove entry=" + str(item.hasher) + ". The exception is: " + str(e))

    def extend(self, items):
        pass

假设每个子实例都有一个唯一的“hasher”字段,可以用作字典中的键(上面的示例与实际情况相去甚远,但它稍微说明了子实例将如何工作以及如何创建测试)

现在是我的自定义连接器。我希望它表现为一个列表或一个集合(更像一个集合,尽管我并不介意),但它是一个继承自dict的类

--------------------ZepConnector.py--------------------

from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import and_
from sqlalchemy.orm import relationship
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Child import Child
from mylibraries.database.tests.Tables import testMetadata
from mylibraries.database.tests.ZepConnector import ZepConnector

class Parent(rdb.Model):
    rdb.metadata(testMetadata)
    rdb.tablename("parents_table")
    rdb.tableargs(schema='test2', useexisting=False)

    id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
    _whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
    _whateverField2 = Column("whatever_field2", String(16)) #Irrelevant

    child1 = relationship(
        "Child",
        uselist=True,
        primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "VR")),
        collection_class=ZepConnector("VR")
        )

    child2 = relationship(
        "Child",
        uselist=True,
        primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "CC")),
        collection_class=ZepConnector("CC")
        )

    def __init__(self):
        print "Parent __init__"
        self._whateverField1 = "Whatever1"
        self._whateverField2 = "Whatever2"
        self.child1 = ZepConnector("VR")
        self.child2 = ZepConnector("CC")

    def addChild1(self, child):
        if isinstance(child, Child):
            print("::addChild1 > Testing .foo method: " + str(self.child1.foo()))
            # The line above doesn't really makes much 
            # but testing the accessibility of the .foo() method.
            # As I'll explain later, it doesn't work
            self.child1.append(child)

    def addChild2(self, child):
        if isinstance(child, Child):
            self.child2.append(child)
import random

from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Tables import testMetadata

class Child(rdb.Model):
    rdb.metadata(testMetadata)
    rdb.tablename("children_table")
    rdb.tableargs(schema='test2', useexisting=False)

    parent_id = Column("parent_id", Integer, ForeignKey("test2.parents_table.id"), primary_key=True)
    type = Column("type", String(2), nullable=True, primary_key=True)
    hasher = Column("hasher", String(5))

    def __init__(self):
        self.type = None
        self.hasher = self.generateHasher()

    def setType(self, typeParameter):
        if typeParameter in set(["VR", "CC"]):
            self.type = typeParameter

    @staticmethod
    def generateHasher():
        retval = str()
        for i in random.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 5):
            retval += i
        return retval
from sqlalchemy.orm.collections import collection

class ZepConnector(dict):
    __emulates__ = list

    def __init__(self, type):
        self.type = type 
        # The 'type' will be "VR" or "CC" and it will be stamped
        # on every Child() class added through this ZepConnector

    def foo(self):
        return True

    @collection.appender
    def append(self, item):
        #Appends a child to itself
        if self.foo():
            item.setType(self.type)
            self[item.hasher] = item

    @collection.remover
    def remove(self, item):
        try:
            del self[item.hasher]
        except ValueError, e:
            print("::remove > Got exception when trying to remove entry=" + str(item.hasher) + ". The exception is: " + str(e))

    def extend(self, items):
        pass

但我不知道为什么,父类中的“ZepConnector”实例似乎不是“ZepConnector”类型,而是“InstrumentedList”:

在Parent()的addChild1方法中,我尝试测试.foo()方法(该方法应只打印“True”)时,出现以下错误:

AttributeError: 'InstrumentedList' object has no attribute 'foo'
显示整个回溯:

Traceback (most recent call last):
  File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 134, in publish
    result = publication.callObject(request, obj)
  File "/home/ae/mytests-cms/grokserver/eggs/grok-1.1rc1-py2.4.egg/grok/publication.py", line 89, in callObject
    return super(ZopePublicationSansProxy, self).callObject(request, ob)
  File "/home/ae/mytests-cms/grokserver/eggs/zope.app.publication-3.10.2-py2.4.egg/zope/app/publication/zopepublication.py", line 205, in callObject
    return mapply(ob, request.getPositionalArguments(), request)
  File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 109, in mapply
    return debug_call(obj, args)
  File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 115, in debug_call
    return obj(*args)
  File "/home/ae/mytests-cms/grokserver/eggs/grokcore.view-1.13.2-py2.4.egg/grokcore/view/components.py", line 101, in __call__
    return mapply(self.render, (), self.request)
  File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 109, in mapply
    return debug_call(obj, args)
  File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 115, in debug_call
    return obj(*args)
  File "/home/ae/mytests-cms/grokserver/src/grokserver/app.py", line 1575, in render
    mylibraries.database.tests.Test.runWholeTest()
  File "/home/ae/mytests-cms/mylibraries/database/tests/Test.py", line 54, in runWholeTest
    __test()
  File "/home/ae/mytests-cms/mylibraries/database/tests/Test.py", line 35, in __test
    parent.addChild1(child)
  File "/home/ae/mytests-cms/mylibraries/database/tests/Parent.py", line 54, in addChild1
    print("::addChild1 > Testing .foo method: " + str(self.child1.foo()))
AttributeError: 'InstrumentedList' object has no attribute 'foo'
Debug at: http://127.0.0.1:8080/_debug/view/1289342582
真奇怪。。。ZepConnector的init方法已正确执行。。。但当我尝试使用它时,它似乎不是ZepConnector

我又做了两次测试,但都没有成功:

在第二次尝试中,我写道:

class ZepConnector(dict):
    __emulates__ = set
但这甚至让事情变得更糟,因为我得到:

TypeError: Incompatible collection type: ZepConnector is not list-like
在第三次(或第二次)尝试中,我想。。。“嗯……如果它说ZepConnector不是列表,那么告诉父对象()不要在关系中使用列表可能会有所帮助……如果说collection_类是ZepConnector,则需要在关系中使用uselist参数…”

于是我写道:

child1 = relationship(
    "Child",
    uselist = False,
    primaryjoin=lambda: and_((Parent.id == Child.parent_id),(Child.type == "VR")),
    collection_class=ZepConnector("VR")
    )
但这引发了一个令人毛骨悚然的例外,谈论一个我不应该看到也不想看到的领域。。。曾经:-D

AttributeError: 'ZepConnector' object has no attribute '_sa_instance_state'
我正在使用Python2.4和SqlAlchemy 0.6.6,以防万一

如果有人有任何想法,指导,咨询。。。无论什么我真的很感激你和我分享。。。嗯。。。美国

提前谢谢你

(如果你达到了这一行,你当然应该感谢你耐心阅读这篇博文)

明白了

我在SqlAlchemy谷歌小组也问了同样的问题,我刚刚得到了答案

引述:

所以这是不正确的- 集合\u类接受一个类或 另一个可调用的参数 将生成您的 收集ZepConnector源 你有下面的说明 ZepConnector(“VR”)是 收藏。你需要使用 兰姆达:在那里。其他错误 你得到的东西看起来会延伸 因此(这也是为什么init是 打电话给ZepConnector-你是 你自己说吧)


感谢迈克尔·拜尔(以及所有试图帮助你的人,即使是通过阅读如此冗长的帖子)

我甚至还没有开始理解你的代码。请把它删减,把你的问题分开(我确信,问题不止一个),然后对每一个单独的问题做一个简单的演示。@knitti>好吧。。。我想我不能把这个问题和其他问题分开。主要的问题可以理解为:“我如何使用我的ZepConnector类作为父类()和子类()之间的集合类?”感谢您的阅读,虽然我不相信,但并没有完全放弃:-)您是否可以被说服包含AttributeError的完整回溯?在控制流潜入
sqlalchemy.util
@knitti>编辑我的问题之前,我对这行特别感兴趣:-)@knitti>Jeez。。。这当然是一个巨大的职位!谢谢你的阅读!好吧,那就酷了。出于兴趣:你想解决什么问题?@knitti>我无法将自己的类ZepConnector用作集合类。我不知道是否可以使用从dict(映射对象)扩展的类来模拟集合/列表的行为,因为在SqlAlchemy示例中,我看到它们使用从列表扩展为列表的集合类或从dict扩展为dict的类,但我希望从dict扩展的类可以作为列表。。。我甚至不知道这是否可行(我想是的,但我不确定),结果证明我唯一要做的是,在Parent.py编写中:collection\u class=lambda:ZepConnector(“VR”)而不是collection\u class=ZepConnector(“VR”)