Use keywords in class to call a specific method - python

Suppose a Python class has different methods, and depending on what the user specifies, a different method is carried out in the main function calculate().
In the example below the user needs to specify the keyword argument 'methodOne' or 'methodTwo'. If no or an incorrect keyword is specified it should default to 'methodOne'.
class someClass(object):
def __init__(self,method=None):
methodList = ['methodOne','methodTwo']
if method in methodList:
self.chosenMethod = method
else:
self.chosenMethod = self.methodOne
def methodOne(self):
return 1
def methodTwo(self):
return 2
def calculate(self):
return self.chosenMethod()
The above clearly does not work since method is a string and not a function. How can I select self.methedOne() or self.methedOne() based on my keyword argument method? In principle the following works:
def __init__(self,method=None):
if method == 'methodOne':
self.chosenMethod = self.methodOne
elif method == 'methodTwo':
self.chosenMethod = self.methodTwo
else:
self.chosenMethod = self.methodOne
But if I have more than two methods this becomes rather ugly. Is there a way to do this similar to my original code?

You could use getattr() for that purpose:
class someClass(object):
def __init__(self,method=None):
methodList = ['methodOne','methodTwo']
if method in methodList:
self.chosenMethod = method
else:
self.chosenMethod = self.methodOne
def methodOne(self):
return 1
def methodTwo(self):
return 2
def calculate(self):
return getattr(self, self.chosenMethod)()
x = someClass(method='methodOne')
print x.calculate()
>>> 1

You can use getattr to get the actual method on the class object.
class someClass(object):
def __init__(self,method=None):
# store it with the object so we can access it later in calculate method
self.method = method
def methodOne(self):
return 1
def methodTwo(self):
return 2
def calculate(self):
# get the actual method from the string here
# if no such method exists then use methodOne instead
return getattr(self, self.method, self.methodOne)()
> someClass('methodOne').calculate()
# 1
> someClass('methodTwo').calculate()
# 2

Related

completion/intellisense on (*args ,**kwargs) functions

Is there a way to have completion/intellisense on (*args ,**kwargs) functions?
For instance:
class GetVar(GetVarInterface):
#classmethod
def fromcustom(cls,locorvar,offset=0,varType="int", name=None,deref=False,member=None):
return GetVarCustom(locorvar,offset,varType, name,deref,member)
class GetVarCustom(GetVar):
def __init__(self,locorvar,offset=0,varType="int", name=None,deref=False,member=None):
I wanted to implement this without specifying every argument of the constructor (For example using *vars, **kwargs) but didn't want to lose completion/intellisense abilities. Is there a way?
The disadvantage in the current implementation is that you would have to replicate the signature twice for every change...
The only option is to add a comment under the function to hint the arguments, otherwise you can't; if the ide is reading that a function has undefined arguments, it will show you that it's undefined.
A "solution" is to just use the common arguments and pass the rest as kwargs, or you can keep the original init.
class Single_Init:
def __init__(self, val_a, val_b, name=None):
self.val_a = val_a
self.val_b = val_b
self.name = name
class Single_Init_B(Single_Init):
# The previous contructor is calld
def get_result(self):
return self.val_a + self.val_b
class Split_Const:
def op_offset(self, offset):
self.offset = offset
def __init__(self, name, member=None, **kwargs):
""" You olso can hint in a func coment """
self.name = name
self.member = member
if 'offset' in kwargs:
self.offset = kwargs['offset']
else:
self.offset = None
if __name__ == '__main__':
single = Single_Init_B(2, 3)
print('Single:', single.get_result())
split = Split_Const('Name')
split.op_offset(0.5)
print('Split:', split.offset)
Got the solution outside this site..
#functools.wraps(functools.partial(GetVarCustom.__init__,1))
def f(*args,**kwargs):
return GetVarCustom(*args,**kwargs)
Of course, it would have been easier in case of a standard function. However, you need to update the assigned attribute of wraps. Otherwise it will change the function name.
#functools.wraps(GetVarCustom.value,assigned=['__doc__'])
def getvalue(*args,**kwargs):
return self_custom.value(*args,**kwargs)

How to dynamically convert non-existing class member functions to existing ones

I have a class:
class DataReader:
def get_data(self, name):
# get data of given name
It's OK that I use it as following:
reader = DataReader()
a = reader.get_data('a')
b = reader.get_data('b')
c = reader.get_data('c')
...
Is it possible that I write codes like following:
a = reader.get_a()
b = reader.get_b()
c = reader.get_c()
For current codes, it will fail since class DataReader has no methods like get_a(). What I want is, do something to let DataReader support method like get_a, and automatically convert it to self.get_data('a'), without really define get_xxx methods one by one.
Here, the a, b, c can be any string, and I cannot know all of them while defining DataReader class. So, let me ask my question in another way: is there some shortcut way to let DataReader support all (infinity) get_xxx methods (here xxx can be any string), as if I defined infinity methods like:
class DataReader:
def get_a(self): return self.get('a')
def get_b(self): return self.get('b')
...
def get_z(self): return self.get('z')
def get_aa(self): return self.get('aa')
...
def get_asdf(self): return self.get('asdf')
...
def get_okjgoke(self): return self.get('okjgoke')
...
One method is having the DataReader to define __getattr__ special method (that method is invoked when attribute is not found inside the object):
class DataReader:
def __init__(self, data):
self.items = data.copy()
def __getattr__(self, attr):
if attr.startswith('get_'):
return lambda: self.items[attr.split('get_')[-1]]
raise AttributeError('Attribute "{}" not found.'.format(attr))
d = DataReader({'a':1, 'b':2})
print(d.get_a())
print(d.get_b())
Prints:
1
2
Your approach of passing the name to get_data seems pretty reasonable to me. But if you insist on using the attribute based lookups, you can override __getattr__ and use get_data to in there for lookups e.g.:
class DataReader:
def __getattr__(self, attr):
parts = attr.partition('_')
if parts[0] == 'get' and parts[-1] != 'data':
return self.get_data(parts[-1])
return super().__getattr__(attr)
def get_data(self, name):
return name
Now you can use Foo().get_a to get Foo().get_data('a').
If you want get the value from a callable like Foo().get_a() instead of Foo().get_a, you can use tuck in a lambda:
class DataReader:
def __getattr__(self, attr):
parts = attr.partition('_')
if parts[0] == 'get' and parts[-1] != 'data':
return lambda: self.get_data(parts[-1])
return super().__getattr__(attr)
def get_data(self, name):
return name
Now you can do Foo().get_a().

