Let's say I have the following class containing a Numpy array a.
class MyClass():
def __init__(self,a,b):
self.a = a
self.other_attributes = b
def transpose(self):
return MyClass(self.a.T,self.other_attributes)
Since this "transpose the data, keep the rest unchanged" method will be used quite often, I would like to implement a short-named attribute like Numpy's .T. My problem is that I don't know how to do it without calling .transpose at initialization, i. e., I only want to do the transpose when it is required, instead of saving it in another attribute. Is this possible?
Use a property to compute attributes. This can also be used to cache computed results for later use.
class MyClass():
def __init__(self, a, b):
self.a = a
self.other_attributes = b
#property
def T(self):
try:
return self._cached_T # attempt to read cached attribute
except AttributeError:
self._cached_T = self._transpose() # compute and cache
return self._cached_T
def _transpose(self):
return MyClass(self.a.T, self.other_attributes)
Since Python 3.8, the standard library provides functools.cached_property to automatically cache computed attributes.
from functools import cached_property
class MyClass():
def __init__(self, a, b):
self.a = a
self.other_attributes = b
#cached_property
def T(self):
return self._transpose()
def _transpose(self):
return MyClass(self.a.T, self.other_attributes)
A transpose is just a view of the data, so "computing" the transpose at instantiation doesn't actually cost anything.
In [11]: a = np.random.rand(2, 1)
In [12]: a
Out[12]:
array([[0.22316214],
[0.69797139]])
In [13]: b = a.T
In [14]: a[0] = 1
In [15]: b
Out[15]: array([[1. , 0.69797139]])
Related
I am writing some small library and I want to provide users two approaches for the same functionality, by instance method and static method. Here is a simplified example:
class ClassTimesAdd(object):
def __init__(self, a, b):
self.a = a
self.b = b
def TimesAdd(self, c):
return self.a * self.b + c
#staticmethod
def TimesAdd(a, b, c):
return a * b + c
print(ClassTimesAdd.TimesAdd(1, 3, 7))
ins = ClassTimesAdd(2, 5)
print(ins.TimesAdd(7))
And you can find that the earlier function will be overwritten and only the last one is valid. I'm wondering if there is some simple method that I can use to make the two approaches both work.
Is it possible to directly set a certain value and get it in a class by any mean(inheritance, metaclass, class decorator) in Python? class B must not be polluted by set('a') in A.
import sys
class A:
set('a')
get()
# -> 'a'
print(sys.modules[__name__])
# => <module '__main__'>
class B:
get()
# -> None
Assuming you know what you are doing, yes, it is possible to set values with programmatic names in a class body, and retrieve then, and have these values restricted to that class body.
All you have to do is to use thelocals() call to get the namespace dictionary, and use that dictionary to hold your values:
class A:
locals()["key"] = "a"
print(locals()["key"] )
This will print "a",
and obviously, this value won't be part of a class B namespace.
If you want just to store values without associating then
with a name, the stackfull project provide a
push and pop calls that will behave just like
you proposed in your example -
but if you try a pop() withour a previous push
in the same scope, you will get an error due to
a stack underflow:
In [4]: !pip install stackfull
Collecting stackfull
...
Successfully installed stackfull-1.0.0
In [5]: from stackfull import push, pop
In [6]: class A:
...: push("a")
...: push("b")
...: print(pop())
...: print(pop())
...:
b
a
In [7]: class B:
...: pop()
...:
...
StackUnderflowError:
(Disclaimer - I am the author of the stackfull package. I never really needed
anything beyond what is already there, so it has not been updated in a long time - and with the "walrus" operator in Python 3.8, it is no longer that useful)
Ok - so I listed this because it resembles the code in your question, but chances are you need something more mainstream, like writing your code in methods, and set instance attributes.
These two independent classes don't reference each other, so as long as you don't pass the same object to both, then neither will 'pollute' the other. To set a value and get a value on an object, you could use something like this:
class A:
def __init__(self):
self.letter = None
def set_value(self, letter):
self.letter = letter
def get_value(self):
return self.letter if self.letter else '(none set)'
class B:
def __init__(self):
self.letter = None
def set_value(self, letter):
self.letter = letter
def get_value(self):
return self.letter if self.letter else '(none set)'
>>> a = A()
>>> aa = A()
>>> b = B()
>>> a.set_value('z')
>>> print(f'values in a, aa, and b are: {a.get_value()}, {aa.get_value()}, {b.get_value()}')
values in a, aa, and b are: z, (none set), (none set)
So as you can see, setting the a object's letter doesn't set it in b (a different class), or in aa, which is a different instance of the same A class. Hope that helps!
Happy Coding!
I'm new to Python OOP and for the purpose of this question I have simplified my problem to this:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
def add(self):
# some arbitrary change
return self.a + self.b
def subtract(self):
# some arbitrary change
return self.a - self.b
a = Foo(a=1, b=2).add()
b = Foo(a=1, b=3).subtract()
So I have an object, which has 2 methods which do different things, in order for me to get some output, I have created 2 separate instances of Foo as the value b has changed.
Is there a way for me to just dynamically set b and the obj.method() without just listing them one after the other? I.E: some sort of generic class that I can use to dynamically set the attributes and the methods that are present in the object? or is there anything built in I can use...
Edit
Here is another example:
class Foo:
def __init__(self, a, b):
self.a = list(a)
self.b = list(b)
def method1(self):.
# some arbitrary change in data
return self.a * 2
def method2(self):
return self.b + [5, 6, 4]
a = Foo(a=[1, 2, 3], b=[]).method1()
b = Foo(b=[1, 2, 3], a=[]).method2()
print(a)
print(b)
So here, the input list changes based on the method called, is there a way for me to package this up so I could feed just one instance some data and then it 'knows' that list a is for method1(), list b is for method2() - I want to use the word reflection but I feel like that might not be accurate.
Again I'm new to OOP so any advice is appreciated
class Foo:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
fo = Foo()
a = fo.add(1,2)
b = fo.subtract(1,3)
you don't need 2 instances of Foo to achieve this.
Just do something like this:
foo = Foo(a = 1, b = 2)
# Perform addition (now 'a' is 1 and 'b' is 2)
a = foo.add()
# Change 'b'
foo.b = 3
# Now perform subtraction (now 'a' is 1 and 'b' is 3)
b = foo.subtract()
I am new to python and object language. I am learning class in python now. but the code below confused me.
class math:
def __init__(self, a, b):
self.a = a
self.b = b
math.add = self.a+self.b
def sum(self):
math.sum = self.a+self.b
s= math(2,1)
x = math.add
y = math.sum
the results look not right. x is 3 but y is not 3. where is my problem?
thanks
I'm guessing what you wanted to do was this.
class math:
def __init__(self, a, b):
self.a = a
self.b = b
self.add = self.a+self.b
def sum(self):
return self.a+self.b
s= math(2,1)
x = s.add
y = s.sum()
print(x)
print(y)
The errors were as follows
You were not calling your instance of math. As these are instance methods, they must reference an instance x = math.add should be x = s.add.
You created a method sum but did not call it y = s.sum simply creates a reference to the function and does not call it, instead you should use y = s.sum()
Your function sum doesn't return anything, so assigning a value to its return value will yield a value of None. To resolve this return a value from sum i.e. return self.a + self.b.
self.add is also quite strange, as it named like a function, but its actually a value, this will not be expected by others looking at your code. A better name for it might be total or remove it since it provides the same functionality as sum.
I have a class which contains data as attributes and which has a method to return a tuple containing these attributes:
class myclass(object):
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def tuple(self):
return (self.a, self.b, self.c)
I use this class essentially as a tuple where the items (attributes) can be modified/read through their attribute name. Now I would like to create objects of this class, which would be constants and have pre-defined attribute values, which I could then assign to a variable/mutable object, thereby initializing this variable object's attributes to match the constant object, while at the same time retaining the ability to modify the attributes' values. For example I would like to do this:
constant_object = myclass(1,2,3)
variable_object = constant_object
variable_object.a = 999
Now of course this doesn't work in python, so I am wondering what is the best way to get this kind of functionality?
Now I would like to create objects of this class, which would be constants and have pre-defined attribute values, which I could then assign to a variable/mutable object, thereby initializing this variable object's attributes to match the constant object,
Well, you can't have that. Assignment in Python doesn't initialize anything. It doesn't copy or create anything. All it does is give a new name to the existing value.
If you want to initialize an object, the way to do that in Python is to call the constructor.
So, with your existing code:
new_object = myclass(old_object.a, old_object.b, old_object.c)
If you look at most built-in and stdlib classes, it's a lot more convenient. For example:
a = set([1, 2, 3])
b = set(a)
How do they do that? Simple. Just define an __init__ method that can be called with an existing instance. (In the case of set, this comes for free, because a set can be initialized with any iterable, and sets are iterable.)
If you don't want to give up your existing design, you're going to need a pretty clumsy __init__, but it's at least doable. Maybe this:
_sentinel = object()
def __init__(myclass_or_a, b=_sentinel, c=_sentinel):
if isinstance(a, myclass):
self.a, self.b, self.c = myclass_or_a.a, myclass_or_a.b, myclass_or_a.c
else:
self.a, self.b, self.c = myclass_or_a, b, c
… plus some error handling to check that b is _sentinel in the first case and that it isn't in the other case.
So, however you do it:
constant_object = myclass(1,2,3)
variable_object = myclass(constant_object)
variable_object.a = 999
import copy
class myclass(object):
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def tuple(self):
return (self.a, self.b, self.c)
constant_object = myclass(1,2,3)
variable_object = copy.deepcopy(constant_object)
variable_object.a = 999
print constant_object.a
print variable_object.a
Output:
1
999
Deepcopying is not entirely necessary in this case, because of the way you've setup your tuple method
class myclass(object):
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def tuple(self):
return (self.a, self.b, self.c)
constant_object = myclass(1,2,3)
variable_object = myclass(*constant_object.tuple())
variable_object.a = 999
>>> constant_object.a
1
>>> variable_object.a
999
Usually (as others have suggested), you'd want to deepcopy. This creates a brand new object, with no ties to the object being copied. However, given that you are using only ints, deepcopy is overkill. You're better off doing a shallow copy. As a matter of fact, it might even be faster to call the class constructor on the parameters of the object you already have, seeing as these parameters are ints. This is why I suggested the above code.