List Comprehension Function Pointer Python - python

I have a method (dosomething) that defines an attribute (self.b). Dummy code below:
class foo:
def __init__(self):
self.a = 1
def dosomething(self, i):
self.b = 2 * self.a + i
return self.b ** 2
testobj = foo()
Attribute a can change - so dosomething is called to determine b given the current value of a.
I want to write a list comprehension like the one below. Except, I need to call dosomething for b to change. The dummy code below would just repeat the current value of self.b 20 times.
[testobj.b for i in range(20)] # pass i to dosomething then store self.b
The quick way is to just return self.b but, the return statement is preoccupied for another value that's much more complicated. If I could return self.b, then the following statement would work:
[testobj.dosomething(i) for i in range(20)]
Attribute b is just an intermediate value that I want to access. Is there a one liner list comprehension for this situation? I was considering defining a function within the method that returns self.b but, I'm not sure how I would be able to access it properly. So something like foo().dosomething(1).getb() wouldn't work because dosomething(1) evaluates to a number.
class foo:
def __init__(self):
self.a = 1
def dosomething(self, i):
self.b = 2 * self.a + i
def getb():
return self.b
return self.b ** 2
I guess I should also add that I don't want to be returning a data structure of different values. It would effect much of my code elsewhere.

Not a good use case for list comprehensions.

Related

Same name for instance method and static method in python

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.

Changing Method called without new instance of Python Class

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()

Is there a way to make dictionary keys point to original variable?

I've been facing a problem with class attributes and dictionaries in Python. I have the following class:
class Test:
def __init__(self, a):
self.a = a
self.dictionary = {'key': self.a}
def check(self, string):
print("Before: ",self.a)
self.dictionary[string] += 2
print("After (Dictionary): ",self.dictionary[string])
print("After (Original variable): ",self.a)
And then i create an object test from it:
test = Test(5)
The problem is: when i use the check method:
test.check('key')
The output is:
Before: 5
After (Dictionary): 7
After (Original variable): 5
What i expected was to be able to change the attribute self.a inside the class by changing the dictionary self.dictionary value where i assigned the self.a attribute. But what's happening is that the original attribute self.a hasn't changed, yet the value inside the dictionary, that was supposed to be self.a, has.
Can anyone explain to me why this happens? I assume the dict is creating a copy of self.a as the value for the 'key'. Is there any way i can have the value of the dictionary point to the original variable self.a so i can change it by changing the value of the dictionary?
Edit:
Thank you, guys! I understand now that i was expecting an incorrect behavior from the dictionary. I shall try another approach.
This is not related to the property of class attributes but rather to how dictionaries work in Python and to the fact that integers are immutable. To illustrate it, the same happens when you do:
value = 5
dictionary = {"key": value}
dictionary["key"] += 2
print(value)
# > 5
print(dictionary["key"])
# > 7
It is important here to note that this does not work because self.a is an integer which is an immutable type in Python. This means that you will not be changing the integer's value by doing something like self.dictionary[string] += 2.
Now, what would work well for your problem would be something like this, where you declare a list instead of an integer to keep the mutability property:
class Test:
def __init__(self, a):
self.a = [a] # instead of self.a = a
self.dictionary = {'key': self.a}
def check(self, string):
print("Before: ",self.a[0])
self.dictionary[string][0] += 2
print("After (Dictionary): ",self.dictionary[string][0])
print("After (Original variable): ",self.a[0])
test = Test(5)
# > Before: 5
# > After (Dictionary): 7
# > After (Original variable): 7
self.a points to an int object and ints are immutable. I.E they cannot be changed. when you create the dictionary object you are saying point this key to the same place that self.a points to. When you then change the value that the dictionary key points to since int is immutable a new into object is created at a new memory location so now the dict key points to that new memory location and not at the same memory location as self.a still points to.
so you now have self.a pointing at the memory location holding int 5 and the dict key pointing to a different memory location holding int 7.
UPDATE
update based on your comment, the only way to make self.a and the dict key value to point to the same item all the time is to use a mutable data type like list for example. since lists are mutable then when you change the value in the list, both self.a and dict still point to the same list and only the value inside it was changed. however all references to the int value need to access it through the first element in the list
class Test:
def __init__(self, a):
self.a = [a]
self.dictionary = {'key': self.a}
def check(self, string):
print("Before: ", self.a[0])
self.dictionary[string][0] += 2
print("After (Dictionary): ", self.dictionary[string][0])
print("After (Original variable): ", self.a[0])
test = Test(5)
test.check('key')
OUTPUT
Before: 5
After (Dictionary): 7
After (Original variable): 7
However as i said in my comment. For what reason would you need to have two different attributes / references to the same value in your class instance. chances are what ever your trying to achieve there is a better way to do it than an approach like this
As per your code, There are 2 instance variable of class Test is :
self.a = a
self.dictionary = {'key': self.a}
In check method you are changing /updating self.dictionary variable and not on self.a
(self.dictionary[string] += 2)
self.dictionary and self.a are two different variable if you want to update self.a than following can be done:
class Test:
def __init__(self, a):
self.a = a
self.dictionary = {'key': self.a}
def check(self, string):
print("Before: ",self.a)
self.a+=2
self.dictionary[string] = self.a
print("After (Dictionary): ",self.dictionary[string])
print("After (Original variable): ",self.a)
Output will be :
('Before: ', 5)
('After (Dictionary): ', 7)
('After (Original variable): ', 7)

How to use inputs within the class?

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.

Mutable objects in python and constants

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.

Categories

Resources