Accessing instance constructor argument within a method - python

Just a quick question, so i have a class named animal and when you create the class you can initialise it with a dogName.
class animal:
def __init__(self, dogName):
self._owner = ""
self._address = ""
def setOwnerDetails(self, name, address):
self._owner = name
self._address = address
def getDetails(self):
return self._owner, self._address
def getName(self):
return self.dogName
##Does not work, trying to access constructor argument.
So when you initialise the instance with a value, which is dogName and in this instance the Dogname is Lucy, how can i access this value within a method?
I know i can do this by creating a instance variable but is there any other way i can do it. The variable above understandable does not work but is there any other way?
dog1 = animal("Lucy")
dog1.setOwnerDetails("Thomas", "35 Trop")
result = dog1.getDetails()
print(dog1.getName()) # trying to print the dog Name that is in the constructor argument.
Any help will be appreciated, I might not have explained it well.

You need to set dog_name as an instance attribute in the constructor:
def __init__(self, dog_name):
self._owner = ""
self._address = ""
self.dog_name = dog_name
You will then be able to access the attribute in the methods using self.dog_name.
Aside: as #jonrsharpe mentions in the comments, you should change your variable name from dogName to dog_name for PEP-8 compliance.

Related

Prevent user of changing variable type in python

I have main class with a lot of attributes that are initially defined as an object of a Prop class. This Prop class has two attributes: its value and the options, which is a list of acceptable values for the attribute.
class Prop():
def __init__(self, value, *options):
self.value = value
self.options = options
class Main():
def __init__(self):
self._prop1 = Prop(None)
self._prop2 = Prop(None)
The first important thing here is that _propx has to be an instance variable, since I will create more than one instance of Main.
The values of a Prop instance can either be a string or an integer, but the problem with this code is that I have to be sure that the user will do something like main._prop1.value = 1 and not main._prop1 = 1 otherwise it would break my code when doing _prop1.options. I don't want to use traits, thus I decided to make each _propx instance a kind of property, but I'm talking about a lot of instances and I don't want to define each setter especially because they will be all the same.
I found two solutions to solve this problem, the first is by using the same setter to all properties:
class Main():
def __init__(self):
self._prop1 = Prop(None)
self._prop2 = Prop(None)
def set_prop(attr):
def set_value(self, value):
self.__dict__[attr].value = value
return set_value
prop1 = property(fset=set_prop('_prop1'))
prop2 = property(fset=set_prop('_prop2'))
The second is by using an auxiliary class and redefine its __set__:
class Aux():
def __set_name__(self, owner, name):
self.public_name = name
self.private_name = '_' + name
def __set__(self, obj, value):
print(self, obj, value, self.private_name)
obj.__dict__[self.private_name].value = value
class Main():
def __init__(self):
self._prop1 = Prop(None)
self._prop2 = Prop(None)
prop1 = Aux()
prop2 = Aux()
the first on seems cleaner, but I have to pass the private name of each variable and I have to write the setter in the Main which I don't like because I would it to be as clean as possible. By other hand, in the second I have to use an auxiliary class.
My question is: is there a way of defining the setter in the Prop class? The reason why I couldn't find a way of doing this is that the Aux.__set__ seems to work only when I create an Aux instance as a class variable (static variable). This is also why I have to create a private and a public variable for each property. Is there a way of using __set__ to an instance (non-static) variable?

How to access attribute of object from another object's method, which is one of attributes in Python?

