Best way to handle preset options in classes - python

I want to have a Class which can be initialized with options a,b and c.
c is a special case, where I can modify the initialization with a variable extend.
I'm currently looking for the best way to do this.
Also I would like my IDE (in this case PyCharm) to make suggestions to me which parameters I can use for the preset.
I came up with two ideas to do it.
Option 1:
class MyClass:
def __init__(self,preset,extend=None):
if preset == "a":
self.x = 1
if preset == "b":
self.x = 2
if preset == "c":
self.x = 3
if extend != None:
self.x = self.x + extend
def __str__(self):
return f"The value of x is {self.x}"
Y=MyClass(preset="c",extend= 3)
print(Y)
#out: The value of x is 6
Option 2:
class MyClass2:
def __init__(self):
self.x=None
def preset_a(self):
self.x=1
def preset_b(self):
self.x=2
def preset_c_with_extend(self,extend):
self.x =3+extend
def __str__(self):
return f"The value of x is {self.x}"
Y2=MyClass2()
Y2.preset_b()
print(Y2)
#out: The value of x is 2
Option 1 looks more elegant to me, but in my workflow I don't want to go to the implementation for initializing a certain preset for looking up the options.
But this would be necessary, because I can not remember for bigger projects if I named the preset a or if it was not A.
Option 1 also leaves it unclear if I can add an option extend.
Here it might happen, that I use preset a with extend=3 and I am wondering why the extend is not applied.
So the actual question: Is there an elegant way to see the preset options without looking at the class implementation? (Maybe some kind of Type Hint?)
Option 2 has this opportunity, and with auto-completion in my IDE I see what presets I can apply. But it doesn't look very elegant.
I am curious about your ideas!

How about:
class MyClass2:
def __init__(self, x):
self.x = x
#staticmethod
def preset_a():
return MyClass2(1)
#staticmethod
def preset_b():
return MyClass2(2)
#staticmethod
def preset_c_with_extend(extend):
return MyClass2(3+extend)
def __str__(self):
return f"The value of x is {self.x}"
Y2=MyClass2.preset_b()
print(Y2)
It ensures that x is set at object creation time and should allow IDE auto-completion.

Another alternative is to use a presets dict. However, I have no idea how PyCharm will treat this solution in regards to suggestions.
class MyClass:
PRESETS = {"a": 1, "b": 2, "c": 3}
def __init__(self, preset, extend=None):
self.x = self.PRESETS.get(preset)
if preset == "c" and extend is not None:
self.x += extend
def __str__(self):
return f"The value of x is {self.x}"
Note that dict's .get() method is used which means x will be None if you try to use a non-existing preset.

Related

Python class __call__ method and dot notation

My Goal is to use dot notation to select strings from dictionarys using the SimpleNamespace modeule while having the ability to change which dictionary to use.
To do this i have tried modifying the class __call__ method to change the output based on a previously set variable. However, due to the use of the __call__ method it requires the use of () to be included which breaks the simple formatting of dot notation. Additinally i need to be able to use class methods as well to change the option i am looking for.
class i: x, y = 1, 2
class j: x, y = 3, 4
class myClass:
def __init__(self):
self.a, self.b = i(), j()
self.selection = "a"
def set_selection(self, selection):
self.selection = selection
def __call__(self):
return getattr(self, self.selection)
mc = myClass()
print(mc().x) ## this generates the output i am wanting by using the __call__ method
mc.set_selection("b") ## i still need to call class methods
print(mc().x)
print(mc.x) ## this is the syntax i am trying to achive
although mc().x works it is not dot notation.
The output i am looking for in this example would be similar to:
import myClass
data = myCalss()
print(data.x + data.y)
#>>> 3
data.set_selection("b")
print(data.x + data.y)
#>>> 7
Seem like __call__() is the wrong choice for the interface you want. Instead, maybe __getattr__() is what you want:
class i: x, y = 1, 2
class j: x, y = 3, 4
class myClass:
def __init__(self):
self.a, self.b = i(), j()
self.selection = "a"
def set_selection(self, selection):
self.selection = selection
def __getattr__(self, at):
return getattr(getattr(self, self.selection), at)
data = myClass()
print(data.x + data.y)
# 3
data.set_selection("b")
print(data.x + data.y)
# 7
Might want some checks to make sure the selection is valid.
Also, probably worth reading up on descriptors if you will be exploring this kind of stuff more deeply.

