基本继承(在python中)

2024-06-09 21:55:04 发布

您现在位置:Python中文网/ 问答频道 /正文

用户

我有一个关于继承的基本问题(在python中)。我有两个类,其中一个是从另一个类继承来的

class   p:
    def __init__(self,name):
        self.pname  = name

class   c(p):
    def __init__(self,name):
        self.cname  = name

是否有可能创建一个父对象和多个引用同一父对象的子对象?它的工作原理应该是父对象包含多个变量,每当我从子对象访问相应的变量时,我实际上从父对象访问变量。一、 e.如果我为一个子项更改它,则所有其他子项也会更改,并且数据只在内存中存储一次(而不是为每个子项复制…)

提前谢谢你。在

这里有一个可能的解决办法,我认为它不是那么好

^{pr2}$

这真的是最先进的技术还是存在其他概念?在

塞巴斯蒂安

谢谢你们所有人的帮助,还有名字惯例:)但我还是不太满意。也许我会举一个更高级的例子来强调我真正想做的事情。在

class P:
    data = "shareddata"
    def __init__(self,newdata):
        self.data = newdata 

    def printname(self):
        print self.name 

class C(P):
    def __init__(self,name):
        self.name = name

现在我可以做以下事情了

In [33]: c1 = test.C("name1")

In [34]: c2 = test.C("name2")

In [35]: c1.printname()
name1

In [36]: c2.printname()
name2

In [37]: c1.data
Out[37]: 'shareddata'

In [38]: c2.data
Out[38]: 'shareddata'

到目前为止,这正是我想要的。每个子类都有一个不同的变量名,父类访问各个变量。正常遗传。 然后是来自父类的变量数据,每个子类都访问它。但是,现在下面的方法不再起作用了

In [39]: c1.data = "tst"

In [40]: c2.data
Out[40]: 'shareddata'

In [41]: c1.data
Out[41]: 'tst'

我希望c1.data中的更改也影响c2.data,因为我希望变量被共享,某种程度上是父类的全局变量。在

不止这些。我还想创建P的不同实例,每个实例都有自己的数据变量。当我创建一个新的C对象时,我想指定从哪个P对象数据中提取数据,也就是说,共享。。。。在

更新:

对@eyquem评论的评论:谢谢你,它正朝着我想要的方向发展。但是,现在__class__.pvar在类的所有对象之间共享。我想要的是P的几个实例可能有不同的pvar。假设P1的pvar=1,P2的pvar=2。然后我想创建与P1相关的子元素C1a,C1b,C1c,也就是说,如果我说C1a.pvar,它应该从P1访问pvar。然后我创建C2a,C2b,C2c,如果我访问C2b.pvar,我想从P2访问pvar。因为C类从P类继承pvar,所以C知道pvar。我天真的想法是,如果我创建一个C的新实例,我应该能够指定哪个(现有)P对象用作父对象,而不是像在C的__init__内部调用P.__init__时那样创建一个全新的P对象。。。听起来很简单,也许我忘了什么。。。在

更新:

所以我找到了this discussion这几乎是我的问题

有什么建议吗?在

更新:

方法。子类似乎不再存在。。在

更新:

以下是另一个链接:

link to discussion

在那里,它是通过复制来解决的。但是我不想复制父类,因为我希望它只存在一次。。。在

更新:

很抱歉昨天离开讨论,我有点不舒服。。。谢谢你的帖子!我现在要通读它们。我想了很多,这里有一个可能的解决办法

class P(object):
    def __init__(self,pvar):
        self.pobject    = None
        self._pvar  = pvar

    @property
    def pvar(self):
    if self.pobject != None:
        return  self.pobject.pvar
    else:
            return self._pvar
    @pvar.setter
    def pvar(self,val):
    if self.pobject != None:
        self.pobject.pvar = val
    else:
            self._pvar=val

    def printname(self):
    print self.name


class C(P):
    def __init__(self,name,pobject):  #<-- The same default `P()` is 
                                          # used for all instances of `C`, 
                                          # unless pobject is explicitly defined.
    P.__init__(self,None)
        self.name   = name
        self.pobject = pobject


p1  = P("1")
p2  = P("2")


c1a = C("c1a",p1)
c1b = C("c1b",p1)
c1c = C("c1c",p1)
c2a = C("c2a",p2)
c2b = C("c2b",p2)
c2c = C("c2c",p2)


print   id(c1a.pvar)
print   id(c1b.pvar)
print   id(c1c.pvar)
print   id(c2a.pvar)
print   id(c2b.pvar)
print   id(c2c.pvar)
print   id(p1.pvar)
print   id(p2.pvar)

