Class Attributes VALUES to a list - python

I have a simple python class that consists of some attributes and some methods.What i need is to make a list out of the class attributes ( only ! )
Class A():
def __init__(self, a=50, b="ship"):
a = a
b = b
def method1():
.....
I want to have a list :
[50, "ship"]

Another solution, possibly more generic, is:
def asList(self):
[value for value in self.__dict__.values()]
Full example with correct syntax:
class A:
def __init__(self, a=50, b="ship"):
self.a = a
self.b = b
def as_list(self):
return [value for value in self.__dict__.values()]
a = A()
print a.as_list()
output:
[50, 'ship']

def asList(self):
return [a,b,....] # will create a new list on each call
Unless you also create an __init__(...) or factory methods or something alike for your class that decomposes this list you wont be able to create a new object back from the list.
See how-to-overload-init-method-based-on-argument-type

Related

How to get all values of variables in class?

class NiceClass():
some_value = SomeObject(...)
some_other_value = SomeOtherObject(...)
#classmethod
def get_all_vars(cls):
...
I want get_all_vars() to return [SomeObject(...), SomeOtherObject(...)], or more specifically, the values of the variables in cls.
Solutions tried that didn't work out for me:
return [cls.some_value, cls.some_other_value, ...] (requires listing the variable manually)
subclassing Enum then using list(cls) (requires using some_value.value to access the value elsewhere in the program, also type hinting would be a mess)
namedtuples (nope not touching that subject, heard it was much more complicated than Enum)
[value for key, value in vars(cls).items() if not callable(value) and not key.startswith("__")] (too hacky due to using vars(cls), also for some reason it also includes get_all_vars due to it being a classmethod)
There are two ways. This is a straight answer to your question:
class Foo:
pass
class Bar:
x: int = 1
y: str = 'hello'
z: Foo = Foo()
#classmethod
def get_all(cls):
xs = []
for name, value in vars(cls).items():
if not (name.startswith('__') or isinstance(value, classmethod)):
xs.append(value)
return xs
This is what I suggest:
from dataclasses import dataclass, fields
class Foo:
pass
#dataclass
class Bar:
x: int = 1
y: str = 'hello'
z: Foo = Foo()
#classmethod
def get_defaults(cls):
return [f.default for f in fields(cls)]
#classmethod
def get_all(cls):
return [getattr(cls, f.name) for f in fields(cls)]
results:
Bar.get_defaults() == Bar.get_all()
# True -> [1, 'hello', __main__.Foo]
Bar.x = 10
Bar.get_defaults() == Bar.get_all()
# False -> [1, 'hello', __main__.Foo] != [10, 'hello', __main__.Foo]
You can create a list of values and define individual attributes at the same time with minimal boilerplate.
class NiceClass():
(some_value,
some_other_value,
) = _all_values = [
SomeObject(...),
SomeOtherObject(...)
]
#classmethod
def get_all_vars(cls):
return cls._all_values
The most obvious drawback to this is that it's easy to get the order of names and values out of sync.
Ideally, you might like to do something like
class NiceClass:
_attributes = {
'some_value': SomeObject(...),
'some_other_value': SomeOtherObject(...)
}
#classmethod
def get_all_vars(cls):
return cls._attributes.values()
and have some way to "inject" the contents of _attributes into the class namespace directly. The simplest way to do this is with a mix-in class that defines __init_subclass__:
class AddAttributes:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.__dict__.update(cls._attributes)
class NiceClass(AddAttributes):
# As above
...
This might sound like a https://xyproblem.info/ but my solution might work in the other case as well. You can get the fields of an object by using __dict__ or vars (which is considered more pythonic given: Python dictionary from an object's fields)
You could do something like:
class ClassTest:
def __init__(self):
self.one = 1
self.two = 2
list(vars(ClassTest()).values())
But you will see that it has some limitations. It doesn't recognize the not in self.variable_name defined variables like you have used above. It might help you nonetheless, because you can simply define them in init.

Is there a way to pass a function call to an inner object?

