如果在类的初始化中尚未存在,则仅声明变量

时间:2016-10-21 14:23:02

标签: python class

我第一次在python项目中使用OOP工作。我有3个班级:PRA,GDB和XLS。

PRA = Main Class
GDB = Responsible for control databases
XLS = Responsible for control xls(x)
UserInput = Responsible for validate user input

我是怎么做的:

PRA:

class PRA(GDB, XLS, UserInput):

    __init__():
      self.gdb_file, self.xls_file = self.ask_questions() # <--- ask_questions is inside the UserInput class.
      self.do_something()

XLS:

class XLS:

  do_something():
    print(self.xls_file)

  __init__(self, xls_file):
     self.xls_file = xls_file

GDB:

class GDB:

  __init__(self, gdb_file):
     self.gdb_file = gdb_file

我想知道在PRA中初始化gdb_file和xls_file是不好的做法。 init ,如果没有,我怎样才能运行self.xls_file和self.xls_gdb的初始化只在PRA?

2 个答案:

答案 0 :(得分:0)

这不是一个真正的答案,而是更多的代码重用示例。不过,我不确定这是不是超级Pythonic。无论如何,看看这个例子:

import inspect

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

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

class C(A, B):
    def __init__(self):
        for super_class in inspect.getmro(type(self))[1:]:
            super_class.__init__(self)

c = C()
print(c.a, c.b)

答案 1 :(得分:0)

有点旧,但你可能想对你的班级名单三思而后行......他们真的太可怕了。

现在wrt /你的问题......从技术上讲,处理父类正确初始化的方法是从子类中调用它的初始化,即:

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

class Child(Parent):
    def __init__(self, name, age):
        super(Child, self).__init__(name)
        self.age = age

您还可以明确命名父类,即:

class Child(Parent):
    def __init__(self, name, age):
        Parent.__init__(self, name)
        self.age = age

但它有一些缺点,比如在调用中对父类进行编码(如果你改变父类,你有两个或更多的地方可以编辑),更重要的是,没有正确解决“钻石“多重遗传问题(即B&C的D儿童,A的B儿童,A的C儿童)。

实际上,使用super()的唯一原因是父类构造函数不兼容,但这是一种巨大的设计气味 - 如果你有两个或多个不兼容的父类,那么你肯定不会以正确的方式使用继承。在您的示例中实际情况就是这样:您的“主”类“不是”“数据库控制器”,而是使用数据库控制器,因此您希望使用合成而不是继承

class ServiceA(object):
    # code here

class ServiceB(object):
    # code here

class Main(object):
    def __init__(self, arg1, arg2, arg3):
        self.arg1 = arg1  
        self.service_a = ServiceA(arg2)
        self.service_b = ServiceB(arg3)

    def run(self):
        something = self.service_a.ask(question)
        self.service_b.do_something_with(something)

此外,您可能希望避免构造函数中的用户交互和代价高昂的资源获取...更好地使用第一种情况的入口点方法(如app = MyApp(params); app.run()`)和延迟初始化第二种情况(等到你需要资源来获取它,使用私有属性作为缓存一个公共属性,在第一次访问时负责获取)。

[编辑]

有人建议基于内省的肮脏黑客,即:

import inspect

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

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

class C(A, B):
    def __init__(self):
        for super_class in inspect.getmro(type(self))[1:]:
            super_class.__init__(self)

c = C()
print(c.a, c.b)

绝对不是要做的事情。

如果您的所有父类都具有兼容的构造函数并正确使用super调用,那么您只需使用super代替:

class A(object):
    def __init__(self):
        super(A, self).__init__()
        self.a = "a"

class B(object):
    def __init__(self):
        super(B, self).__init__()
        self.b = "b"

class C(A, B):
    def __init__(self):
        super(C, self).__init__()
        self.c = "c"

c = C()
print c.a, c.b, c.c

这也通过以正确的顺序调用父类来处理“钻石继承”问题:

class D(C, A):
    def __init__(self):
        super(D, self).__init__()
        self.d = "d"

d = D()
print "d : ", d.a, d.b, d.c, d.d

请注意,除非只有一个父类是“正确的”类(带有状态),而所有其他类都是mixin类(只添加功能的无状态类),所以多重继承通常不是设计气味(同样作为一个维持地狱)。由于Python不使用静态类型,因此继承主要用于实现继承,并且在很多情况下,组合/委托(或者只是在OP情况下的简单组合)是比实现继承更好的解决方案。