Adding attributes to an object - python

I am trying to find the order of a polynomial. I have created a method called "order" to set self.order to the order of the polynomial it is used on, ie polynomial1.order (p1.order). However, in order to add the order attribute so p1.order can work, I find I need to do p1.order() first. How can I remove this step to make it automatic?
Here is my code, do inform me if there are any other faux pas, I'm new to classes:
class Polynomial(object):
def __init__(self,*p_coeffs):
self.p_coeffs = list(p_coeffs)
def order(self):
self.order = len(self.p_coeffs)
p1 = Polynomial(2,0,4,-1,0,6)
p2 = Polynomial(-1,3,0,4.5)
p1.order() #<-- this step is the one I want to remove so I do not need to write it for every polynomial
print(p1.order)
Thanks in advance
EDIT: I need to keep my "order" method in the process

Simply perform all instance initialization that you'd like to automatically occur within the __init__() method.
class Polynomial(object):
def __init__(self,*p_coeffs):
self.p_coeffs = list(p_coeffs)
self.set_order()
def set_order(self):
self.order = len(self.p_coeffs)
p_list = [
Polynomial(2,0,4,-1,0,6),
Polynomial(-1,3,0,4.5),
]
for p in p_list:
print(p.order)
Output:
$ python test.py
6
4

Related

Calculate attributes with subclass parameters

