Not sure what I am doing wrong here when trying to initiate instance of object and set a name to the instance...
class Person:
def Person(self, name):
def __init__(self, name):
self.name = name
m = Person.Person('James')
m.name
Any help with an explanation?
I've personally not encountered a situation where the init function is nested beneath a parent function...
The problem here is correlated to the function definition. Basically, you are calling Person function that define but doesn't call the init one. So, you can solve like that:
class Person:
def __init__(self, name):
self.name = name
m = Person('James')
m.name
Related
I am currently learning how to program in Python I am stuck calling an attribute from a Parent class. In the example below, how can I call the attribute "name" on "daisy" to print the name. I always get an error "'Mammal' object has no attribute 'name'.
class Vertebrate:
spinal_cord = True
def __init__(self, name):
self.name = name
class Mammal(Vertebrate):
def __init__(self, name, animal_type):
self.animal_type = animal_type
self.temperature_regulation = True
daisy = Mammal('Daisy', 'dog')
print(daisy.name)
here I want to print the name which has been defined in the Vertebrate class, but I always get an error
"'Mammal' object has no attribute 'name'"
You need to call super in the __init__ of Mammal, like this:
class Mammal(Vertebrate):
def __init__(self, name, animal_type):
super().__init__(name)
self.animal_type = animal_type
self.temperature_regulation = True
When __init__ of Mammal is called, it doesn't automatically call the __init__ of it's parent class, that's what super does here.
When you assign an init function to the child class, it overrides the default init function of parent class being called. In such a case you need to explicitly call the parent class using the super function. You also need to assign the class Vertebrate to be a child of the class Object to be able to access all of the object's modules within it.
class Vertebrate(object):
def __init__(self, name):
self.name = name
spinal_cord = True
class Mammal(Vertebrate):
def __init__(self, name, animal_type):
super(Mammal, self).__init__(name)
self.animal_type = animal_type
self.temperature_regulation = True
animal = Mammal("Daisy", "dog")
print animal.name
I have a class inside a class like this:
class Robot(object):
def __init__(self):
self.name = 'ganken'
class Speaker(object):
pass
Let’s say I want to access Robot.name from Speaker, how do I do that
You can make Speaker a sub class of Robot:
class Robot(object):
def __init__(self):
self.name = 'ganken'
class Speaker(Robot):
def get_name(self):
return self.name
When you make an instance of Speaker, it will now have the name ganken associated with it.
s = Speaker
s.get_name()
Output:
'ganken'
You could have also called s.name and it would have still returned 'ganken', but usually you want to define functions in your class to get and set different attributes of your class (look up getters and setters if you want more information).
I might have misunderstood your question. If you want to access the name of a instance of a Robot class in your Speaker class (and don't necessarily want to make Speaker a subclass of Robot), you could define your class as:
class Robot(object):
def __init__(self):
self.name = 'ganken'
class Speaker(object):
def get_robot_name(self, robot):
return robot.name
Notice that you can pass a robot instance into the get_robot_name function in this example.
Demo:
r = Robot()
s = Speaker()
s.get_robot_name(r)
'ganken'
You could try the following where you create a speaker object in the Robot class if you are looking for a nested class solution. But i don't know what is the reason for you to do this though.
Try this assuming Python3 environment:
class Robot(object):
def __init__(self):
self.name = 'ganken'
self.speaker = self.createSpeaker()
def createSpeaker(self):
return Robot.Speaker(self)
class Speaker:
def __init__(self,robot):
self.robot = robot
def say_name(self):
return f'Name: {self.robot.name}'
robot = Robot()
print(robot.speaker.say_name())
Try the below:
print(Robot().name)
Just call it then access it
Output is:
ganken
I am trying to print a string variable returned by name() function, which in this case should print "Jim, but Python is printing
`<bound method Human.name of <__main__.Human object at 0x7f9a18e2aed0>>`
Below is the code.
class Human:
def __init__(self):
name = None
def setName(self, _name):
name = _name
def name(self):
return self.name
jim = Human()
jim.setName("Jim")
print(jim.name())
UPDATE:
After reading the answers, i updated the code as shown below, but, now i am getting a new error TypeError: 'str' object is not callable
class Human:
def __init__(self):
self.name = None
def setName(self, _name):
self.name = _name
def name(self):
return self.name
jim = Human()
jim.setName("Jim")
print(jim.name())
self.name is the method itself. You have no attributes storing the name. Nowhere do you actually set the name as an attribute. The following works:
class Human:
def __init__(self):
self.name = None
def setName(self, _name):
self.name = _name
# NOTE: There is no more name method here!
Now you have an actual attribute, and you don't need to call the method here:
jim = Human()
jim.setName("Jim")
print(jim.name) # directly using the attribute
You could even just set the attribute directly:
jim = Human()
jim.name = "Jim"
print(jim.name)
Alternatively, use self._name to store the name on the instance:
class Human:
_name = None
def setName(self, _name):
self._name = _name
def name(self):
return self._name
Here we used a class attribute Human._name as a default, and only set self._name on the instance in the Human.setName() method.
The problem is that name is the name of the internal variable in your object and also the name of the method.
The namespace for variables and methods is the same. Change the name of your method to something other than name. This will fix your getter. On first glance I thought that that would be all you have to do, but the recommendation in Martijn's answer also applies -- you need to assign to self.name and not just name in order to get your setter to work as well.
As an aside, this getter/setter pattern is not usually appropriate for Python. You should ask yourself why you want to use a getter/setter pattern over simply accessing the object's variable directly. See the section on getters and setters in this article for more detail.
You can use setter and getter properties instead of your custom defined methods.
class Human():
def __init__(self):
self._name = None
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
And then, use them:
jim = Human()
jim.name = "Jim"
print(jim.name)
I have a Category class which has different names for each categories, the names of the categories can be unknown, good and bad, all categories share the same behavior so i don't want to create sub classes for each type of category, the problem comes when i am trying to
create the different categories in this way:
Category.GOOD
This statement should return a category object with his name setting to 'good' so i try
the following:
class Category(object):
def __init__(self, name):
self.name = name
#property
def GOOD(self):
category = Category(name='good')
return category
#property
def BAD(self):
category = Category(name='bad')
return category
Then i created and use the category with the following output:
c = Category.GOOD
c.name
AttributeError: 'property' object has no attribute 'name'
Realizing that this doesn't work i try a java like approach:
class Category(object):
GOOD = Category(name='good')
BAD = Category(name='bad')
def __init__(self, name):
self.name = name
What i get here is a undefined name "Category" error, so my question is if there is a pythonic way to create a category object like this.
You probably want to use classmethods:
class Category(object):
#classmethod
def GOOD(cls):
category = cls(name='GOOD')
return category
Now you can do c = Category.GOOD().
You cannot do this with a property; you either have to use a classmethod, or create your own descriptor for that:
class classproperty(property):
def __get__(self, inst, cls):
return self.fget(cls)
I'm abusing the property decorator here; it implements __set__ and __del__ as well, but we can just ignore those here for convenience sake.
Then use that instead of property:
class Category(object):
def __init__(self, name):
self.name = name
#classproperty
def GOOD(cls):
return cls(name='good')
#classproperty
def BAD(cls):
return cls(name='bad')
Now accessing Category.GOOD works:
>>> Category.GOOD
<__main__.Category object at 0x10f49df50>
>>> Category.GOOD.name
'good'
I'd use module variables for this. Consider you have the module category.py:
class Category(object):
# stuff...
now you put the two global objects in it:
GOOD = Category(name='good')
BAD = Category(name='bad')
You can use it like that:
from path.to.category import GOOD, BAD
I don't say that this is pythonic but I think this approach is elegant.
The main point that you could not use class definition inside that class definition itself. So the most straight way to achieve what you are want is to use class/static methods as shown below, or even package constants.
class Category(object):
def __init__(self, name):
self.name = name
#classmethod
def GOOD(cls):
return Category(name='good')
#classmethod
def BAD(cls):
return Category(name='bad')
print Category.GOOD().name
or
class Category(object):
def __init__(self, name):
self.name = name
#staticmethod
def GOOD():
return Category(name='good')
#staticmethod
def BAD():
return Category(name='bad')
print Category.GOOD().name
I'm having trouble with my code. I'm trying to create a subclass which inherits the parent class's attributes and methods but it doesn't work. Here's what I have so far:
class Employee(object):
def __init__(self, emp, name, seat):
self.emp = emp
self.name = name
self.seat = seat
Something is wrong with the block of code below - the subclass.
Do I have to create the __init__ again? And how do I create a new attribute for the subclass. From reading questions, it sounds like __init__ in the subclass will override the parent class - is that true if I call it to define another attribute?
class Manager(Employee):
def __init__(self, reports):
self.reports = reports
reports = []
reports.append(self.name) #getting an error that name isn't an attribute. Why?
def totalreports(self):
return reports
I want the names from the Employee class to be in the reports list.
For example, if I have:
emp_1 = Employee('345', 'Big Bird', '22 A')
emp_2 = Employee('234', 'Bert Ernie', '21 B')
mgr_3 = Manager('212', 'Count Dracula', '10 C')
print mgr_3.totalreports()
I want reports = ['Big Bird', 'Bert Ernie'] but it doesn't work
You never called the parent class's __init__ function, which is where those attributes are defined:
class Manager(Employee):
def __init__(self, reports):
super(Manager, self).__init__()
self.reports = reports
To do this, you'd have to modify the Employee class's __init__ function and give the parameters default values:
class Employee(object):
def __init__(self, emp=None, name=None, seat=None):
self.emp = emp
self.name = name
self.seat = seat
Also, this code will not work at all:
def totalreports(self):
return reports
reports's scope is only within the __init__ function, so it will be undefined. You'd have to use self.reports instead of reports.
As for your final question, your structure won't really allow you to do this nicely. I would create a third class to handle employees and managers:
class Business(object):
def __init__(self, name):
self.name = name
self.employees = []
self.managers = []
def employee_names(self);
return [employee.name for employee in self.employees]
You'd have to add employees to the business by appending them to the appropriate list objects.
You need to run the superclass's init() in the appropriate place, plus capture the (unknown to the subclass) arguments and pass them up:
class Manager(Employee):
def __init__(self, reports, *args, **kwargs):
self.reports = reports
reports = []
super(Manager, self).__init__(*args, **kwargs)
reports.append(self.name) #getting an error that name isn't an attribute. Why?