How do I convert a class property to integer

I have the following class:
class temp_con():
def __init__(self):
self.t = 0
#property
def t(self):
return self.t
#t.setter
def t(self,value):
self.t = value
I need to use it to compare against a number following this logic:
if num <= temp_con.t - 2:
#dothing
However i get the error:
Type error: unsupported operand type for -: 'property' and 'int'<
I have tried int(temp_con.t) and getattr(temp_con, t) but those did not work.
How can I utilize the property as an int?
You need to use separate names for the property and the attribute it wraps. A good convention is to use the property name prefixed with a _ as the attribute name.
class TempCon:
def __init__(self):
self._t = 0
#property
def t(self):
return self._t
#t.setter
def t(self, value):
self._t = value
Then you can access the property on an instance of the class.
temp_con = TempCon()
print(temp_con.t)
temp_con.t = 5
print(temp_con.t)
You're accessing t on CLASS, not on an OBJECT of CLASS.
Try:
q = temp_con()
if num <= q.t - 2:
pass
In you code temp_con.t returns property object, which wraps getter (and setter) you've defined in your class code, but it doesnt execute it.
UPDATE: (memo: read twice)
There's also another problem with your code. First (well, it's second in code, but it will happen first) you define getter t, then later you OVERWRITE it with self.t = 0. As a result you'll get (as t) property accessible as a class member (which happens in your example) and value 0 as object's member.
You need an instance of the class in order to use the property and, as pointed out in other answers, you need to use a different name for your object variable. Try:
class temp_con():
def __init__(self):
self._t = 0
#property
def t(self):
return self._t
#t.setter
def t(self,value):
self._t = value
my_temp_con = temp_con()
if num <= my_temp_con.t - 2:
pass
Thus, to access the value of the property and not the property function, you have to access it through my_temp_con.t.

High Order Function Constructor

I'm programming in Python and I need to program a particular object but I'm having some difficulties: I want an object that can recall on demand a particular generator passed during its construction through init.
Now I've write something like this but obviously it doesn't work.
class Foo():
id = ''
def __init__ (self, num)
self.id = num
def recallGenerator():
return self.generator
where and how have I to pass and store the generator that I want to recall with recallGenerator() ?
Well, I have solved.
This is the class I wanted
class Foo():
id = ''
generator = ''
def __init__ (self, num, gen)
self.id = num
self.generator = gen
def recallGenerator(param1, param2,...):
return self.generator(param1, param2,...)
Now, given a generic generator G(param1, param2...) you can create the object and pass it to the constructor with
objectIWanted = Foo(1, G)
and then you can recall the generator with
objectIWanted.recallGenerator(param1, param2,...)
NB note the missing parenthesis when passing G to the constructor.

Dynamically generate method from string?

I have a dict of different types for which I want to add a simple getter based on the name of the actual parameter.
For example, for three storage parameters, let's say:
self.storage = {'total':100,'used':88,'free':1}
I am looking now for a way (if possible?) to generate a function on the fly with some meta-programming magic.
Instead of
class spaceObj(object):
def getSize(what='total'):
return storage[what]
or hard coding
#property
def getSizeTotal():
return storage['total']
but
class spaceObj(object):
# manipulting the object's index and magic
#property
def getSize:
return ???
so that calling mySpaceObj.getSizeFree would be derived - with getSize only defined once in the object and related functions derived from it by manipulating the objects function list.
Is something like that possible?
While certainly possible to get an unknown attribute from a class as a property, this is not a pythonic approach (__getattr__ magic methods are rather rubyist)
class spaceObj(object):
storage = None
def __init__(self): # this is for testing only
self.storage = {'total':100,'used':88,'free':1}
def __getattr__(self, item):
if item[:7] == 'getSize': # check if an undefined attribute starts with this
return self.getSize(item[7:])
def getSize(self, what='total'):
return self.storage[what.lower()]
print (spaceObj().getSizeTotal) # 100
You can put the values into the object as properties:
class SpaceObj(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
storage = {'total':100,'used':88,'free':1}
o = SpaceObj(**storage)
print o.total
or
o = SpaceObj(total=100, used=88, free=1)
print o.total
or using __getattr__:
class SpaceObj(object):
def __init__(self, **kwargs):
self.storage = kwargs
def __getattr__(self,name):
return self.storage[name]
o = SpaceObj(total=100, used=88, free=1)
print o.total
The latter approach takes a bit more code but it's more safe; if you have a method foo and someone create the instance with SpaceObj(foo=1), then the method will be overwritten with the first approach.
>>> import new
>>> funcstr = "def wat(): print \"wat\";return;"
>>> funcbin = compile(funcstr,'','exec')
>>> ns = {}
>>> exec funcbin in ns
>>> watfunction = new.function(ns["wat"].func_code,globals(),"wat")
>>> globals()["wat"]=watfunction
>>> wat()
wat

Categories