I am studying classes in python programming in jupyter notebooks and google colab.
I don't understand the results with respect to this class.
class employee_constructor():
def __init__(self,name,surname,salary):
self.name=name
self.surname=surname
self.salary=salary
def increasesalary(self,percentage):
self.salary=self.salary*(1+percentage/100)
def displayEmployee(self):
print('this employee is {} and gets {} dollars'.format(emp1.name,emp1.salary))
now I try to print out results:
emp1=employee_constructor('jose','ferro',1000)
emp2=employee_constructor('manolo','rod','1500')
emp1.displayEmployee
print('before increase',emp1.salary)
emp1.increasesalary(5)
emp1.increasesalary(5)
print('after increase',emp1.salary)
print(emp1.salary)
# this line does not give error and does nothing:
emp1.increasesalary
print(emp1.salary)
# this line gives error:
# increasesalary() missing 1 required positional argument: 'percentage'
emp1.increasesalary()
I don't understand why running the method without the parenthesis would not cause any error (actually the method is not run) whereas with the parenthesis (and not passing the neccesary variable through an error)
secondly, how can I avoid such kind of errors? i.e. if the user passes nothing assume vale zero
note:
this question explains init method and was proposed as solution. My question is related but is not answered there
I don't understand why running the method without the parenthesis would not cause any error (actually the method is not run) whereas with the parenthesis (and not passing the neccesary variable through an error)
When you refer a method (function in the context of an object, self is passed implicitly) by object.method the method object is returned. But to actually execute the function you need to call it i.e. use the parentheses.
For fun, save the returned method object as a variable and call that instead, you'll see that you're doing the same thing as they refer to the same object.
Now, when you called emp1.increasesalary(), you didn't pass the required argument percentage leading to the error. Note again, the self (object itself) is passed implicitly.
how can I avoid such kind of errors? i.e. if the user passes nothing assume vale zero
Make the argument a keyword argument with a default value of 0:
def increasesalary(self, percentage=0):
self.salary = self.salary * (1 + percentage / 100)
you can always use a funtion (without parenthesis) in python:
def f():
pass
print(f)
this will not call the function but just print out its memory location. so a line containing the function f itself is a valid python statement; but it does not call the function.
then: you need to use self and not emp1 in your displayEmployee(self) method:
def displayEmployee(self):
print('this employee is {} and gets {} dollars'.format(self.name, self.salary))
better:
def __str__(self):
return f"this employee is {self.name} and gets {self.salary} dollars"
then you can
print(emp1)
Related
What is the difference between when we use a variable as an attribute like self.message and when we use it as a parameter like message in a method:
def talk(self, message)
print("{} sad : {}".format(self.name, self.message))
def talk(self, message)
print("{} sad : {}".format(self.name, message))
A parameter is really just a variable. It is declared by the function signature, and it gets assigned one of the arguments as part of the function call process.
An attribute is not a variable at all. It is a part of an object, similar to an index inside []. It is accessed using dot notation.
In your code, both functions declare a message parameter, but only the second one uses it. The first function gets all its information from the self object instead of using its message parameter.
lets consider the below mentioned example
class car():
def car_type(self,car_name):
return f'its an electric car and its a {car_name}'
instance=car()
print(instance.car_type('BMW'))
print(dir(car()))
print(dir(instance.car_type('hello')))
when you look closely to above mentioned code you will find that i have tried to access the directory of instance.car_type using this statement print(dir(instance.car_type('hello')))
and for instance if you remove the 'hello' from this statement it will thrown an error
TypeError: car_type() missing 1 required positional argument: 'car_name'
so in order to avoid this error i first tough it will take the same argument 'BMW' which i used earlier while calling the method of this class and error went away and when i tried changing 'BMW' argument with any random word for example 'hello' error went away but why that happened is still unknown to me.
and what surprised me most was that when i didn't gave any variable to my car_type function as mentioned below i was still able to access the directory of instance.car_type without any argument.
class car():
def car_type(self):
return 'its an electric car and its a'
instance=car()
print(instance.car_type())
print(dir(car()))
print(dir(instance.car_type()))
If you don't give argument, compiler won't be able to compile code.
car_name parameter: def car_type(self,car_name) needs its argument in calling method: instance.car_type(???)
Consider this simplified situation:
class Decoder:
def __str__(self):
return self.__bytes__().decode('ascii')
class Comment(Decoder, bytes):
def __bytes__(self):
return b'#' + self
Usage:
Comment(b'foo')
Prints:
b'foo'
Instead of expected:
#foo
Regardless of the order in Comment.mro() (i.e. I can swap Decoder and bytes in the supeclass list), Decoder.__str__() is never called.
What gives?
Comment(b'foo') calls Comment.__new__, which, not being defined, resolves to either Decoder.__new__ or bytes.__new__, depending on the order in which you list them in the definition of Comment.
The MRO for Comment is Comment, bytes, Decoder, object. However, the functions actually being called are:
Comment.__new__, to create a new object. Since that function isn't defined, we next call bytes.__new__, which is defined. It effectively just calls object.__new__(Comment, b'foo'), giving you your final object.
To display the return value of Comment, the interpreter tries to call Comment.__repr__, not Comment.__str__. Again, the function isn't defined, so it falls back to bytes.__repr__, giving the observed result.
If you use print function you get expected result, but if you look at result from console you see the result of __repr__ method. If you need it works in this way you can call self.__str__() from __repr__
>>msg = Comment(b'foo')
>>msg
b'foo'
>>print(msg) # or str(msg)
'#foo'
There you can read how it works docs
I have created the following constructor:
class Analysis:
def __init__(self, file_list, tot_col, tot_rows):
self.file_list = file_list
self.tot_col = tot_col
self.tot_rows = tot_rows
I then have the method full_analysis() call calc_total_rows() from the same file:
def full_analysis(self):
"""Currently runs all the analysis methods"""
print('Analysing file...\n' +
'----------------------------\n')
calc_total_rows()
From another file I am calling the full_analysis() however errors occur saying that calc_total_rows() is not defined, and the method is just below it.
I'm inexperienced with Python however I tried to rearrange the code and add 'self' in various places to no avail.
The other file does meet the requirements of the constructor, and if I remove the calc_total_rows() method, the print line runs. I however do not wish to call each method individually, and would like to call a single method which runs them all.
If calc_total_rows is an instance method as your question implies, then you need to call self.calc_total_rows() from within full_analysis. Unlike some other languages, Python does not have implicit instance references within method scope; you have to explicitly retrieve the member method from self.
I wish I had found this sooner.
In order to solve this, I had to use self in front of the method.
In my example:
def full_analysis(self):
"""Currently runs all the analysis methods"""
print('Analysing file...\n' +
'----------------------------\n')
self.calc_total_rows()
This works.
bit of an issue with a function I'm writing for adding and subtracting a value located within a class.
I'm trying to pass a value that I've read in from a csv to my add function. This value is a decimal value (e.g. 500.00) I've tried eliminating the trailing 0's to make it just 500, this didn't work either. I keep getting:
TypeError: add() takes exactly one argument (two given).
Even though I have a print statement confirming its only trying to pass in the 500.
Here's my function:
def add(amount):
self.total = self.total + amount
It's being called by v.add(i) Even if I set i to an arbitray integer value it still results in the same error. I am relatively inexperience with python, so perhaps there is something simple I'm missing here. Thanks.
class Myclass(object):
def __init__(self, total=0.):
self.total = total
def add(self, amount): # <= needs `self` parameter
self.total += amount
v = Myclass()
v.add(2.)
When you call an object method, it implicitly passes a reference to the object - so calling v.add(something) actually calls Myclass.add(v, something).
Voila - two parameters, when you told it to only expect one...
It sounds like you may have 2 issues:
the normal definition of a method presumes the 'self' argument
def add(self, amount):
you appear to be dealing with a string if you are trying to remove trailing zeros.
you may wish/need to convert the string value "500.00" to a floating point value
self.total = self.total + float(amount)
If you try to add a string to a number, Python will complain. You can see the type of an object being held in a variable using the type() function. E.g., you may wish to print the type of the 'amount' argument inside the add() method like this (for debugging):
print "the type of amount is", type(amount)
It will show you what you have (str, int, etc.)
(BTW it would probably be better style to convert it outside the method and have the method accept only numeric values for amount.)