Clean pythonic composition with default parameters

Suppose I want to compose two objects and I'd like to be able to be able to define multiple constructors that respect the default arguments.
class A:
def __init__(x,y=0):
self.x = x
self.y = y
class B:
def __init__(w,objA, z=1):
self.w = w
self.objA = objA
self.z = z
I'd like to have multiple constructors for B which allow me to either pass an object A or pass parameters and then construct A. Looking at What is a clean, pythonic way to have multiple constructors in Python? I can do:
class B:
def __init__(w, objA, z=1):
self.w = w
self.objA = objA
self.z=z
#classmethod
def from_values(cls,w,z,x,y):
objA = A(x,y)
return cls(w,objA,z)
The problem is that the default values are being overwritten and I'd like to keep them. The following of course does not work.
#classmethod
def from_values(cls,w,x,**kwargs):
objA = A(x,**kwargs)
return cls(w,objA,**kwargs)
So it seems I'm stuck with remembering the default values and calling them like this
#classmethod
def from_values(cls,w,x,z=1,y=0):
objA = A(x,y)
return cls(w,objA,z)
This is not what I want since I'd rather have the objects themselves handle the default values and not be forced remember the default values. I could do one better than the above and use:
#classmethod
def from_values(cls,w,x,z=1,**kwargs):
objA = A(x,**kwargs)
return cls(w,objA,z)
But in this case I still need to "remember" the default value for z. Is there a Pythonic solution to this? Is this a design problem? Can someone point me to a good design pattern or best practices? This problem compounds when composing with several objects...
class L:
def __init__(objM,objN):
self.objM = objM
self.objN = objN
#classmethod
def from_values(cls, m1,m2,m3,n1,n2):
objM = M(m1,m2,m3)
objN = N(n1,n2)
return cls(objM, objN)
First I would argue that this isn't what you want to do. As this scales up, trying to call your constructor will be tedious and error-prone.
You can solve both of our problems with an explicit dictionary.
class A:
def __init__(self, config):
self.x = config.get('x')
assert self.x # if you need it
self.y = config.get('y', 0)
class B:
def __init__(self, b_config, objA):
self.w = b_config.get('w')
self.objA = objA
self.z = b_config.get('z', 1)
#classmethod
def from_values(cls,b_config,a_config):
return cls(b_config, A(a_config))
B.from_values({'w':1, 'z':2}, {'x': 3, 'y': 4})
It's probably not as clever or neat as what you're looking for, but it does let you construct from an A if you already have it, or to pass in a configurable set of parameters in a more structured way.

Monkey patching __eq__ in Python