I'm working in small Python program with several classes and subclasses. The main point is that I need to calculate the value of the main class with the attributes of the subclasses.
class Product:
class Extra_1:
value = 5
base_value = 25
final_value = base_value + Extra1.value
The expected output for base_value it would be 30.
However I need to call this class from other file through an import, when I do that I'm not able to get the expected output (50) Instead of that I get 30. It seems like Python its not calculating the value with the formula.
import myprogram
myprogram.Product.Extra.value = 25
print(myprogram.Product.final_value) #Output = 30
I tried to create a function to calculate the final_value and assigning the return as value but I still have the same problem.
class Product:
class Extra_1:
value = 5
creates a class Product with an inner class Extra_1. Technically
a class is also an object, and a code like
base_value = 25
final_value = base_value + Product.Extra_1.value
references an attribute of an object Product and an attribute of a
an object Product.Extra_1. But usually classes are templates to create new objects. A code
x = Product()
y = Product()
creates (instantiates) two new objects of class Product. To achieve
what you want, you can define a special method named __init__ (instantiation automatically invokes this method)
and redesign your program to use instantiation. See
https://docs.python.org/3/tutorial/classes.html
Python Class-Level Variables
There are some things I don't understand. First of all, are Extra, Extra1 and Extra_1 the same subclass? Assuming this and that the last two lines of the first code are inside of the Product class, then this is the expected behavior. Remember that those are class level variables, and, as is, they are evaluated just once. No matter what you do with base_value after the second line got interpreted. And this is true also if you make an instance of the Product class, the class-level variable final_value will not change unless you change it directly.
So, if you still want to use the static subclass attribute base_value and the static class attribute value to calculate your final value (I don't know why) you have to make at least final_value an instance level attribute:
class Product:
class Extra_1:
value = 5
def __init__(self):
self.final_value = Product.base_value + Product.Extra_1.value
base_value = 25
This way, every new instance of Product will calculate its final_value according with the actual value of base_value and value.
import myprogram
#First Product instance will calculate its result with the original values
p1 = myprogram.Product()
#Changing the original value
myprogram.Product.Extra_1.value = 25
#After the modification, creating a new instance
p2 = myprogram.Product()
#This will print the original 30
print(p1.final_value)
#This, in the other hand, will print 50
print(p2.final_value)
Python documentation Class and Instance Variables

TypeError: __init__() missing 1 required positional argument: 'lists'

I created a class, something like below -
class child:
def __init__(self,lists):
self.myList = lists
def find_mean(self):
mean=np.mean(self.myList)
return mean
and when I create an onject something like below -
obj=child()
it gives the error -
TypeError: __init__() missing 1 required positional argument: 'lists'
if I create object like below then it works well -
obj=child([44,22,55)
or If I create the class like below -
class child:
def find_mean(self,myList):
mean=np.mean(myList)
return mean
and then I create the object like below -
obj=child()
then also it works well, however I need to make it in the way I explained in the very begining. Can you please help me understand this context?
In the first example, the __init__ method expects two parameters:
self is automatically filled in by Python.
lists is a parameter which you must give it. It will try to assign this value to a new variable called self.myList, and it won't know what value it is supposed to use if you don't give it one.
In the second example, you have not written an __init__ method. This means that Python creates its own default __init__ function which will not require any parameters. However, the find_mean method now requires you to give it a parameter instead.
When you say you want to create it in the way you explained at the beginning, this is actually impossible: the class requires a value, and you are not giving it one.
Therefore, it is hard for me to tell what you really want to do. However, one option might be that you want to create the class earlier, and then add a list to it later on. In this case, the code would look like this:
import numpy as np
class Child:
def __init__(self, lists=None):
self.myList = lists
def find_mean(self):
if self.myList is None:
return np.nan
mean = np.mean(self.myList)
return mean
This code allows you to create the object earlier, and add a list to it later. If you try to call find_mean without giving it a list, it will simply return nan:
child = Child()
print(child.find_mean()) # Returns `nan`
child.myList = [1, 2, 3]
print(child.find_mean()) # Returns `2`
the code you have at the top of your question defines a class called child, which has one attribute, lists, which is assigned at the time of instance creation in the __init__ method. This means that you must supply a list when creating an instance of child.
class child:
def __init__(self, lists):
self.myList = lists
def find_mean(self):
mean=np.mean(self.myList)
return mean
# works because a list is provided
obj = child([44,22,55])
# does not work because no list is given
obj = child() # TypeError
If you create the class like in your second example, __init__ is no longer being explicitly specified, and as such, the object has no attributes that must be assigned at instance creation:
class child:
def find_mean(self, myList):
mean=np.mean(myList)
return mean
# does not work because `child()` does not take any arguments
obj = child([44,22,55]) # TypeError
# works because no list is needed
obj = child()
The only way to both have the myList attribute, and not need to specify it at creation would be to assign a default value to it:
class child:
def find_mean(self,myList=None):
mean=np.mean(myList)
return mean
# now this will work
obj = child()
# as will this
obj = child([24, 35, 27])

python - how to share variables between two different instances

I have seen many posts that shows how to access constant value, by inheritance. that's not my case.
I would like to create two instances from two different modules, and be able to share information/variables between them.
two issues:
1. the classes "dont know" each other, because they are on different files, "import"ing them as modules does not help much in this case
2. how can "print_class" instance can access & change values of variable in "cal_class" instance ?
Please note, I am looking for a way to access value from one instance to another. (in my case, there is allot of information (excel tables) to pass between instances, passing parameters through the "main" function is not practical)
Here is my simplify problem:
cal_class_file.py
class cal_class:
def add(self,first,second)
self.result= first + second
print_class_file.py
class print_class:
def print_sum(self):
result_from_cal_class = ?? <=-# How to get the value from local_calculate.result?
print(result_from_cal_class)
main.py
import cal_class_file
import print_class_file
def main():
local_calculate = cal_class_file.cal_class() # create instance
local_print = print_class_file.print_class(); # create instance that reads values from "local_calculate" instance
local_calculate.add(5,6) # calculate addition
local_print.print_sum() # output: 11
local_calculate.add(4,5) # update values in "local_calculate" instance
local_print.print_sum() # output: 9
How can I get the current (Latest) value for "result_from_cal_class" ?
Pass the value in. You have it right there in your client code:
class print_class:
def print_sum(self, result_from_cal_class):
print(result_from_cal_class)
def main():
local_calculate = cal_class_file.cal_class() # create instance
local_print = print_class_file.print_class(); # create instance that reads values from "local_calculate" instance
local_calculate.add(5, 6) # calculate addition
local_print.print_sum(local_calculate.result) # output: 11
local_calculate.add(4, 5) # update values in "local_calculate" instance
local_print.print_sum(local_calculate.result) # output: 9
Output:
11
9
However, if you mean that your client does this:
def main():
# setup elided ...
# actually call to add is done in another function
local_calculate.add(5, 6) # calculate addition
# actually call to print_sum is done somewhere else:
local_print.print_sum() # output: 11
You could define print_class like this:
class print_class:
def __init__(self, calculator):
self.calculator = calculator
def print_sum(self):
print(self.calculator.result)
Then initialise it like this:
def main():
local_calculate = cal_class_file.cal_class() # create instance
local_print = print_class_file.print_class(local_calculate); # create instance that reads values from "local_calculate" instance
Be careful as this is a little like having a global variable: calculate does something, leaving a result, print picks up the last result.
If you have an unexpected call to calculate between the one you want and the print, you will get unexpected results.

What is the most efficient way to return multiple values from a class method in Python?

I have multiple classes with methods like the one below:
#property
def max_ill(self):
maxval = max(self.illarr)
maxpts = [idx for idx,val in enumerate(self.illarr) if val==maxval]
maxpts = [ self.roomgrid.ptsdict[pt].ptid for pt in maxpts ]
return {'data':maxval,"points":maxpts}
What I'd like to do is to split this property into two such that I can access the max_ill['data'] and max_ill['points'] as individual properties like .max_ill_data and .max_ill_points. This will aid in auto-code-compeletion and also free me from having to remember what each property returns. However, as you can see above, calling each property individually will result in some of the calculations being repeated.
So, is there an elegant (non-hacky) way that I can run the calculation just once and assign both values? I know that I could call a function within the def __init__ constructor function and set these values. But I don't foresee myself needing these values everytime I instantiate a class (hence the use of #property).
Is this a place where setter might be useful ?
One way of doing it is something known as lazy-property but that also has it's drawbacks in case your self.illarr could change over time. In short it would be something like this:
def max_ill(self):
# Helper function to create the needed values. Not to be used directly
maxval = max(self.illarr)
maxpts = [idx for idx,val in enumerate(self.illarr) if val==maxval]
maxpts = [ self.roomgrid.ptsdict[pt].ptid for pt in maxpts ]
# Save the calculated values as attributes
self._max_ill_data = maxval
self._max_ill_points = maxpts
#property
def max_ill_data(self):
try:
# Get the saved value (raises an AttributeError when not existing)
return self._max_ill_data
except AttributeError:
# We found None, so call the method that creates these and return it afterwards
self.max_ill()
return self._max_ill_data
#property
def max_ill_points(self):
try:
return self._max_ill_points
except AttributeError:
self.max_ill()
return self._max_ill_points
So the max_ill is responsible for calculating the values and the properties only return the saved value or if there is no such attribute call the function that creates these.
There are also some libraries that implement lazyproperties even with tied parameters so this is just to illustrate how they (could) simplified work or if you don't want to add dependencies.

Python: dynamically create methods based on other classes'

I've looked for quite a while but couldn't find a proper answer to my question:
I have a class containing methods which operate on arrays and I want dynamically create methods with a similar name in another class with a modified output.
I've got something like this so far, can anyone guide me ?
Thanks
Class A():
def__init__(self,array):
self.data = array
def method1(self,*args):
newarray = whatever(self.data,*args)
return newarray
def method2(self,*args):
newarray = whatever2(self.data,*args)
return newarray
I want to be able to use those methods to generate new ones in a more complex class, say:
class B(C): #inherits from C
def __init__(self,[arg1,array]):
#initialize from parent class
C.__init__(self,[arg1,array])
#create new methods for this class using same name
methodnames = [element for element in dir(A) if element[0] != '_']
for methodname in methodnames:
##following works but this is not the output I want here
#self.__dict__[methodname] = getattr(A(array),methodname)
#following doesn't work... at least not as I expect it to
#case1
#self.__dict__[methodname] = [arg1,getattr(A(array),methodname)]
#case2
self.__dict__[methodname] = list([arg1,getattr(A(array),methodname)])
a = array
#following returns a list of [arg1, method] but what I really want is [arg1,newarray]
C([arg1,array]).method1(*args)
OK, so let's try to be clearer:
Class A contains filters, takes an array and applies filter as method, returns filtered data.
Class filters()
def__init__(self,array):
self.data = array
def filter1(self,*args):
newarray = median(self.data,*args)
return newarray
def filter2(self,*args):
newarray = gaussian(self.data,*args)
return newarray
...
In another module, I have class SpecialData, which operates on a list of x,y data (where x and y are iterables, i.e. lists, arrays...). So something like
Class SpecialData():
def __init__(self,[x,y]):
self.data = [x,y]
def power(self,power):
ypow = self.data[1]**power
return [x,pow]
def porod(self):
return [x**4,x**4*y]
....
Now, what I want is to add the filter methods contained in class filters to class SpecialData.
I could, of course do this by re-coding all filters with proper format for SpecialClass. but what I really want, is that each time a new filter is added to class filters, to make it available at runtime in class SpecialData without having to re-hard code the new filter.
So, not being very clever, I tried to read the list of available filters in class filters by:
import filters
filternames = [element for element in dir(filters) if element[0] != '_']
for fitlername in filternames:
generate_filters_in_class_SpecialClass
How do I do this properly ?
I found a number of posts related to this, some using super(), others using SpecialData.dict or even setattr. Since the 2nd seemed more understandable to me, I focused on this one and came up with:
import filters
Class SpecialData():
def __init__(self,[x,y]):
self.data = [x,y]
filternames = [element for element in dir(filters) if element[0] != '_']
for fitlername in filternames:
self.__dict__[fitlername ] = [self.data[0],getattr(filters(self.data[1]),fitlername)]
Of course, this doesn't work, because the list is not callable. If I change the last line to :
self.dict[fitlername ] = list([self.data[0],getattr(filters(self.data[1]),fitlername)])
it returns the method as the 2nd element, rather than the result.
Note that the following works, but this is not what I want...
self.dict[fitlername ] = getattr(filters(self.data[1]),fitlername)
Hope this is clearer now...
I think you are trying to make an advanced use of Python without using/knowing its advanced features, like you are borrowing techniques from another language.
This is not a criticism, but you should have a look on Python tutorial, Python introspection or metaclasses.
I think that if you just complete your knowledge on Python functions you will be easily able to solve your problem in a much simpler way.
Rather than generating a proposed solution, you should make it clearer what you are trying to achieve. Class A is a clear example of the starting point; please post an example of your desired ending point, e.g.
Class B():
def__init__(self,array):
self.data = array
def method1(self,*args):
newarray = ComplexWhatever(self.data,*args)
return newarray
def method2(self,*args):
newarray = EvenBiggerWhatever2(self.data,*args)
return newarray
a = A(input_array)
b = B(input_array)
print(a.method1(args))
print(b.method1(args))
What isn't clear is how you want to "dynamically generate" the new function "ComplexWhatever()" instead of writing the function by hand.

Categories