Here is my program structure:
class parent(object):
def __init__(self): pass
def __post_init_stuff(self):
#post initialization stuff
class child(parent):
def __init__(self):
#dostuff
self.__post_init_stuff()
def otherfunc(classname, args):
classname(args)
otherfunc(child)
The problem that I'm having is that when otherstuff(child) executes, I get this error:
AttributeError: 'child' object has no attribute '_child__post_init_stuff'
Any advice?
Names that start with __ in Python are like protected in C++. You could name with only one underscore instead or access it as self._parent__post_init_func, since this is its mangled name within the scope. I recommend the first thing, since this is ugly and hacky.
Related
I have a Python module as follows:
# src/exec.py
class A:
def run(self, stuff):
b = B(stuff.x)
class B:
def __init__(self, x):
self.obj = self.create_some_obj()
I'm trying to test a part of class A independently, for which I need to replace the obj in B with a fake object. I'm doing this as follows:
# test/test_execs.py
import exec as ex
class FakeObjForB:
def __init__(self):
# some init
class TestClass:
#patch.object(ex.B, 'obj', FakeObjForB())
def test_with_fake_obj(self):
a = ex.A()
a.run()
# assert something about the state of a that depends on the b inside its run method
Running this test gives me the error: AttributeError: <class 'B'> does not have the attribute 'obj'. I tried replacing the line with the #patch decorator with #patch.object(ex.B, 'obj', FakeObjForB(), create=True). This, however, results in b.obj using the actual definition, and not FakeObjForB, which in turn leads to a false-failure in the assertion in test_with_fake_obj. Any clues about what I'm doing incorrectly here?
In your example you're patching the B class, that's the object passed as the first argument. That class doesn't declare obj attribute on the class level and so AttributeError is raised. When you provide create=True it won't complain as that argument allows the obj attribute to be dynamically created when needed/accessed. But, that won't ever happen as the very first "access" of that attribute is its actual creation - no dynamic mocking ever happened.
A solution is to actually patch the method whose returned value would be assigned to the obj attribute, like:
#patch.object(ex.B, 'create_some_obj', FakeObjForB())
self.assertFalse(b.__is_manual) AttributeError: 'BaseResource' object has no attribute '_Resources__is_manual'
My test_resources.py is
class Resources(TestCase):
def test_disable_manual_mode(self):
self.assertFalse(b.__is_manual)
if __name__=='__main__':
b = base.BaseResource()
unittest.main()
And My base.py is
class BaseResource(object):
def __init__(self, index=0, parent=None, **kwargs):
self.__is_manual = False
def disable_manual_mode(self):
self.__is_manual = False
Both are in same directory I want to import __is_manual in test_resouces.py
How do i do it.
I have tried b.__is_manual but it is giving error(mentioned above)
According to Python docs
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.
The instantiation of object must be inside the test class.
When naming the attribute to __is_manual, you are defining it as a "protected" attribute, and you can not access it. Simplify your code.
class BaseResource(object):
def __init__(self, index=0, parent=None, **kwargs):
self.is_manual = False
def disable_manual_mode(self):
self.is_manual = False
Also, the instantiation of object must be inside the test class.
class Resources(TestCase):
def test_disable_manual_mode(self):
b = base.BaseResource()
self.assertFalse(b.is_manual)
if __name__=='__main__':
unittest.main()
We can't access __is_manual. Because we can't access a variable starting with __ (double underscore).
I am new to python and asking very basic question. I am trying to understand multiple inheritance. I have two parent classes i.e Speciy and Living and one child class Bird but when i run the following program, i get error 'Bird' object has no attribute '_Living__house'.Please tell me what i am doing wrong
But when i use single inheritance i.e class Bird(Speciy) or class Bird(Living)it works fine. So only the error comes when i use multiple inheritence
class Speciy:
def __init__(self,legs=4,colour="White"):
self.__legs=legs
self.__colour=colour
def get_legs(self):
return self.__legs
def set_legs(self,legs):
self.__legs=legs
def get_colour(self):
return self.__colour
def set_colour(self,colour):
self.__colour=colour
class Living:
def __init__(self,house="city"):
self.__house=house
def get_house(self):
return self.__house
def set_house(self,house):
self.__house=house
class Bird(Speciy,Living):
def __init__(self,wings=2):
super().__init__()
super().__init__()
self.__wings=wings
def get_wings(self):
return self.__wings
def set_wings(self,wings):
self.__wings=wings
b1=Bird(4)
print(b1.get_wings())
b1.set_colour("Green")
print(b1.get_colour())
print(b1.get_house())
I have solved the issue my self using
Speciy.__init__(self,legs,colour)
Living.__init__(self,house)
I wrote the following code. When I try to run it as at the end of the file I get this stacktrace:
AttributeError: 'super' object has no attribute do_something
class Parent:
def __init__(self):
pass
def do_something(self, some_parameter, next_parameter):
if type(some_parameter) is not int:
raise AttributeError("Some message")
if type(next_parameter) is not int:
raise AttributeError("Some message")
class Child(Parent):
def __init__(self):
super(Parent).__init__()
def do_something(self, some_parameter, next_parameter):
super(Parent).do_something(some_parameter, next_parameter)
return some_parameter + next_parameter
object = Child()
object.do_something(2, 2)
How should I solve this and where did I the mistake in this simply inheritance sample?
You're passing the wrong argument to super. If you're going to pass arguments at all, they need to be the current class and instance, not the parent class you're expecting to call. Or assuming you're using Python 3, you can skip the arguments completely and the compiler will make it work for you anyway. Calling super with one argument is allowed, but it returns an "unbound super object" which is almost never useful.
Change your calls to use one of these styles:
class Child(Parent):
def __init__(self):
super().__init__() # no arguments is almost always best in Python 3
def do_something(self, some_parameter, next_parameter):
super(Child, self).do_something(some_parameter, next_parameter) # name the current class
return some_parameter + next_parameter
I'd also note that your type checks in Parent.do_something are rather awkward. Rather than type(some_parameter) is not int, use isinstance(some_parameter, int) (unless you deliberately want to exclude subtypes).
You have a few issues here. Firstly there was an indentation error for the parent do_something definition. This meant that it was defined as a function in and of itself, rather than being a method of the class Parent.
Secondly, class methods should usually have self as their first parameter, as when they are called, the object that they refer to is passed as the first variable.
Thirdly, when you call super() you do not need to specify what the super is, as that is inherent in the class definition for Child.
Below is a fixed version of your code which should perform as you expect.
class Parent:
def __init__(self):
pass
def do_something(self, some_parameter, next_parameter):
if type(some_parameter) is not int:
raise AttributeError("Some message")
if type(next_parameter) is not int:
raise AttributeError("Some message")
class Child(Parent):
def __init__(self):
super(Parent).__init__()
def do_something(self, some_parameter, next_parameter):
super().do_something(some_parameter, next_parameter)
return some_parameter + next_parameter
test = Child()
test.do_something(2, 2)
i want to call a method in an Instance by another new Instance like this:
class parentClass:
# Some methods here
class a:
def __init__(self, otherclass):
otherclass.__foo(a);
class b:
def __foo(self, firstclass):
#do something with firstclass
pClass = parentClass();
classB = pClass.b();
classA = pClass.a(classB);
But with this code i will get this kind of error:
AttributeError: b instance has no attribute '_a__foo'
I already tried to add this before method __foo():
#classmethod
But this still doesn't works.
Thanks for Help!
This is the simplest Solution:
Instead of
def __foo(self, firstclass):
i have to write
def foo(self, firstclass):
The double _ won't work here.
I will leave this Question & Answere at this place for other people with the same 'problem'.