I would like to know if it's possible, and if yes, how to access attribute(s) of a "super" class instance, when having composition implemented.
Example provided below is only to provide idea here and setup common ground on further explanations.
I want to have access to "id" attribute for an instance of MiniVan directly from object "door" (type DoorElement).
My Code
class Car:
def __init__(self, _id):
self.id = _id
class CarElement:
def __init__(self, name):
self.name = name
def get_car_id(self):
# Body which will access value of attribute "id"
return car_id
class MiniVan(Car):
def __init__(self, _id):
super(MiniVan, self).__init__(_id)
self.door = DoorElement('door')
self.engine = EngineElement('engine')
class DoorElement(CarElement):
def __init__(self, name):
super(DoorElement, self).__init__(name)
class EngineElement(CarElement):
def __init__(self, name):
super(EngineElement, self).__init__(name)
def main():
mini_van = MiniVan(123)
id_from_door = mini_van.door.get_car_id()
id_from_engine = mini_van.engine.get_car_id()
print(id_from_door) # Expected output 123
print(id_from_engine) # Expected output 123
if __name__ == '__main__':
main()
Expected:
Printed out twice "123"
What I've tried:
Passing required attribute during creating object
I know that I could just define init method with passing "car_id" but for some reasons I would love to avoid it if possible. If not, I would propably just go for it.
to set class attribute, and then call it from CarElement class within classmethod e.g.:
#classmethod
def get_id(cls):
return Car.id
But issue with this solution is that, I can have many child-classes for Car class (MiniVan, Truck, etc.) and I want have it still working.
Trying to use descriptor
def __get__(self, instance, owner):
return instance.id
But I could understand it wrong, and actually getter (as far as I understand clean code) should return instance of a class and not any attribute.
Additional Info
I will ALWAYS use CarElement (or child classes) instances as attributes of instance of Car (or child classes) instances - different usage will be treated as use-error
There can be a lot of different child classes of Car class, but always within inheritance way ( Car <- RacingCar(Car) <- FormulaOneCar(RacingCar) ) but no composition
In order for your code to work, you would have to initialize all CarElement-s with car_id. Currently, the error you are getting comes from lack of such a variable in the scope of the method. My idea of a change is this:
class CarElement:
def __init__(self, name, car_id):
self.name = name
self.car_id = car_id
def get_car_id(self):
# Body which will access value of attribute id
return self.car_id
I can't see any other magic way.

Unable to access the parent class member in base class in python

I am using python 3.4 and i am new in object oriented programming and want to access the parent class member in my child class. But it is not accessible. Can anyone help me to get rid of this?
# Base class members can be accessed in
# derived class using base class name.
# Parent or super class
class Company:
def BasicInfo(self):
self.CompanyName = "ABC Solutions"
self.Address = "XYZ"
# Inherited or child class
class Employee(Company):
# constructor
def __init__(self, Name):
print("Employee Name:", Name)
print("Company Name:", self.CompanyName)
def main():
# Create an object
emp01 = Employee("John")
if __name__ == "__main__":
main()
The below mentioned code is working but using the same concept, my code is not working, why? Can anyone explain me the reason.
class Room:
def __init__(self):
self.roomno = 0
self.rcap = 0
self.rooms = {}
self.nog = 10
def addRoom(self):
self.rcap = input("Please enter room capacity:\n")
self.rooms[self.roomno] = self.rcap
class Booking(Room):
def addBooking(self):
while int(self.nog) > int(self.rcap):
print("Guest count exceeds room capacity of: %d" % int(self.rcap))
x = Booking()
x.addRoom()
x.addBooking()
You're missing a call to the superclass' BasicInfo method:
def __init__(self, Name):
print("Employee Name:", Name)
super().BasicInfo()
# ^^Here^^
print("Company Name:", self.CompanyName)
You can replace super().BasicInfo() with a direct reference to the class obviously:
Company.BasicInfo(self)
In your second example, the subclass does not define a __init__ method, so it would inherit that from parent; as a result, the instance variables would be present in the child class.
Your base class method BasicInfo is never getting called. If you call it explicitly either in your child class's __init__, it would work
class Employee(Company):
# constructor
def __init__(self, Name):
super(Employee, self).BasicInfo()
print("Employee Name:", Name)
print("Company Name:", self.CompanyName)

python: instance attribute error

