关于python:将超类实例转换为子类实例

Convert superclass instance to subclass instance

  • 我有一个不能触摸的外部图书馆。这个库有一个函数gena(),它返回类A的实例。
  • 在我这边,我把B类定义为A类的一个子类。
  • 我想在我的项目中使用类B的实例,但是该实例应该由gena()生成。

有什么标准和简单的方法可以做到这一点吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# I cannnot tweak these code

def genA():
    a = A
    return(a)

class A:
    def __init__():
        self.a = 1

# ---

# code in my side

class B(A):
    def __init__():
        self.b = 2


a = genA()
# like a copy-constructor, doesn't work
# b = B(a)

# I want to get this
b.a # => 1
b.b # => 2

这里是一个等价的C++代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>

// library side code
class A {
public:
  int a;
  // ... many members

  A() { a = 1; }
};

void fa(A a) {
  std::cout << a.a << std::endl;
}

A genA() { A a; return a; }

// ///
// my code

class B : public A {
public:
  int b;
  B() : A() { init(); }
  B(A& a) : A(a) { init(); }
  void init() { b = 2; }
};

void fb(B b) {
  std::cout << b.b << std::endl;
}


int main(void) {
  A a = genA();
  B b(a);

  fa(b); // => 1
  fb(b); // => 2
}


您不应该使用__new__,但它只适用于新样式的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A(object):
    def __init__(self):
        self.a = 10

class B(A):
    def __new__(cls, a):
        a.__class__ = cls
        return a

    def __init__(self, a):
        self.b = 20

a = A()
b = B(a)

print type(b), b.a, b.b   # <class '__main__.B'> 10 20

但正如我所说,不要这样做,您可能应该使用聚合,而不是在这种情况下使用子类。如果您希望制作B,使其具有与A相同的接口,您可以使用__getattr__编写透明代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
class B(object):
    def __init__(self, a):
        self.__a = a
        self.b = 20

    def __getattr__(self, attr):
        return getattr(self.__a, attr)

    def __setattr__(self, attr, val):
        if attr == '_B__a':
            object.__setattr__(self, attr, val)

        return setattr(self.__a, attr, val)


我不明白你的密码。我认为这是错误的。首先,在EDOCX1中,A和B都没有self(0);其次,在B类中,您没有调用A的构造函数。第三,gena不返回任何对象,只引用一个类。请检查更改的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def genA():
    a = A() #<-- need ()
    return(a)

class A:
    def __init__(self):  # <-- self missing
        self.a = 1

# ---

# code in my side

class B(A):
    def __init__(self, a=None):
        super().__init__()  #<-- initialize base class

        if isinstance(a, A): #<-- if a is instance of base class, do copying
            self.a = a.a

        self.b = 2


a = genA()
a.a = 5
b = B(a)

# this works
print(b.a) # => 5
print(b.b) # => 2


似乎没有一种标准的方法可以做到这一点,但有几种方法。如果您不想处理每个单独的属性,我建议使用以下属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A(object):
    # Whatever

class B(A):
    def __init__(self, a):
        super(B, self).__init__()
        for attr in dir(a):
            setattr(self, attr, getattr(a, attr))
        # Any other specific attributes of class B can be set here

# Now, B can be instantiated this way:
a = A()
b = B(a)

如果您不想访问父级的"private"属性,可以添加

1
if not attr.startswith('__'):

for环路。