I'm trying to create a class A which is basically a list of objects B.
I would like to be able to call a method in A which automatically
returns a list of the corresponding method in B:
A.method(x) = [B.method(x) for B in A]
The issue is that I need a dynamical behavior, so any method in B is
automatically "inherited" by A without having to hard code it.
I have tried using lambda functions and exec("""def ..."""),
but nothing seems to work. Here is an attempt:
class A(object):
def __init__(self,Bs):
self.listOfBs = Bs[:]
if self.listOfBs:
for method_name in dir(self.listOfBs[0]):
if not callable(getattr(self.listOfBs[0],method_name)):
continue
f = lambda x: [getattr(B,method_name)(x) for B in self.listOfBs]
setattr(self,method_name,f)
class B(object):
def __init__(self,name):
self.name = name
def getName(self,x):
return self.name+x
#So if I define:
a = A([B('x'),B('y'),B('z')])
#I would like to have: a.getName('W') = ['xW','yW','zW']
#However I get the error: TypeError: 'str' object is not callable
I think there should be an easy/elegant way of implementing the above behavior in python, but I couldn't find anything that works.
You may use __getattr__ to make method lookup dynamic
class A:
def __init__(self, bs):
self.bs = bs
def __getattr__(self, method_name):
def call(*args, **kw):
return [getattr(b, method_name)(*args, **kw) for b in bs]
return call
Thanks a lot. I had tried getattr before, but was missing some steps.
Just for the record, following Glazner's suggestion here is a working solution, which works both with attributes and methods:
class A(object):
def __init__(self,Bs):
self.listOfBs = Bs[:]
def __getattr__(self, attr):
if not all(hasattr(b,attr) for b in self.listOfBs):
raise AttributeError("Attribute %s not found." %attr)
val = getattr(self.listOfBs[0],attr)
if not callable(val):
return np.array([getattr(b,attr) for b in self.listOfBs])
def call(*args, **kw):
return [getattr(b, attr)(*args, **kw) for b in self.listOfBs]
return call
class B(object):
def __init__(self,name):
self.name = name
def getName(self,x):
return self.name+x
a = A([B('x'),B('y'),B('z')])
a.name #Returns ['x','y','z']
a.getName('W') #Returns ['xW','yW','zW']
Related
Is there any way to have a method which processes the attributes and returns the desired value in python?
Below is the example of what i want to achieve.
class Foo():
self.a = '123'
self.b = '234'
def hex_value(self,attribute): # method for attribute.
return hex(attribute)
if __name__=="__main__":
obj = Foo()
print(obj.a.hex) # should give hex value of 'a' by simply using dot operator.
I feel a little dirty by hacking someting like this together, but you could use some kind of proxy class to do this:
class Proxy():
def __init__(self, value, parent):
self.value = value
self.parent = parent
def __getattr__(self, attr):
return self.parent.__getattribute__(attr + '_value')(self.value)
class Foo():
def __init__(self):
self.a = '123'
self.b = '234'
self.c = 'foo_Bar'
def hex_value(self,attribute):
return hex(int(attribute))
def repeated_value(self,attribute):
return attribute + " " + attribute + " " + attribute
def __getattribute__(self, attr):
if not attr.endswith('_value') and not attr.startswith('__'):
return Proxy(super(Foo, self).__getattribute__(attr), self)
return super(Foo, self).__getattribute__(attr)
if __name__=="__main__":
obj = Foo()
print(obj.a.hex) # should give hex value of 'a' by simply using dot operator.
print(obj.c.repeated) # prints 'foo_Bar foo_Bar foo_Bar'
The idea is that everything that you access in Foo is wrapped in a proxy. And everything you access in the proxy that's not avaiable is called on the proxy's creator (with an '_value' added) instead.
But just because you can doesn't mean you should.
Given a class and a set of its methods - how can you determine from within that class which methods have been decorated with a certain decorator?
My goal is to basically get the actual values of the methods that are decorated, so something like:
class A():
def get_values(self):
...
# returned {'a-special-name': 1, 'b': 2}
#my_dec('a-special-name') # Ideally be able to also put optional name
def a(self):
return 1
#my_dec
def b(self):
return 2
Any idea on how to accomplish this?
Edit: this should also work on parent classes, that is, if A is a subclass of:
class B():
#my_dec
def c(self):
return 3
then get_values() of A instance should return {'a-special-name': 1, 'b': 2, 'c': 3} (order is irrelevant of course)
Edit: class based decorator that works but not with inheritance. Any idea how to make it work with inheritance but without having to decorate the class itself?
class my_dec(object):
def __init__(self, func, name=None):
self.func = func
self.name = name or func.__name__
self.func._some_flag = True
def __get__(self, instance, cls=None):
if instance is None:
return self
return self.func(instance)
If you can define the decorator yourself, then simply have it "mark" the method object in some way:
def my_dec(method):
method._this_be_decorated = True
return method
The class can then look for those marked methods; something like:
from inspect import isfunction
class A:
def get_values(self):
return filter(lambda i: isfunction(i) and hasattr(i, '_this_be_decorated'),
vars(type(self)).values())
This will return an iterable of function objects which you can process further as needed.
def my_dec(name):
if callable(name):
# name is callable – take its name
func = name # no make the code more readable
func.special_name = func.__name__
return func
else:
# name is the name to give – add an inner layer of functions
def inner(function_object):
function_object.special_name = name
return function_object
return inner
class A():
def get_values(self):
# return a dict of special name to call result mapping for every class member that has a special_name.
return {func.special_name: func(self) for func in self.__class__.__dict__.values() if hasattr(func, 'special_name')}
# returned {'a-special-name': 1, 'b': 2}
#my_dec('a-special-name') # Ideally be able to also put optional name
def a(self):
return 1
#my_dec
def b(self):
return 2
def no_dec(self):
return 42
should do what you want.
As deceze mentions, decorators can do whatever they want so there's no reliable generic answer. If you "own" the decorator you can add special properties to it's return value ie (Q&D py2.7 example):
def mydec(name=''):
# py27 hack - for py3 you want nonlocal instead
n = [name]
def innerdec(func):
# py27 hack - for py3 you want nonlocal instead
name = n[0] or func.__name__
def wrapper(*args, **kw):
print("in mydec.wrapper for {}".format(name))
return func(*args, **kw)
wrapper.ismydec = True # so we know this is decorated by mydec
wrapper.func = func # so we can get the original func
wrapper.name = name
return wrapper
return innerdec
def collect_dec(cls):
decorated = {}
for attname in dir(cls):
obj = getattr(cls, attname)
if getattr(obj, "ismydec", False):
decorated[obj.name] = obj.func
cls._decorated_funcs = decorated
return cls
#collect_dec
class A():
def get_values(self):
return {
name:func(self) for name, func in self._decorated_funcs.items()
}
#mydec('a-special-name') # Ideally be able to also put optional name
def a(self):
return 1
#mydec() # no name
def b(self):
return 2
a = A()
print(a.get_values())
Which outputs:
{'a-special-name': 1, 'b': 2}
I have a big class which has a lot of functions and attributes.
the instances are created from data in a remote database.
the process of creating each instance is very long and heavy.
In performance sake ive created a bunch class from this heavy class.
so accessing the attributed is easy and works great .
the problem is how to use the methods from that class.
ex :
class clsA():
def __init__(self,obj):
self.attrA=obj.attrA
def someFunc(self):
print self
class bunchClsA(bunch):
def __getattr__(self, attr):
# this is the problem:
try:
#try and return a func
func = clsA.attr
return func
except:
# return simple attribute
return self.attr
Clearly this dosent work , Is there a way i could access the instance function staticly and override the "self" var ?
Found out a nice solution to the problem :
from bunch import Bunch
import types
#Original class:
class A():
y=6
def __init__(self,num):
self.x=num
def funcA(self):
print self.x
#class that wraps A using Bunch(thats what i needed .. u can use another):
class B(Bunch):
def __init__(self, data, cls):
self._cls = cls # notice, not an instance just the class it self
super(B, self).__init__(data)
def __getattr__(self, attr):
# Handles normal Bunch, dict attributes
if attr in self.keys():
return self[attr]
else:
res = getattr(self._cls, attr)
if isinstance(res, types.MethodType):
# returns the class func with self overriden
return types.MethodType(res.im_func, self, type(self))
else:
# returns class attributes like y
return res
data = {'x': 3}
ins_b = B(data, A)
print ins_b.funcA() # returns 3
print ins_b.y # returns 6
And this solves my issue, its a hack and if you have the privileges, redesign the code.
How can I modify a self variable with a decorator?
Ex.
class Foo:
def __init__(self,a):
self.a = a
self.li = []
def afunction(self):
pass
I want to add the function object afunction to the list self.li so I can call it in a list. Ex. Have a list of functions defined by the class. How would I do that?
Thanks
I don't think you need a decorator. Functions are first-class objects in Python:
class Foo:
def __init__(self,a):
self.a = a
self.li = [self.afunction]
def afunction(self):
pass
If your intention is to mark certain functions of a class as a special type so that you can identify them later for some other purpose, you could use a decorator, or you could just use a naming convention.
def marked(function):
function.marked = 1
return function
class MarkAware(object):
def run_marked(self, *args, **kwargs):
for name in dir(self):
meth = getattr(self, name)
if hasattr(meth, 'marked'):
meth(*args, **kwargs)
def foo(self):
pass
#marked
def bar(self):
pass
Alternative:
class NameConvention(object):
def run_batchable(self, *args, **kwargs):
for name in dir(self):
if name.startswith('batchable_'):
getattr(self, name)(*args, **kwargs)
def foo(self):
pass
def batchable_bar(self):
pass
As Lattyware explains in a comment to unutbu's answer, you can't directly do what you're asking, because any decorator on afunction will be run while the class itself is being created, not when each instance is created.
If all you really want is "a list of functions defined by the class", you don't need anything fancy at all for that. Just create that list in __init__:
def __init__(self, a):
self.a = a
self.li = [f for f in dir(self) if inspect.ismethod(f)]
If you want a list of certain specific functions, the easiest way is the way unutbu suggests, which still doesn't require a decorator.
If you want the decorator just to mark "this method should go into li", see sr2222's answer.
None of these are what you asked for, but they are probably what you want. There are a few ways to actually use a decorator to add the function to self.li, but they're all pretty horrible, and you probably don't want them. For example:
class Foo:
def __init__(self,a):
self.a = a
self.li = []
def mydecorator(f):
self.li.append(f)
return f
#mydecorator
def afunction(self):
print('a')
self.afunction = new.instancemethod(afunction, self, Foo)
I'm trying to create a wrapper that blocks the execution of some methods. The classic solution is to use this pattern:
class RestrictingWrapper(object):
def __init__(self, w, block):
self._w = w
self._block = block
def __getattr__(self, n):
if n in self._block:
raise AttributeError, n
return getattr(self._w, n)
The problem with this solution is the overhead that introduces in every call, so I am trying to use a MetaClass to accomplish the same task. Here is my solution:
class RestrictingMetaWrapper(type):
def __new__(cls, name, bases, dic):
wrapped = dic['_w']
block = dic.get('_block', [])
new_class_dict = {}
new_class_dict.update(wrapped.__dict__)
for attr_to_block in block:
del new_class_dict[attr_to_block]
new_class_dict.update(dic)
return type.__new__(cls, name, bases, new_class_dict)
Works perfectly with simple classes:
class A(object):
def __init__(self, i):
self.i = i
def blocked(self):
return 'BAD: executed'
def no_blocked(self):
return 'OK: executed'
class B(object):
__metaclass__ = RestrictingMetaWrapper
_w = A
_block = ['blocked']
b= B('something')
b.no_blocked # 'OK: executed'
b.blocked # OK: AttributeError: 'B' object has no attribute 'blocked'
The problem comes with 'more complex' classes like ndarray from numpy:
class NArray(object):
__metaclass__ = RestrictingMetaWrapper
_w = np.ndarray
_block = ['max']
na = NArray() # OK
na.max() # OK: AttributeError: 'NArray' object has no attribute 'max'
na = NArray([3,3]) # TypeError: object.__new__() takes no parameters
na.min() # TypeError: descriptor 'min' for 'numpy.ndarray' objects doesn't apply to 'NArray' object
I assume that my metaclass is not well defined because other classes (ex: pandas.Series) suffer weird errors, like not blocking the indicated methods.
Could you find where the error is? Any other idea to solve this problem?
UPDATE:
The nneonneo's solution works great, but seems like wrapped classes can break the blocker with some black magic inside the class definition.
Using the nneonneo's solution:
import pandas
#restrict_methods('max')
class Row(pandas.Series):
pass
r = Row([1,2,3])
r.max() # BAD: 3 AttributeError expected
As it says in the TypeError, min (and related functions) will only work on instances of np.ndarray; thus, the new subclass must inherit from the class you are trying to wrap.
Then, since you extend the base class, you have to replace the methods with a suitable descriptor:
class RestrictedMethod(object):
def __get__(self, obj, objtype):
raise AttributeError("Access denied.")
class RestrictingMetaWrapper(type):
def __new__(cls, name, bases, dic):
block = dic.get('_block', [])
for attr in block:
dic[attr] = RestrictedMethod()
return type.__new__(cls, name, bases, dic) # note we inject the base class here
class NArray(np.ndarray):
__metaclass__ = RestrictingMetaWrapper
_block = ['max']
Note: enterprising applications can still access "restricted" functionality through the base class methods (e.g. np.ndarray.max(na)).
EDIT: Simplified the wrapper and made it transparently subclassable.
Note that this can all be done in a simpler way using a class decorator:
class RestrictedMethod(object):
def __get__(self, obj, objtype):
raise AttributeError("Access denied.")
def restrict_methods(*args):
def wrap(cls):
for attr in args:
setattr(cls, attr, RestrictedMethod())
return cls
return wrap
#restrict_methods('max', 'abs')
class NArray(np.ndarray):
pass