Having some trouble understanding why I'm able to re-define (monkey patch) __eq__ outside of a class, but not change its definition through __init__ or in a method:
class SpecialInteger:
def __init__(self,x):
self.x = x
self.__eq__ = self.equals_normal
def equals_normal(self,other):
return self.x == other.x
def equals_special(self,other):
return self.x != other.x
def switch_to_normal(self):
self.__eq__ = self.equals_normal
def switch_to_special(self):
self.__eq__ = self.equals_special
a = SpecialInteger(3)
b = SpecialInteger(3)
print(a == b) # false
a.switch_to_normal()
print(a == b) # false
SpecialInteger.__eq__ = SpecialInteger.equals_normal
print(a == b) # true
SpecialInteger.__eq__ = SpecialInteger.equals_special
print(a == b) # false
Am I just using self incorrectly or is there some other reason it works like this?
To do it inside the class, you would simply define the __eq__ method inside of your class.
class SpecialInteger:
def __init__(self,x):
self.x = x
def __eq__(self, other):
# do stuff, call whatever other methods you want
EDIT: I see what you are asking, you wish to override the method (which is a "magic" method) at the instance level. I don't believe this is possible in the base construct of the language, per this discussion.
The reason your monkey patch works in that example is because it is being passed on the Class level, as opposed to the instance level, whereas self is referring to the instance.
Just to add on to an excellent existing answer, but this doesn't work because you are modifying the class instance, and not the class.
In order to get the behavior you desire, you can modify the class during __init__, however, this is woefully inadequate (since it modifies the class, and therefore all instances of the class), and you are better off making those changes visible at the class scope.
For example, the following are equivalent:
class SpecialInteger1:
def __init__(self,x):
self.x = x
self.__class__.__eq__ = self.equals_normal
...
class SpecialInteger2:
def __init__(self,x):
self.x = x
def equals_normal(self,other):
return self.x == other.x
def __eq__(self, other):
return self.equals_normal(other)
You should prefer case SpecialInteger2 in all examples, since it is more explicit about what it does.
However, none of this actually solves the issue you are trying to solve: how can I create a specialized equality comparison at the instance level that I can toggle? The answer is through the use of an enum (in Python 3):
from enum import Enum
class Equality(Enum):
NORMAL = 1
SPECIAL = 2
class SpecialInteger:
def __init__(self, x, eq = Equality.NORMAL):
self.x = x
self.eq = eq
def equals_normal(self, other):
return self.x == other.x
def equals_special(self, other):
return self.x != other.x
def __eq__(self, other):
return self.__comp[self.eq](self, other)
# Define a dictionary for O(1) access
# to call the right method.
__comp = {
Equality.NORMAL: equals_normal,
Equality.SPECIAL: equals_special
}
Let's walk through this quickly, since there are 3 parts:
An instance member variable of eq, which can be modified dynamically.
An implementation of __eq__ that selects the correct equality function based on the value of self.eq.
A namespace-mangled dictionary (a class/member variable that starts with __, in this case, self.__comp) that allows efficient lookup of the desired equality method.
The dictionary can easily be done-away with, especially for cases where you only wish to support 1-5 different possible comparisons, and replaced with idiomatic if/then statements, however, if you ever wish to support many more comparison options (say, 300), a dictionary will be much more efficient O(1) than if/then comparisons (linear search, O(n)).
If you wish to do this with setters (like in the original example), and actually hide the member functions from the user, you can also do this by directly storing the function as a variable.
All method definitions are defined at class level (literally the name is a key in a dict belonging to the class). This is also true of anything else you put at class level. Which is why for instance a variable assignment outside a method in a class produces a class variable.
The easiest way to keep the same functionality would be to just refer to some other variable from __eq__. It could be some reference variable, or a saved method.
class SpecialInteger:
def __init__(self,x):
self.x = x
self._equal_method = self.equals_normal
# ...
def switch_to_normal(self):
self._equal_method = self.equals_normal
def switch_to_special(self):
self._equal_method = self.equals_special
def __eq__(self, other):
return self._equal_method(other)

Python 3: Calling a class function inside of __init__

I have a little question about python 3.
I want to create a class, which is using a function from within of that class. Just like:
class Plus:
def __init__(self, x, y):
self.x = x
self.y = y
self.test()
def test(self):
return self.x + self.y
now I am doing something like
a = Plus(5,6)
print(a)
and python is giving me
<__main__.Plus object at 0x000000000295F748>
and not 11 as I want it. I know that I can get 11 by
a = Plus(5, 6).test()
print(a)
but that's not what I want. I want to call the class and getting the result without adding .test() to it.
Can you help me?
I would go for:
class Plus:
def __init__(self, x, y):
self.x = x
self.y = y
self.test()
def test(self):
res = self.x + self.y
self.__repr__ = lambda:str(res)
return res
>>> Plus(5,5)
10
>>> a = Plus(5,5)
>>> a
10
>>> a.test()
10
This way you are not recomputing the sum each time you call print, its updated when you call the test method.
You'd need to define a __str__ method for your Plus class:
class Plus:
def __init__(self, x, y):
self.x = x
self.y = y
def test(self):
return self.x + self.y
def __str__(self):
return str(self.test())
now I am doing something like
a = Plus(5,6)
print(a)
and python is giving me
<__main__.Plus object at 0x000000000295F748>
and not 11 as I want it. I know that I can get 11 by
a = Plus(5, 6).test()
print(a)
but that's not what I want. I want to call the class and getting the result without adding .test() to it.
I am not sure what do you mean by 'and not 11 as I want it'. If you want Plus(5, 6) to actually return 11 (int instance), you should make Plus a function that returns the sum. Alternatively you can override __new__ method and hook upon object creation -- but this is a bad idea.
What are you trying to achieve?
I doubt, that by 'and not 11 as I want it' you want something special to be printed (formatted, represented). If so, override __str__ or __unicode__ or __repr__ method.
Edit:
ignore this answer, it is a comment on a misinterpretation of the question
This is just wrong.
when you instantiate an object, you'd expect to get a reference to that object.
if you just want a global function returning a number, why even bother to make a class with an init?
in python you shouldn't want static class's like in C# for encapsulation. instead name the module something, and use that for encapsulation.

