Package: useful-decorators
UsefulDecoratorsSome Decorators I use for various purposes. Some more useful, some less.This is a collection of some Decorators for Python you might find useful.pip install usefull-decoratorsProgramming PatternsCacheThe Cache Decorator will automatically cache the creation of an object of the decorated class.fromuseful_decorators.patternsimportCachedefdisable():returnTrue@Cache(disable=disable)classTest:def__init__(self,q,p=False):self.q=qself.p=pq1=Test("test",True)#Create a new Objectq2=Test("test",True)#This will return the SAME object form the cacheq3=Test("test2")#This will create a new Object.On each call of an__init__method,
the cache will check if there ever was another call that used the same arguments, and if yes return that. If you really want a new Object ( ignore the cache )
you can use<class>.__create_no_cache()with the arguments you would usually pass to the__init__method. You can also reset the cache with<class>.__clear_cache()You can also use the 'disable' property of the decorator. This allows you to specify a function which is called to check if the cache is enabled or disabled.Test.__create_no_cache("hello",True)#Always creates a new Object (will not be added to the cache)#orTest.__clear_cache()Test("hello",True)Note that cached objects are thesame. If you change an attribute on one of the objects, the other will change too. In the example above changing
something inq1will also changeq2.SingletonThe Singleton decorator will change the class to only ever create one instance. This is done by injecting code in the__init__method which checks if an
object of the class is already created.fromuseful_decorators.patternsimportSingleton@Singleton(strict=False)classTest:def__init__(self,q,p=False):self.q=qself.p=pq1=Test("test",True)# Creates a new Objectq2=Test("test",True)# This is the same object as q1q3=Test("test2")# If strict is disabled, this is ALSO the same objects as q1There are basically two methods to handle calls to the__init__method after the original object was created. We can ignore the call no matter the arguments
and return the singleton in all cases (default) or we can raise an error.
It isalwaysbetter to use another method to get the instance because it is clearer to everybody who reads the code. So after you create an instance you can do the followingq2=Test.getInstance()Which returns the instance. This is the only way when strict is set to true to obtain an instance. If strict is set to false, you can overwrite the current instance by usingTest.resetInstance()Test("hi",True)#ORTest.createNew("hi",True)createNewis just a shortcut to reset and create at the same time.ObservableThe Observable decorator allows to attach function calls to changes in the fields of the class.fromuseful_decorators.patternsimportObservabledefchangeling(q):print(q)@Observable(attach=[("q",changeling)])#Now changeling gets called with the new value everytime a new value is assigned to the field named 'q'classTest:def__init__(self,q,p=False):self.q=qself.p=pq1=Test("hello")q1.q="world"#changeling gets called with 'world'The decorator expects a list of tuples as theattachkeyword. Each tuple must contain a name of a field in the class, and a method to call.
This method must take exactly ONE argument (the updated value).
Currently, there is no function call if the field gets deleted withdel.builder_functionThe builder_function decorator is just a shortcut for a method returning the object it belongs to. So instead ofclassTest:def__init__(self):self.q=Noneself.p=Nonedefset_q(self,q):self.q=qreturnselfyou can writefromuseful_decorators.patternsimportbuilder_functionclassTest:def__init__(self):self.q=Noneself.p=None@builder_functiondefset_q(self,q):self.q=qThis allows for easy construction of Objects that can be used like thisobj.setx(x).create_q(q,v=True)....FunctionsThis repo provides some decorators for functions in general.infixThis decorator allows you to make a function (which takes two arguments) into an infix operator.
Your function name has to be surrounded by '|'.fromuseful_decorators.functionsimportinfix@infixdeftest(q1,q2):returnq1+2*q2print("Hello"|test|"World"|test|"1")attachThis decorator allows you to attach another function to the decorated function.fromuseful_decorators.functionsimportattachdefattached(q=1):print("world"*q)@attach(attached)deffoo():print("hello")foo()# hello worldYou can also specify the arguments that shall be passed to the attached function like sofromuseful_decorators.functionsimportattachdefattached(q=1):print("world"*q)@attach(attached,q=2)deffoo():print("hello")foo()# hello worldworldOf course, you can attach multiple methods as well. Just add more@attachdecorators.prependthis isexactlythe same asattachbut will execute the specified methodbeforethe original method.chainthe chain decorator allows for chaining functions together and feeding ones output in another ones input.fromuseful_decorators.functionsimportchaindefq1(q,h=2):print(q*h)@chain(q1)defq2(q):returnq+1@chain(q1,3)#same as @chain(q1,h=3)defq3(q):returnq+1q2(1)# 4 because (1+1)*2 = 4q3(1)# 6 because (1+1)*3 = 6The input is always the FIRST argument of the chained function. The function with the decorator is always evaluated first and then fed into the function which is
mentioned in the decorator. Of course the chain can be as long as you want.