Is there a way in python to pass a function call to an inner object, maybe through a decorator or wrapper? In the example below, class A holds a list of class B objects, and one of the class B objects is selected as the active object. I want class A to function as a passthrough, just identifying which of the class B objects that the call goes to. However, class A doesn't know what type of class it is going to hold beforehand, so I can't just add a set_var function to class A. It has to work for any generic function that class B has. It will only have one type of class in its objects list, so it could take class B as an input when it is instantiated and dynamically create functions, if that's a possibility. The client wouldn't know whether it's dealing with class A or class B. The code below is as far as I got.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, object):
self.objects.append(object)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
You could use the generic __getattr__ to delegate to the wrapped object.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, obj):
self.objects.append(obj)
self.current_object = obj
def __getattr__(self, name):
return getattr(self.current_object, name)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
print(b_obj2.var)
That will print "100".
You will still get an AttributeError if the wrapped object doesn't have the expected method.
It was interesting to look at this, it is intentionally rough but it does indeed allow you to call one the B instance's set_var methods.
The code below uses sets as a quick and dirty way to see the difference in callable methods, and if there is; it sets the attribute based on that name. Binding the method to the A instance.
This would only bind set_var once from the first object given.
def add_object(self, object):
self.objects.append(object)
B_methods = set([m for m in dir(object) if callable(getattr(object, m))])
A_methods = set([m for m in dir(self) if callable(getattr(self, m))])
to_set = B_methods.difference(A_methods)
for method in to_set:
setattr(self, method, getattr(object, method))

Python creating objects in a loop append items to same list instead of a new list

I have a code that creates an object inside a loop. The object has a list that contains different type of object.
class A:
a = ''
def __init__(self):
pass
class B:
def __init__(self):
pass
list_of_A = list()
for i in range(3):
_b = B()
for j in range(2):
_a = A()
_b.list_of_A.append(_a)
print(len(_b.list_of_A))
The output is:
2
4
6
What I expected was:
2
2
2
I tried deleting _b at the end of the inner loop. But didn't work.
How should I make sure the loop creates a new object of B.
One way is to make list_of_A an instance variable, so it creates new list everytime you create an object:
class B:
def __init__(self):
self.list_of_A = list() # or = []
When you have the following arrangement:
class B:
def __init__(self):
pass
list_of_A = list()
list_of_A is shared by all objects of that class (because this is a class variable), and so you are appending to the same list object.
Do this:
class B:
def __init__(self):
self.list_of_A = list()
Reason: Class Variable(or Static Variable) vs Instance Variable
In your code, list_of_A is a class variable(or static variable) so it is same for all the objects(or instances) of class B.
In the code suggested above, list_of_A is an instance variable so it is different and unique for each object(or instance) of class B.

Calculating the difference between the output of two class objects