Is there a way to run a method for all instances of a class in python?

Example code:
>>> class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def power(self):
print(self.x**self.y)
def divide(self):
print(self.x/self.y)
>>> foo = MyClass(2, 3)
>>> bar = MyClass(4, 7)
>>>
>>> foo.power()
8
>>> bar.divide()
0.5714285714285714
Whenever I used classes in Python previously, I just ran the method for each instance separately (see above). I was just wondering If there was a way to run the same method for all the instances of that class at once, because it could get a bit annoying, if you have 20 or so instances. I'm thinking of something like this:
>>> allinstances.power()
8
16384
Is there a way of doing this?
class MyClass(object):
instancelist = []
def __init__(self, x, y):
self.x = x
self.y = y
MyClass.instancelist.append(self)
def power(self):
print(self.x ** self.y)
def divide(self):
print(self.x / self.y)
foo = MyClass(2, 3)
bar = MyClass(4, 7)
[instance.power() for instance in MyClass.instancelist]
will output:
8
16384
This way you do not need any global variables or placeholders that are stored outside of the class definition.
Not usually. You could make your class be capable of that, however:
GLOBAL_MYCLASS_LIST = []
class MyClass(object):
def __init__(self, x, y):
GLOBAL_MYCLASS_LIST.append(self)
self.x = x
self.y = y
def power(self):
print(self.x**self.y)
def divide(self):
print(self.x/self.y)
a = MyClass(2, 3)
b = MyClass(4, 7)
all_powers = [i.power() for i in GLOBAL_MYCLASS_LIST]
Of course, you could also do that without baking it into the class, which is probably cleaner for most cases where you might have different sets of MyClasses:
myclass_list = []
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def power(self):
print(self.x**self.y)
def divide(self):
print(self.x/self.y)
myclass_list.append(MyClass(2, 3))
myclass_list.append(MyClass(4, 7))
all_powers = [i.power() for i in myclass_list]
From your question, I believe you would want a bit of dynamism too. Something like below could help:
I have added a function called printBoth() for demonstration.
Note: Python 2.x code below
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def power(self):
print "power",self.x**self.y
def divide(self):
print "divide", self.x/self.y
def printBoth(self):
print "x: ", self.x
print "y: ", self.y
class Test:
def __init__(self, items):
self.items = items
def __getattr__(self, key):
def fn():
return [getattr(x,key)() for x in self.items]
return fn
foo = MyClass(2, 3)
bar = MyClass(4, 7)
t = Test([foo,bar])
t.power()
t.divide()
t.printBoth()
Output:
power 8
power 16384
divide 0
divide 0
x: 2
y: 3
x: 4
y: 7
Note: The code can break on many occasions, you neeed to perform additional checks in real implementation.
The important part is here:
def __getattr__(self, key):
def fn():
return [getattr(x,key)() for x in self.items]
return fn
The above function is invoked upon any function call on the Test instance. What is returned is function that takes no arguments. The function runs over all the instances, and invokes the same function on every item on self.items (which is the list of all the instances you want to invoke your function on). The results are returned as a list.
Sure. Put the instances in a list as you create them, then iterate over the list and call the method on each instance. Also, you should change your methods to return rather than print their results, as this is much more flexible. That way you can store the results in a list, write them to a file, do further calculations with them, or print them.
instances = [MyClass(2, 3), MyClass(4, 7)]
results = [x.power() for x in instances]
Just use a loop:
foo = MyClass(2, 3)
bar = MyClass(4, 7)
for i in [foo, bar]:
i.power()
If you are not sure that all instances will have the method, use a hasattr check:
for i in list_of_instances:
if hasattr(i, 'power'):
i.power()
I think all answers are valid, depending on the use case. I would argue that if this class is used in seperated parts of your app/program you wouldn't want to depend on the GLOBAL_MYCLASS_LIST declared some where before (as #amber suggested). You would want to be sure this variable exists and declare it as a Class Variable and have the compute_all as a Class method or even as a static method with #staticmethod decorator (which I think is less relevant to the specific use case.
Again, I would stress that this is a very specific use case, and not very common. so you should think about your design before doing that and not using the more straight pythonic ways offered in other answers.
I would also like to refer you to this nice video of a Pycon lecture about classes in python which does a nice job of explaining this (The decks are here.)

Categories