I get a dict to init a class person. there is one field in person: 'name'. 'name' field is optional, meaning that if the dict don't have the 'name' item, then there's no 'name' value of person. I use getter methods to get instance attribute, but it will throw a error if there's no 'name' value. I don't know is there any good programming style to improve my code? Because python create instance field at run time, I don't know how to use getter like java.
class Person:
def __init__(self,person_dict):
try:
self.name = person_dict['name']
except Exception:
pass
def getName(self):
return self.name
pdict = {}
p = Person(pdict)
print p.getName()
AttributeError: Person instance has no attribute 'name'
class Person:
def __init__(self,person_dict):
self.name = person_dict.get('name')
In this case self.name = person_dict.get('name') won't raise Exception and Person objects will have name attribute (None by default)
UPD. Because of getName method is useless, I cut it down from example. Access name attr directly.
class Person:
def __init__(self,person_dict):
self.name = person_dict.get('name', 'default_name')
pdict = {}
p = Person(pdict)
print p.name # there is no need for getter
If you don't want the exception, then you should make sure the instance has a value for name. Since lookup falls back to the class if an attribute can't be found on the instance, an easy way to do this is to simply add name = None (or whatever default value you want the instance to use) to the class definition. Assignment to the attribute on the instance will "hide" the default value.
class Person:
name = None
def __init__(self,person_dict):
try:
self.name = person_dict['name']
except Exception:
pass
You could instead write your __init__ like this:
def __init__(self,person_dict):
self.name = person_dict.get('name')
The get() method of dictionaries returns None if the key isn't found, or you can provide a second argument with a different default value.

TypeError in Python 3.x

I have no idea what is wrong! This is a very simple program and I have done a lot head banging! Please someone enlighten me!
This a lab problem from the CSE 111 - Programming Language II course. They teach Java at the university and the code I wrote in Java works fine.
I just have to create a Student class with some fields to hold the basic information about a student with methods to get and set the attributes. Then create an instance of that class and tryout the methods.
But every time I run this program the following error occurs:
TypeError: set_name() takes exactly 1 positional argument (2 given)
Here is the code I wrote.
class Student:
'''Student class'''
name = None
id = 0
address = None
cgpa = None
def get_name():
return name
def set_name(n):
name = n
def get_id():
return id
def set_id(i):
id = i
def get_address():
return address
def set_address(a):
address = a
def get_cgpa():
return cgpa
def set_cgpa(c):
cgpa = c
#An object of Student class
jack = Student()
jack.set_name('jacky')
print(jack.get_name())
You're not accepting a reference to your instance as the first argument to that method, i.e. your set_name() should be written:
def set_name(self, n):
self.name = n
This is somewhat different from other languages where there is a built-in keyword (such as this) that refers to the current object. Python passes that reference explicitly, as an argument to the method.
All your other methods must be modified similarly.
Note that just setting name = n sets a local variable name which goes away when the method ends; it does not set anything on the instance. You have to explicitly set self.name if you want an instance attribute.
Also, and this is a matter of style, but you do not usually write set and get methods in Python. It is normal practice to set and get attributes directly. If you want to do validation of values, use a property instead. So basically, none of your methods are actually necessary in good style.
However, you don't have an __init__() method. Usually you would pass the desired attributes of the instance when instantiating the class and save these on the instance.
class Student:
def __init__(self, name, id, address, cgpa):
self.name = name
self.id = id
self.address = address
self.cgpa = cgpa
herman = Student("Herman Munster", 12345, "1313 Mockingbird Lane", 4.0)
Try this:
import sys
class Student:
'''Student class'''
self.name = None
self.id = 0
self.address = None
self.cgpa = None
def get_name(self):
return self.name
def set_name(self, n):
self.name = n
def get_id(self):
return self.id
def set_id(self, i):
self.id = i
def get_address(self):
return self.address
def set_address(self, a):
self.address = a
def get_cgpa(self):
return self.cgpa
def set_cgpa(self, c):
self.cgpa = c
You need to pass self as the first argument to each member function of the class. Member variables must then be referred to with self, i.e. self.name. Furthermore, you may wish to include an __init__() function; this serves usually to initialize any member variables, and is called at the instantiation of the class.
Take a look at the Python documentation here for some examples on well-formed classes: http://docs.python.org/tutorial/classes.html#random-remarks
In Python, you need to pass in self for each of your member functions. You also need to reference class variables as self.x, if you want them to take an effect.
Here are a couple examples that you need to apply to the rest of your code.
def set_name(self, n):
self.name = n
def get_cgpa(self):
return self.cgpa
There is some explanation for why this is the case in the documentation.
This is because first argument of methods is self - the class instance.
See What is the purpose of self?
and http://docs.python.org/tutorial/classes.html#class-objects

Categories

Resources