All over my code I use a python “static” class like this:
curStatus = StaticClass.getStat()
where
class StaticClass:
#staticmethod
def getStat () -> str:
return "noSimulate"
But now I have a refactor issue where sometimes SIMULATE is TRUE or FALSE
SIMULATE: bool = false
If Simulate is true, I want staticmethod.getStat() to be a different method.
But I only want to check SIMULATE once and use polymorphism to do the rest.
& I don’t want to refactor the whole code base.
How can I change StaticClass method by just checking SIMULATE once?
I used this info: python3-patterns
and created these two .py files:
Testing.polymorphism
# https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Factory.html
SIMULATE:bool = True
# class myBase(object):
class myBase:
#staticmethod
def factory(sim:bool) :
return yesSim() if sim else myBase()
#staticmethod
def getDroneStatus() -> str:
print("myBase.getDroneStatus()")
return "UNITIALIZED! FAIL!!"
#staticmethod
def getStaticStatus() -> str:
print("myBase.getStaticStatus()")
return "UNITIALIZED! FAIL!!"
class yesSim(myBase):
#staticmethod
def getDroneStatus() -> str:
return "yesSim"
GSCRAMtcp = myBase.factory(SIMULATE)
if __name__ == '__main__':
myTCP = myBase.factory(SIMULATE)
print(myTCP.getStaticStatus())
print(myTCP.getDroneStatus())
and this testfile:
from Testing.polymorphism.testPolymorph import GSCRAMtcp
if __name__ == '__main__':
print(GSCRAMtcp.getDroneStatus())
print(GSCRAMtcp.getStaticStatus())
Related
i have a little "basic understanding" Python problem.
So let me explain my problem.
At first a very simple code snippet.
class Revert:
__sentence = ""
def __init__(self, sentence: str):
self.__sentence = sentence
def get_sentence(self):
return self.__sentence
def revert_sentence(self):
return self.__sentence[::-1]
if __name__ == '__main__':
print(Revert("Stackoverflow").get_sentence())
print(Revert("Stackoverflow").revert_sentence())
So this show normal function calling of python functions.
But how can i transform this code so i can call the revert function like this:
print(Revert("Stackoverflow").get_sentence().revert_sentence())
Maybe I'm miss the forest through the trees. But I didn't get it how to do this.
I already tried to solve the problem with innermethods but this didn't work for me
...
def get_sentence(self):
def revert_sentence():
self.revert_sentence()
return self.__sentence
...
Many thanks in advance
Implement __str__ to return the actual string. Then in the existing methods, return the object. This way you can chain. But when print is applied to it, that __str__ method will kick in:
class Revert:
__sentence = ""
def __init__(self, sentence: str):
self.__sentence = sentence
def get_sentence(self):
return self
def revert_sentence(self):
return Revert(self.__sentence[::-1])
# Some more such methods ...
def upper(self):
return Revert(self.__sentence.upper())
def first(self, count):
return Revert(self.__sentence[:count])
def dotted(self):
return Revert(".".join(self.__sentence))
# For getting a string
def __str__(self):
return self.__sentence
print(Revert("Stackoverflow").get_sentence().revert_sentence())
print(Revert("Stackoverflow")
.revert_sentence()
.first(8)
.upper()
.revert_sentence()
.first(4)
.dotted()) # "O.V.E.R"
Note that now the .get_sentence() method is not really doing much, and you can always strip it from a chain.
Here You go:
class Revert:
__sentence = ""
def __init__(self, sentence: str):
self.__sentence = sentence
def get_sentence(self):
return self.__sentence
def revert_sentence(self):
# It's important to know that you are making changes in the same instance of the object
self.__sentence = self.__sentence[::-1]
return self
def pseudo_revert(self):
# Return a new object with reverted string, but this instance still has original string intact.
return Revert(self.__sentence[::-1])
if __name__ == '__main__':
r1 = Revert("Stackoverflow")
r2 = Revert("Stackoverflow")
print(r1.get_sentence()) # Stackoverflow
print(r1.revert_sentence().get_sentence()) # wolfrevokcatS
print(r1.get_sentence()) # wolfrevokcatS
print(r2.get_sentence()) # Stackoverflow
print(r2.pseudo_revert().get_sentence()) # wolfrevokcatS
print(r2.get_sentence()) # Stackoverflow
Hope this helps you understand the object, instance of an object, and method of object distinctly.
I'd like to use named constants whereever possible instead of providing literal values or longish function signatures with a lot of boolean args.
Therefore i like pythons enum.Flag or enum.Enum.
More precisely, I would like to pass an argument to a function which holds a bit combination of enum.Flags. And i would like to avoid writing module.TheFlags.flagX for every set flag I would like to pass to the function. The flags should replace the boolean args.
I came up with following code:
import enum
class AvailableFlags(enum.Flag):
flag1 = enum.auto()
flag2 = enum.auto()
class FuncFlags:
def __init__(self):
self._flags = AvailableFlags(0)
#property
def flag1(self):
self._flags |= AvailableFlags.flag1
return self
#property
def flag2(self):
self._flags |= AvailableFlags.flag2
return self
def __str__(self):
return str(self._flags.value)
def func(setup_flags: FuncFlags):
print(setup_flags)
if __name__ == "__main__":
func(FuncFlags().flag1)
func(FuncFlags().flag2)
func(FuncFlags().flag1.flag2)
func(FuncFlags())
It creates instances of FuncFlags and then mis-uses the properties to set single flags returning the changed object itself.
However, one would expect that the property does NOT change object state.
Therefore, this is obviously not a clean solution despite that it works, though.
So, my question is, how this can be implemented in a clean, reusable way?
I'm not really clear on what you are trying to accomplish, but perhaps this helps?
import enum
class AvailableFlags(enum.Flag):
flag1 = enum.auto()
flag2 = enum.auto()
flag1, flag2 = AvailableFlag
def func(setup_flags: AvailableFlags):
print(setup_flags)
if __name__ == "__main__":
func(flag1)
func(flag2)
func(flag1|flag2)
func()
Meanwhile, I found an answer by adding another level of indirection.
I want to share it here if it is of interest for someone else.
Object state is maintained as every invokation of a flag creates a new instance from the current instance by setting an additional flag.
If we attempt to access an undefined flag an exception is raised (not shown).
import enum
class AvailableFlags(enum.Flag):
flag1 = enum.auto()
flag2 = enum.auto()
class FlagHelper:
def __init__(self, cls, value = 0):
self._cls = cls
self._flags = self._cls(value)
def __getattr__(self, item):
if item in self._cls.__members__:
return self.__class__(self._flags | getattr(self._cls, item))
getattr(self._cls, item) # Let attribute error pass through
def __str__(self):
return str(self._flags.value)
class FuncFlags(FlagHelper):
def __init__(self, value = 0):
super().__init__(AvailableFlags, value)
def func(setup_flags: FuncFlags):
print(setup_flags)
if __name__ == "__main__":
ff = FuncFlags()
func(ff.flag1)
func(ff.flag2)
func(ff.flag1.flag2)
func(ff)
Output:
1
2
3
0
When I do not crate object for CP class, the operations are not captured. I am referring to the code below, Can somebody help me understand why we need obj creation in this case
from abc import ABC, abstractmethod
class P(ABC):
def __init__(self):
super().__init__()
self._pre_map = {}
self._pre_order = []
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
def execute(self):
pass
class CP(P):
def __init__(self):
super().__init__()
def execute(self):
self.prnt()
def prnt(self):
print (self._pre_map)
print (self._pre_order)
#Working
print("\n++++++++ working")
obj = CP()
obj.set_pre("test string added")
obj.execute()
#Not Working
print("\n+++++++ not working")
CP().set_pre("test string added")
CP().execute()
It produces,
++++++++working
0
{0: 'test string added'}
[0]
+++++++not working
0
{}
[]
When you call the class the second time with CP.execute(), you have created a completely new instance of the CP class. It is not going to have the text string you specified.
If you actually wanted it to print the values like the working one you can make the functions return self after each call in the P class. If you did that you could do something like this.
from abc import ABC, abstractmethod
class P(ABC):
def __init__(self):
super().__init__()
self._pre_map = {}
self._pre_order = []
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
##need to return self here
return self
def execute(self):
pass
class CP(P):
def __init__(self):
super().__init__()
def execute(self):
self.prnt()
def prnt(self):
print (self._pre_map)
print (self._pre_order)
#Working
print("\n++++++++ working")
obj = CP()
obj.set_pre("test string added")
obj.execute()
#Not Working
print("\n+++++++ not working: but now working after returning self in the P class")
CP().set_pre("test string added").execute()
++++++++ working
0
{0: 'test string added'}
[0]
+++++++ not working: but now working after returning self in the P class
0
{0: 'test string added'}
[0]
This would print the result you want.
The reason for the difference is the fact that in the first one, you are creating an instance, and using that instance the whole way through, whereas in the second one, you are using two different instances of your class.
The two different instances cannot share their attributes, so you are unable to recall what happened. If you really don't want to use a dedicated variable, change your P class to look like this:
class P(ABC):
...
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
return self
...
And use CP().set_pre("test string added").execute()
I'm overwriting the MutableSet from collections.abc, and I want to be able to determine whenever its instance equates to True/False.
I know about the magic methods for comparisons, but I am looking for behaviour like checking an empty set/list that Python provides.
class Example():
pass
e = Example()
if e:
print("This shall work - the default of an instance is True")
# What I'd like is something similar to...
if []:
pass
else:
print("This shall be false because it's empty, there wasn't a comparison")
I've looked in the cookbook: Special methods Data model - Other various websites - I can't seem to find the answer :(
Ultimately I would like to be able to go:
class A:
def __init__(self, value: int):
self.value = value
def __cool_equality_method__(self):
return self.value > 5
a = A(10)
b = A(3)
if a:
print("This happens")
if b:
print("This doesn't happen")
What about __bool__ simply?
class A:
def __bool__(self):
if not getattr(self, 'trueish', None):
return False
else:
return True
a = A()
if a:
print("Hello")
a.trueish = True
if a:
print("a is True")
You need to implement the __bool__ method on your class, which is simply your old __cool_equality_method__ renamed to __bool__:
class A:
def __init__(self, value: int):
self.value = value
def __bool__(self):
return self.value > 5
a = A(10)
b = A(3)
if a:
print("This happens")
if b:
print("This doesn't happen")
"""
This happens
"""
I have a method that returns dynamic type based on the class I pass in:
def foo(cls):
return cls()
How can I setup typing for this function?
After reading this article https://blog.yuo.be/2016/05/08/python-3-5-getting-to-grips-with-type-hints/, I found solution myself:
from typing import TypeVar, Type
class A:
def a(self):
return 'a'
class B(A):
def b(self):
return 'b'
T = TypeVar('T')
def foo(a: T) -> T:
return a()
This template suites my question above, but actually, my need is a little bit different that I need to work more. Below I include my problem and solution:
Problem: I want to use the with keyword like this:
with open_page(PageX) as page:
page.method_x() # method x is from PageX
Solution
from typing import TypeVar, Type, Generic
T = TypeVar('T')
def open_page(cls: Type[T]):
class __F__(Generic[T]):
def __init__(self, cls: Type[T]):
self._cls = cls
def __enter__(self) -> T:
return self._cls()
def __exit__(self, exc_type, exc_val, exc_tb):
pass
return __F__(cls)
So, when I use with PyCharm, it's able to suggest method_x when I pass PageX into with open_page(PageX) as page: