问题
I have a base class, a bunch of subclasses, and for each of these subclasses, I have another set of sub-subclasses. For example:
class BaseClass(object):
def __init__(self):
with open(config.txt) as f
self.config_array = f.readlines()
class FirstOrderSubClass(BaseClass):
def __init__(self, name):
self.name = name
class SecondOrderSubClass(FirstOrderSubClass):
def __init__(self, name, version):
self.name = name
self.version = version
super(SecondOrderSubClass, self).__init__(self.name)
# needed to access self.config_array
print self.config_array
I need to get the __init__()
method of the SecondOrderSubClass
to make the following assignment: self.lines = self.config_array
.
EDIT: added line print self.config_array
. If I run the code I get:
TypeError: __getattr__() takes exactly 1 argument (2 given)
回答1:
You cannot access self.config_array
until BaseClass.__init__()
has run to set the attribute.
Either fix FirstOrderSubClass
to also invoke the base class __init__
or call it directly.
Fixing the FirstOrderSubClass
is probably the best way to do so:
class FirstOrderSubClass(BaseClass):
def __init__(self, name):
super(FirstOrderSubClass, self).__init__()
self.name = name
However, your __init__
method signatures do not match so you cannot rely on cooperative behaviour here; as soon as you add a mix-in class in the hierarchy, things can and probably will break. See *Python's super() is considered super! by Raymond Hettinger, or it's followup PyCon presentation to explain why you want your signatures to match.
Calling the BaseClass.__init__
unbound method directly (passing in self
explicitly) would also work:
class SecondOrderSubClass(FirstOrderSubClass):
def __init__(self, name, version):
super(SecondOrderSubClass, self).__init__(name)
self.version = version
BaseClass.__init__(self)
Note that there is no point in assigning to self.name
there if you are going to ask FirstOrderSubClass.__init__
to do the exact same thing.
The proper way to use super()
is for all your methods to at least accept all the same arguments. Since object.__init__()
never does, this means you need a sentinel class that does not use super()
; BaseClass
will do nicely here. You can use *args
and **kw
to capture any additional arguments and just ignore those to make cooperative subclassing work:
class BaseClass(object):
def __init__(self, *args, **kw):
with open(config.txt) as f
self.config_array = f.readlines()
class FirstOrderSubClass(BaseClass):
def __init__(self, name, *args, **kw):
super(FirstOrderSubClass, self).__init__(*args, **kw)
self.name = name
class SecondOrderSubClass(FirstOrderSubClass):
def __init__(self, name, version, *args, **kw):
super(SecondOrderSubClass, self).__init__(name, *args, **kw)
self.version = version
回答2:
You have to call the FirstOrderSubClass
super
method:
class BaseClass(object):
def __init__(self):
with open("config.example.txt",'w') as f:
f.write("Hello world")
with open("config.example.txt") as f:
self.config_array = f.readlines()
class FirstOrderSubClass(BaseClass):
def __init__(self, name):
super(FirstOrderSubClass,self).__init__()
self.name = name
class SecondOrderSubClass(FirstOrderSubClass):
def __init__(self, name, version):
self.name = name
self.version = version
super(SecondOrderSubClass, self).__init__(self.name)
# needed to access self.config_array
grandchild = SecondOrderSubClass("peter",2.0)
print grandchild.config_array
##>>>
##['Hello world']
来源:https://stackoverflow.com/questions/30501525/get-attribute-from-a-super-class-in-python