This is probably has a very solution but I am struggling with this a bit.
I have 3 almost similar functions I'd like to refactor into one.
Here's the function:
def delete_labels_replication_controller(provider, obj_type):
obj_label_list = []
obj_type_list = provider.mgmt.list_replication_controller()
def delete_labels_node(provider, obj_type):
obj_label_list = []
obj_type_list = provider.mgmt.list_node()
def delete_labels_image(provider, obj_type):
obj_label_list = []
obj_type_list = provider.mgmt.list_image()
Now, as you see, the only thing that changes is the provider.mgmt.xxx class and it changes according to the obj_type I want to pass into the function.
Question is how to use only 1 function for all of them and replace only the .xxx part of the object?
Thanks!
I am sure there is a better solution but maybe using getattr like this?
def delete_labels_by_type(obj_type):
obj_type_list = getattr(provider.mgmt, obj_type)()
return obj_type_list
Do like this
def myFunction(provider, obj_type, flag_type)
obj_label_list = []
if flag_type == 1:
obj_type_list = provider.mgmt.list_replication_controller()
elif flag_type == 2:
obj_type_list = provider.mgmt.list_node()
elif flag_type == 3:
obj_type_list = provider.mgmt.list_image()
You could just pass the obj_type_list as another parameter to the function:
def delete_labels(provider, obj_type, obj_type_list):
obj_label_list = []
...
and then call like this delete_labels(provider, obj_type, provider.mgmt.list_replication_controller()) (and if that's the only time you need the provider parameter, you can remove it entirely)
Or pass a reference to the getter method:
def delete_labels(provider, obj_type, getter):
obj_label_list = []
obj_type_list = getter(provider.mgmt)
...
and then call like this: delete_labels(provider, obj_type, MgmtClass.list_replication_controller)
In both cases, you can move the bulk of the three functions (the common part not shown in the question) into that new function and keep the original functions for easier usage:
def delete_labels_replication_controller(provider, obj_type):
return delete_labels(provider, obj_type, provider.mgmt.list_replication_controller())
Related
I need to get the object method who called another function. I don't want its name, but the actual object.
So far, I got this.
import inspect
def info():
stack_call = inspect.stack()
cls_method = stack_call[1][3]
cls_obj = stack_call[1].frame.f_locals["self"]
cls_members = inspect.getmembers(cls_obj)
my_obj = None
for el in cls_members:
if el[0] == cls_method:
my_obj = el[1]
break
print(my_obj)
class Bob:
def __int__(self):
pass
def jim(self):
info()
test = Bob()
test.jim()
It does what I want to do, but I don't like having to go through the list to find the right method with its name.
I tried many things, but can't see how to make it better.
Would anybody have a better version?
A little different:
def info():
stack_call = inspect.stack()
cls_obj = stack_call[1].frame.f_locals[list(stack_call[1].frame.f_locals.keys())[0]]
cls_method = getattr(cls_obj, stack_call[1][3])
print(cls_method)
I have a class containing a list and some boolean methods.
class Cls:
data = [] // populated in __init__()
def flag1(self):
def flag2(self):
def flag3(self): # these all return booleans, based on the data
I want to create a higher level function, taking a parameter one of the flags, manipulating the data in a number of ways, applying the flag to the new data, and counting the number of results.
Something like:
def hof(self, fn):
count = 0
for i in range(1, 10):
new_obj = Cls(self.data+i)
if new_obj.fn():
count +=1
Is there any way to accomplish this without turning all the flags into static methods ?
===
Edit: Made it work, in a very hackish way:
class Cls:
data = []
def __init__(self):
self.data = value
class flag1(self):
return True
class flag2(self):
return False
# The hackish part
flag_dict = {
1: flag1,
2: flag2,
}
def hof(self, flag):
count = 0
for i in range(1,10):
new_obj = Cls(self.data + [i])
if self.flag_dict[flag](new_obj):
count +=1
return count
But it seems like a hack, and it's not quite understandable. Could someone point to a better way ?
Thanks.
You should be able to just pass the methods into the function like instance.hof(Cls.flag1), and internally, write it as if fn(new_obj):, with no need to make it a staticmethod.
I would like to know how to call one global variable with two different values in a class and call them in the other class (within which behave such as flags).
in SerialP.py
Class SerialP(object):
def ReceiveFrame (self, data, length):
global myvariable
if x:
myvariable = 1:
elif y:
myvariable = 2
in fmMain.py
Class fmMain:
def OnReadConfig(self, event):
if SerialP.myvariable = 1:
#do this task
if SerialP.myvariable = 2:
#do another task
There are a few issues with your code.
First, comparison is done with == and not with = which is used for assignment. Also, you have not included the import statement which might be misleading.
In fmMain.py
import SerialP # and not from SerialP import SerialP
Class fmMain:
def OnReadConfig(self, event):
if SerialP.myvariable == 1: # changed to ==
#do this task
if SerialP.myvariable == 2: # changed to ==
#do another task
I am maintaining a little library of useful functions for interacting with my company's APIs and I have come across (what I think is) a neat question that I can't find the answer to.
I frequently have to request large amounts of data from an API, so I do something like:
class Client(object):
def __init__(self):
self.data = []
def get_data(self, offset = 0):
done = False
while not done:
data = get_more_starting_at(offset)
self.data.extend(data)
offset += 1
if not data:
done = True
This works fine and allows me to restart the retrieval where I left off if something goes horribly wrong. However, since python functions are just regular objects, we can do stuff like:
def yo():
yo.hi = "yo!"
return None
and then we can interrogate yo about its properties later, like:
yo.hi => "yo!"
my question is: Can I rewrite my class-based example to pin the data to the function itself, without referring to the function by name. I know I can do this by:
def get_data(offset=0):
done = False
get_data.data = []
while not done:
data = get_more_starting_from(offset)
get_data.data.extend(data)
offset += 1
if not data:
done = True
return get_data.data
but I would like to do something like:
def get_data(offset=0):
done = False
self.data = [] # <===== this is the bit I can't figure out
while not done:
data = get_more_starting_from(offset)
self.data.extend(data) # <====== also this!
offset += 1
if not data:
done = True
return self.data # <======== want to refer to the "current" object
Is it possible to refer to the "current" object by anything other than its name?
Something like "this", "self", or "memememe!" is what I'm looking for.
I don't understand why you want to do this, but it's what a fixed point combinator allows you to do:
import functools
def Y(f):
#functools.wraps(f)
def Yf(*args):
return inner(*args)
inner = f(Yf)
return Yf
#Y
def get_data(f):
def inner_get_data(*args):
# This is your real get data function
# define it as normal
# but just refer to it as 'f' inside itself
print 'setting get_data.foo to', args
f.foo = args
return inner_get_data
get_data(1, 2, 3)
print get_data.foo
So you call get_data as normal, and it "magically" knows that f means itself.
You could do this, but (a) the data is not per-function-invocation, but per function (b) it's much easier to achieve this sort of thing with a class.
If you had to do it, you might do something like this:
def ybother(a,b,c,yrselflambda = lambda: ybother):
yrself = yrselflambda()
#other stuff
The lambda is necessary, because you need to delay evaluation of the term ybother until something has been bound to it.
Alternatively, and increasingly pointlessly:
from functools import partial
def ybother(a,b,c,yrself=None):
#whatever
yrself.data = [] # this will blow up if the default argument is used
#more stuff
bothered = partial(ybother, yrself=ybother)
Or:
def unbothered(a,b,c):
def inbothered(yrself):
#whatever
yrself.data = []
return inbothered, inbothered(inbothered)
This last version gives you a different function object each time, which you might like.
There are almost certainly introspective tricks to do this, but they are even less worthwhile.
Not sure what doing it like this gains you, but what about using a decorator.
import functools
def add_self(f):
#functools.wraps(f)
def wrapper(*args,**kwargs):
if not getattr(f, 'content', None):
f.content = []
return f(f, *args, **kwargs)
return wrapper
#add_self
def example(self, arg1):
self.content.append(arg1)
print self.content
example(1)
example(2)
example(3)
OUTPUT
[1]
[1, 2]
[1, 2, 3]
I've got a piece of code which contains a for loop to draw things from an XML file;
for evoNode in node.getElementsByTagName('evolution'):
evoName = getText(evoNode.getElementsByTagName( "type")[0].childNodes)
evoId = getText(evoNode.getElementsByTagName( "typeid")[0].childNodes)
evoLevel = getText(evoNode.getElementsByTagName( "level")[0].childNodes)
evoCost = getText(evoNode.getElementsByTagName("costperlevel")[0].childNodes)
evolutions.append("%s x %s" % (evoLevel, evoName))
Currently it outputs into a list called evolutions as it says in the last line of that code, for this and several other for functions with very similar functionality I need it to output into a class instead.
class evolutions:
def __init__(self, evoName, evoId, evoLevel, evoCost)
self.evoName = evoName
self.evoId = evoId
self.evoLevel = evoLevel
self.evoCost = evoCost
How to create a series of instances of this class, each of which is a response from that for function? Or what is a core practical solution? This one doesn't really need the class but one of the others really does.
A list comprehension might be a little cleaner. I'd also move the parsing logic to the constructor to clean up the implemenation:
class Evolution:
def __init__(self, node):
self.node = node
self.type = property("type")
self.typeid = property("typeid")
self.level = property("level")
self.costperlevel = property("costperlevel")
def property(self, prop):
return getText(self.node.getElementsByTagName(prop)[0].childNodes)
evolutionList = [Evolution(evoNode) for evoNode in node.getElementsByTagName('evolution')]
Alternatively, you could use map:
evolutionList = map(Evolution, node.getElementsByTagName('evolution'))
for evoNode in node.getElementsByTagName('evolution'):
evoName = getText(evoNode.getElementsByTagName("type")[0].childNodes)
evoId = getText(evoNode.getElementsByTagName("typeid")[0].childNodes)
evoLevel = getText(evoNode.getElementsByTagName("level")[0].childNodes)
evoCost = getText(evoNode.getElementsByTagName("costperlevel")[0].childNodes)
temporaryEvo = Evolutions(evoName, evoId, evoLevel, evoCost)
evolutionList.append(temporaryEvo)
# Or you can go with the 1 liner
evolutionList.append(Evolutions(evoName, evoId, evoLevel, evoCost))
I renamed your list because it shared the same name as your class and was confusing.