print   id(c1a.name)
print   id(c1b.name)
print   id(c1c.name)
print   id(c2a.name)
print   id(c2b.name)
print   id(c2c.name)

这有点麻烦,我希望有一个更简单的方法来实现这一点。但是它有一个特点,pvar只在P类中提到,而C类不知道pvar,因为根据我对继承的理解,它应该是这样的。然而,当我创建一个新的C实例时,我可以指定一个现有的P实例,它将存储在变量poobject中。当访问变量pvar时,实际上访问存储在该变量中的P实例的pvar。。。在

输出由

3078326816
3078326816
3078326816
3074996544
3074996544
3074996544
3078326816
3074996544
156582944
156583040
156583200
156583232
156583296
156583360

现在我将仔细阅读你最后的评论

祝你一切顺利,塞巴斯蒂安

更新:在

我认为最优雅的方法是以下(这行不通)

class P(object):
    def __init__(self,pvar):
        self.pvar   = pvar

    def printname(self):
        print self.name


class C(P):
    def __init__(self,name,pobject):  
        P = pobject
        self.name   = name

我认为python应该考虑到这一点。。。在

更新:

好吧,现在我找到了一个实现这个目标的方法,这要归功于艾奎姆的解释。但既然这真的是一个黑客,就应该有一个官方版本。。。在

def replaceinstance(parent,child):
    for item in parent.__dict__.items():
        child.__dict__.__setitem__(item[0],item[1])
        print item

class P(object):
    def __init__(self,pvar):
        self.pvar   = pvar

    def printname(self):
    print self.name


class C(P):
    def __init__(self,name,pobject):
    P.__init__(self,None)
    replaceinstance(pobject,self)
        self.name   = name



p1  = P("1")
p2  = P("2")


c1a = C("c1a",p1)
c1b = C("c1b",p1)
c1c = C("c1c",p1)
c2a = C("c2a",p2)
c2b = C("c2b",p2)
c2c = C("c2c",p2)


print   id(c1a.pvar)
print   id(c1b.pvar)
print   id(c1c.pvar)
print   id(c2a.pvar)
print   id(c2b.pvar)
print   id(c2c.pvar)
print   id(p1.pvar)
print   id(p2.pvar)

print   id(c1a.name)
print   id(c1b.name)
print   id(c1c.name)
print   id(c2a.name)
print   id(c2b.name)
print   id(c2c.name)

输出同上

3077745184
3077745184
3077745184
3074414912
3074414912
3074414912
3077745184
3074414912
144028416
144028448
144028480
144028512
144028544
144028576

更新:即使id看起来是正确的,最后一个代码也不能像这次测试中所明确的那样工作

c1a.pvar    = "newpvar1"

print   c1a.pvar
print   c1b.pvar
print   c1c.pvar
print   c2a.pvar
print   c2b.pvar
print   c2c.pvar
print   p1.pvar
print   p2.pvar

它有输出

newpvar1
1
1
2
2
2
1
2

不过,我发布的版本首先奏效了:

class P(object):
    def __init__(self,pvar):
        self.pobject    = None
        self._pvar  = pvar

    @property
    def pvar(self):
    if self.pobject != None:
        return  self.pobject.pvar
    else:
            return self._pvar
    @pvar.setter
    def pvar(self,val):
    if self.pobject != None:
        self.pobject.pvar = val
    else:
            self._pvar=val

    def printname(self):
    print self.name


class C(P):
    def __init__(self,name,pobject):  #<-- The same default `P()` is 
                                          # used for all instances of `C`, 
                                          # unless pobject is explicitly defined.
    P.__init__(self,None)
        self.name   = name
        self.pobject = pobject


p1  = P("1")
p2  = P("2")


c1a = C("c1a",p1)
c1b = C("c1b",p1)
c1c = C("c1c",p1)
c2a = C("c2a",p2)
c2b = C("c2b",p2)
c2c = C("c2c",p2)


print   id(c1a.pvar)
print   id(c1b.pvar)
print   id(c1c.pvar)
print   id(c2a.pvar)
print   id(c2b.pvar)
print   id(c2c.pvar)
print   id(p1.pvar)
print   id(p2.pvar)

print   id(c1a.name)
print   id(c1b.name)
print   id(c1c.name)
print   id(c2a.name)
print   id(c2b.name)
print   id(c2c.name)




print   "testing\n"

c1a.printname()
c1b.printname()
c1c.printname()
c2a.printname()
c2b.printname()
c2c.printname()


