Python Subclass Attribute Error - python

During a lecture today we began to do work with subclasses within Python. As an example, we were given code resembling a very basic social network which is as follows:
class socialNetwork:
class node:
def __init__(self, name, friendList):
self.name=name
self.friendList=friendList
def __init__(self):
self.nodeList=[]
def addPerson(self, name, friendList):
person=self.node(name,friendList)
self.nodeList.append(person)
s = socialNetwork()
s.addPerson("John",["Alice","Bob"])
s.addPerson("Alice",["John","Bob","Jeff"])
s.addPerson("Bob",["John","Alice","Jeff","Ken"])
s.addPerson("Jeff",["Alice","Bob","Barbra"])
s.addPerson("Ken",["Bob","Barbra"])
s.addPerson("Barbra",["Jeff","Ken"])
for person in s.nodeList:
print("name: ",person.name, "\n\t friends: ",person.friendList)
However, whenever I attempt to run this, I receive the following message:
Traceback (most recent call last):
** IDLE Internal Exception:
File "C:\Users\Mike\AppData\Local\Programs\Python\Python36-
32\lib\idlelib\run.py", line 460, in runcode
exec(code, self.locals)
File "C:/Users/Mike/AppData/Local/Programs/Python/Python36-32/run.py",
line 15, in <module>
s.addPerson("John",["Alice","Bob"])
AttributeError: 'socialNetwork' object has no attribute 'addPerson'
Simply put, I have no idea why I am encountering this error, especially after the professor ran the same code just fine. Am I missing something here, and if so could someone please point it out?

Your class doesn't have addPerson method, because your class is indented wrong way. It should look like this:
class socialNetwork:
class node:
def __init__(self, name, friendList):
self.name=name
self.friendList=friendList
def __init__(self):
self.nodeList=[]
def addPerson(self, name, friendList):
person=self.node(name,friendList)
self.nodeList.append(person)
Indentation does matter in python. A clue that something is wrong would be you having two __init__ methods at the same level.

You haven't defined any subclasses. Inheritance is specified in Python by putting the parent class(es) in parenthesis, e.g.:
class Node:
pass
class Leaf(Node):
# Leaf is a subclass of Node
pass
"Network" and "Node" don't really make sense to be subclasses, but one should be composed of the other.
What you've done is define a class socialNetwork with one attribute, a class called node. That's why you get an AttributeError, because there is no addPerson attribute in socialNetwork.

Firstly, node is not a subclass of socialNetwork but a class nested within the latter.
Secondly, socialNetwork actually has no attribute addPerson, but socialNetwork.node does.

Related

Python: calling overriden base class method in base class init [duplicate]

This question already has an answer here:
I can't get super() to work in python 2.7
(1 answer)
Closed 8 years ago.
Consider the following classes, running python2.7:
class S(object):
def __init__(self):
print 'Si'
self.reset()
def reset(self):
print 'Sr'
self.a=0
class U1(S):
def reset(self):
print 'U1r'
self.b=0
super(S,self).reset()
The desired functionality is that
creating an instance of the base class calls its reset method;
creating an instance of the derived class calls its reset method, and also invokes the base class's reset method.
I get (1):
>>> print S().a
Si
Sr
0
but not (2):
>>> print U1().b
Si
U1r
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "tt.py", line 4, in __init__
self.reset()
File "tt.py", line 14, in reset
super(S,self).reset()
AttributeError: 'super' object has no attribute 'reset'
What's the cleanest way to get what I want? I presume the error has something to do with the order in which class membership is getting constructed, but I can't figure it out from the documentation. . .
You should be calling super(U1, self).reset() in U1.reset(). When you use super, you should always pass the name of the current class as the first argument, not the name of the parent class. As stated in the docs:
super(type[, object-or-type])
Return a proxy object that delegates method calls to a parent or sibling class of type
super will look up the method on the parent or sibling of the type you provide. When you provide the parent class, it will try to find implementations of reset on parents/siblings of the parent, which will fail.
Should be:
super(U1, self).reset()
In my head, I read "super(U1,..." as "parent of U1" to keep it straight.

Python: how to automatically create an instance in another class

In writing a Python (2.5) program, I tried to create a class and, in its __init__ function, automatically create an instance of another class with its name as an argument to the __init__ function, something like this:
class Class1:
def __init__(self,attribute):
self.attribute1=attribute
class Class2:
def __init__(self,instanceName):
#any of Class2's attributes
exec instanceName + '=Class1('attribute1')'
# this should produce an instance of Class1 whose name is instanceName
But when I make an instance of Class2, instance=Class2('instance2'), and try to get attribute1 of instance2 (which should have been created from Class2's __init__ function) I get an error message:
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
print instance2.attribute1
NameError: name 'instance2' is not defined
I don't know what the problem is, since name='instance3' and
exec name+'=Class1('attribute1') does work, though this is probably because I don't have much experience with Python. How would I be able to do something like this automatically when an instance is created?
I have to run, so hopefully, someone else can fix any mistakes in this post:
class Class1:
def __init__(self, attribute):
self.attribute1 = attribute
class Class2:
def __init__(self, instanceName):
setattr(self, instanceName, Class1(...)) # replace ... with whatever parameters you want

How can I get child classes to use parent variables without redefining them?

Long time reader, first time asker. Anyway, Here's the code I'm working with:
class Person(object):
def __init__(self, s):
self.name = s
self.secret = 'I HAVE THE COOKIES'
#classmethod
def shout(self):
print self.name.upper()
class Kid(Person):
def __init__(self, s):
super(Kid,self).__init__(s)
self.age = 12
b = Person('Bob')
k = Kid('Bobby')
print b.name
print k.name
print k.age
print k.secret
k.shout()
Which results in this output and error:
Bob
Bobby
12
I HAVE THE COOKIES
Traceback (most recent call last):
File "a.py", line 22, in <module>
k.shout()
File "a.py", line 8, in shout
print self.name.upper()
AttributeError: type object 'Kid' has no attribute 'name'
I assumed that Kid would be able to use the Person's shout method substituting its (the kid's) "self" for parent (where the method lives). Apparently, that's not the case. I know I could declare name outside of init, but that's both unable to accomodate inputted data and a no-no. Another alternative would be to redefine shout for every child of Person, but that's a lot of repeated code that I'm trying to avoid.
Thanks very much in advance!
The issue is that #classmethod is a method on a class. It does not have access to an instance's attributes. Specifically the method is actually passed the class object, thus self is misnamed. You should really call shout's argument cls. If you remove the #classmethod then this would all make sense and your code would work as expected.
As it is, you can think of k.shout() as equivalent to Kid.shout().