I have created two class objects that retrieve information from a database and store them in pandas in order for me to use the data science libraries. They both return values that I display in a Django template. I want to create a third value that is just the calculated difference of the first two and also display that in the Django template.
First class object:
class IntDailyNumbers (object):
def __init__(self, begin_date, end_date, store=None):
self.begin_date = begin_date
self.end_date = end_date
self.store = store
self.int_daily_numbers = pd.DataFrame(list(gapayment.objects.values('Trans_Store', 'Fee_Pd', 'Trans_date')))
self.int_daily_numbers['Fee_Pd'] = pd.to_numeric(self.int_daily_numbers['Fee_Pd'])
self.int_daily_numbers['Trans_date'] = pd.to_datetime(self.int_daily_numbers['Trans_date'])
self.sum_int_daily_numbers = np.sum(self.int_daily_numbers[(self.int_daily_numbers['Trans_date'] >=self.begin_date) &
(self.int_daily_numbers['Trans_date'] <= self.end_date) &
(self.int_daily_numbers['Trans_Store'] == self.store.store_number)])
def get_sum_int_daily_numbers(self):
sum_intdailynumbers = self.sum_int_daily_numbers['Fee_Pd']
sum_intdailynumbers = round(sum_intdailynumbers.astype(float), 3)
return sum_intdailynumbers
def __str__(self):
return self.get_sum_int_daily_numbers()
Second Class Object:
class IntDailyGoals (object):
def __init__(self, begin_date, end_date, store=None):
self.begin_date = begin_date
self.end_date = end_date
self.store = store
#print(self.begin_date, self.end_date, self.store.store_number)
self.int_mnth_goal = pd.DataFrame(list(StoreGoalsInput.objects.values('store_number',
'interest',
'date')))
self.int_mnth_goal['interest'] = pd.to_numeric(self.int_mnth_goal['interest'])
self.int_mnth_goal['date'] = pd.to_datetime(self.int_mnth_goal['date'])
self.mnth_goal_int =self.int_mnth_goal[(self.int_mnth_goal['date'] >= self.begin_date) &
(self.int_mnth_goal['date'] <= self.end_date) &
(self.int_mnth_goal['store_number'] == self.store.store_number)]
self.mnth_goal_int= self.mnth_goal_int['interest']
self.tot_workingdays = np.busday_count(np.datetime64(self.begin_date),
np.datetime64(self.end_date),
weekmask='Mon Tue Wed Thu Fri Sat')
self.div_intmnthgoal_workingdays = round(np.divide(self.mnth_goal_int, self.tot_workingdays),2)
def get_div_goalsint_wdays(self):
div_goalsint_wdays = self.div_intmnthgoal_workingdays.tolist()[0]
return div_goalsint_wdays
def __str__(self):
return self.get_div_goalsint_wdays()
I believe I need to make a third class for the difference calculation but I cannot figure out how to pass the returns of the first two.
How I understand your question, it has nothing to do with django, but with passing objects from one class to another. Here are two simple solutions, given by class C and class D.
First lets define a minimal example of your two classes. Both have a method, that does something and returns something.
class A:
def foo(self):
print('foo')
return 'foo'
class B:
def bar(self):
print('bar')
return 'bar'
Solution 1: We create a third class, that has an instance of type A and an instance of type B as member variable.
# Contains a class instance of A and B and baz() accesses their methods.
class C:
def __init__(self, a, b):
self.a = a
self.b = b
def baz(self):
self.a.foo()
self.b.bar()
You can use this class with:
# main
a = A()
b = B()
c = C(a,b)
c.baz()
Solution 2: We simply pass the two return values to the function qux(). This function can also be part of a class, if you want it to be.
class D:
def qux(self, res_a, res_b):
print(res_a, res_b)
Here we can use qux() in the following way
# main
a = A()
b = B()
d = D()
d.qux(a.foo(),b.bar())
Since there was some confusion about inheritance. You can also inherit the methods. Don't confuse this with Solution 1. And I don't advise to use inheritance here. The idea of inheritance is, that a child class object is-a parent-class object, like a square is-a rectangle. And that is not what you want.
class E(A,B):
def foobar(self):
self.foo()
self.bar()
Usage from main:
e = E()
e.foobar()

Apply a function to all instances of a class

I am looking for a way to apply a function to all instances of a class. An example:
class my_class:
def __init__(self, number):
self.my_value = number
self.double = number * 2
#staticmethod
def crunch_all():
# pseudocode starts here
for instances in my_class:
instance.new_value = instance.my_value + 1
So the command my_class.crunch_all() should add a new attribute new_value to all existing instances. I am guessing I will have to use #staticmethod to make it a "global" function.
I know I could keep track of the instances that are being defined by adding something like my_class.instances.append(number) in __init__ and then loop through my_class.instances, but I had no luck so far with that either. Also I am wondering if something more generic exists. Is this even possible?
Register objects with the class at initialisation (i.e. __init__) and define a class method (i.e. #classmethod) for the class:
class Foo(object):
objs = [] # registrar
def __init__(self, num):
# register the new object with the class
Foo.objs.append(self)
self.my_value = num
#classmethod
def crunch_all(cls):
for obj in cls.objs:
obj.new_value = obj.my_value + 1
example:
>>> a, b = Foo(5), Foo(7)
>>> Foo.crunch_all()
>>> a.new_value
6
>>> b.new_value
8

Categories