print   "\n"
c1a.name = "c1anewname"
c2b.name = "c2bnewname"


c1a.printname()
c1b.printname()
c1c.printname()
c2a.printname()
c2b.printname()
c2c.printname()


print "pvar\n"

print   c1a.pvar
print   c1b.pvar
print   c1c.pvar
print   c2a.pvar
print   c2b.pvar
print   c2c.pvar
print   p1.pvar
print   p2.pvar

print "\n"
c1a.pvar    = "newpvar1"

print   c1a.pvar
print   c1b.pvar
print   c1c.pvar
print   c2a.pvar
print   c2b.pvar
print   c2c.pvar
print   p1.pvar
print   p2.pvar

print "\n"
c2c.pvar    = "newpvar2"

print   c1a.pvar
print   c1b.pvar
print   c1c.pvar
print   c2a.pvar
print   c2b.pvar
print   c2c.pvar
print   p1.pvar
print   p2.pvar

有了输出

^{14}$

有人知道为什么会这样吗?我可能不太理解python处理这个__dict__的内部方式。。。在


Tags: nameselfiddefprintp2c2cp1
3条回答

It should work like that that the parent object contains several variables and whenever I access the corresponding variables from a child I actually access the variable form the parent. I.e. if I change it for one child it is changed also for all other childes and the data are only stored once in memory (and not copied for each child...)

那不是继承。在

那是完全不同的概念。在

你的“共享变量”只是可以被改变的对象,并且在其他对象中有引用。没什么有趣的。在

继承与此完全不同。在

我认为您的解决方案是可行的;您可以使用属性使访问P的属性更容易:

class P(object):
    def __init__(self,name='default',pvar=1):
        self.pname  = name
        self.pvar=pvar

class C(object):
    def __init__(self,name,pobject=P()):  #<-- The same default `P()` is 
                                          # used for all instances of `C`, 
                                          # unless pobject is explicitly defined.
        self.cname  = name
        self.pobject=pobject
    @property
    def pvar(self):
        return self.pobject.pvar
    @pvar.setter
    def pvar(self,val):
        self.pobject.pvar=val

c1=C('1')
c2=C('2')

c1c2共享相同的pobject

^{pr2}$

请注意,更改pvarc1会改变c2.pvar

print(c2.pvar)
# 2

c3有不同的pobject

c3=C('3',P())
print(c3.pvar)
# 1

关于心理学实验的OOP设计(在评论中提到):

import Image

class Picture(object):
    def __init__(self,filename):
        self.filename = filename
        self.image=Image.open(filename)       

class Person(object):
    def __init__(self,name):
        self.name=name
        # other vital statistics associated with people as individuals here

class Trial(object):
    # A trial is composed of one person, one picture, and the places they look
    def __init__(self,person,picture,locations):
        self.person=person
        self.picture=picture
        self.locations = locations
    # put methods for analyzing where the person looked here

一个Picture当然不是Person,反之亦然。Trials也是如此,所以这些类都不应该互相继承。在

这些类中的每一个都有一个公共(也许还有一个私有)接口。 公共方法和属性应该可以从其他类自由访问。 因此,给定一个Trial实例,t,应该可以通过t.picture.image访问该图像。只要您只访问公共属性和方法,那么一切都应该正常。在

为了方便起见,可以使用properties将属性链接到组件属性。例如:

class Trial(object):
    ...
    @property
    def image(self):
        return self.picture.image

但是,为了简化这一点,比如说,TrialPicture的一个子类,这将违背OOP的基本设计原则。在

另一个答案是对的,你的问题更多的是关于名称空间和引用,而不是继承。在

Python中的所有变量都是引用,所有对象实例都是一个命名空间。所以你可以:

class C():
    def __init__(self, x):
        self.x  = x

class Shared(object):
    def __init__(self, value):
        self.value  = value

# instances:
>>> shared1 = Shared(1)
>>> shared2 = Shared(2)
>>> c1 = C(shared1)
>>> c2 = C(shared1)
>>> c3 = C(shared2)
>>> c4 = C(shared2)
# c1 and c2 sharing a reference to shared1
>>> c1.x.value
1
>>> c2.x.value
1
# change c2.x will reflect on c1 
>>> c2.x.value = 3
>>> c1.x.value
3
# but not on c3, because shared1 and shared2 are distinct namespaces
>>> c3.x.value
2

更新:

但是小心,很容易犯错误:

^{pr2}$

我认为最先进的技术应该是使用properties来隐藏私有实例变量中的^{},这样就可以使用c1.x而不是c1.x.value,从而避免像上面的例子那样的错误。在

相关问题 更多 >