Error: "x instance has no attribute y" when trying to inherit from class

I can't really understand what I'm doing wrong, since when I try it in "small scale" and it is working there.
I have a class named Play()
I goes like this:
class Play():
def __init__(self):
file = open("/home/trufa/Desktop/test", "r")
self.word = random.choice(file.readlines()).rstrip()
self.errAllowed = 7
self.errMade = 0
self.errList = []
self.cheatsAllowed = 2##chetas not incrementing
self.cheatsMade =0
self.wordList = ["*"]*len(self.word) ##this one is the one I want to have available in another class
...
Then I have another class called Score()
class Score(Play):
def __init__(self):
self.initialScore = 0
def letterGuess(self):
self.initialScore += 1
return self.errList
...
I instantiated both:
game = Play()
points = Score()
And if I do:
print points.letterGuess()
It gives me an error:
Traceback (most recent call last):
File "/home/trufa/workspace/hangpy/src/v2.py", line 188, in <module>
startGame()
File "/home/trufa/workspace/hangpy/src/v2.py", line 134, in startGame
print points.letterGuess()
File "/home/trufa/workspace/hangpy/src/v2.py", line 79, in letterGuess
return self.errList
AttributeError: Score instance has no attribute 'errList'
I don't understand why since I can do this without any trouble:
class One():
def __init__(self):
self.list= [1,2]
class Two(One):
def meth(self):
return self.list
uan = One()
tu = Two()
print uan.list
print tu.meth() ## Both output [1,2]
I'm very new to OOP so I could be doing all kinds of silly mistakes but I can't figure out where!
I think I have posted all the relevant code, but I you think the error might be elsewhere, I can provide it.
As I said I'm very new, so this might have nothing to do with inheritance I just think it called that when you get "something" from within another class (you must be shouting at the screen by now)
You overwrite the original __init__, which is then never called and doesn't initialize the members. You must call the parent's __init__ separately, usually with this snippet:
def __init__(self):
super(Score, self).__init__()
See the docs for super() for details. However, super() only works for so-called new-style classes. You must therefore either change the definition of Play to inherit from object:
class Play(object)
or you call the parent's method directly:
def __init__(self):
Play.__init__(self)
When you inherit from the class Play, you automatically get the attributes that you've created in the definition of Play, but you don't get the attributes that you've created in Play.__init__. You have to explicitly call it like so:
class Score(Play):
def __init__(self):
Play.__init__(self)
self.initialScore = 0
See Boldewyn's suggestion for using super to do this; but IMO you should probably get used to the basic way inheritance works before fiddling with super.
To further clarify, if you don't override __init__ as you have in this case, then it's inherited and called automatically.
You forgot to initialize the superclass.
class Score(Play):
def __init__(self):
super(Score, self).__init__()
self.initialScore = 0

How do you alias a python class to have another name without using inheritance?

If I have a python class, how can I alias that class-name into another class-name and retain all it's methods and class members and instance members? Is this possible without using inheritance?
e.g. I have a class like:
class MyReallyBigClassNameWhichIHateToType:
def __init__(self):
<blah>
[...]
I'm creating an interactive console session where I don't want my users' fingers to fall off while instantiating the class in the interactive sessions, so I want to alias that really long class name to something tiny like 'C'. Is there an easy way to do this without inheritance?
C = MyReallyBigClassNameWhichIHateToType
Also, if you're importing the name from another module...
from modulename import ReallyLongNameWhichIHateToType as FriendlyName
You can simply do:
ShortName = MyReallyBigClassNameWhichIHateToType
A class in Python is just an object like any other, and can have more than one name.
Refactor the name, no reason it should have a name that long.
Otherwise whateverName = VeryLongClassName should do the trick.
Simple name assignment approach works but has one disadvantage that might be important in some cases: the alias name will be the same as the name of the "base" class because of the __name__ property.
class C(object):
pass
D = C
print(C.__name__) # 'C'
print(D.__name__) # 'C' again
For example, if you create custom exception and then another one that assigning the first one you will get the name of this "parent" exception every time no matter which one of them you raise and this should probably confuse a user:
class CustomBaseException(Exception):
def __init__(self, operation):
super(CustomBaseException, self).__init__()
self.operation = operation
def __str__(self):
return f"Invalid operation '{self.operation}'"
OperationException = CustomBaseException
raise OperationException('readd')
output:
Traceback (most recent call last):
File "<input>", line 12, in <module>
CustomBaseException: Invalid operation 'readd'
So a solution would be to actually subclass the class:
class CustomBaseException(Exception):
def __init__(self, operation):
super(CustomBaseException, self).__init__()
self.operation = operation
def __str__(self):
return f"Invalid operation '{self.operation}'"
class OperationException(CustomBaseException):
pass
raise OperationException('delite')
output:
Traceback (most recent call last):
File "<input>", line 14, in <module>
OperationException: Invalid operation 'delite'

Categories