I've got a class that wraps functions with some metadata, in particular a parental relationship with other instances:
class Foo(object):
def __init__(self, func, parent):
self.func = func
self.parent = parent
self.parent_func = self.parent.func
In a few cases, I would like to use Foo to wrap a function that internally calls another Foo's function:
def f(x): return str(x).title()
def g(x): return self.parent_func(x)
a = Foo(f)
b = Foo(g, a)
print b.func("april is the cruellest month")
>>> April Is The Cruellest Month
Problem is that g isn't actually a method until b runs Foo.__init__, so it doesn't have a self.
I'm assuming there's something rather fundamental I'm missing about scoping, object methods, or functions' first-class citizenship status, and would greatly appreciate a point in the right direction.
EDIT: Looks like my above genericized example threw folks off, so I'm adding a more specific example below. The idea of this class is that each instance is an integer property (primality, perfection, its list of factors, etc), and contains a function that tests an integer for the property (returning a bool or an answer, as the case base be).
def f(n): # returns list of factors of n
def s(n): return len(self.parent_func(n))==2 # checks if n is semiprime
factors = Foo(f)
semiprime = Foo(s, factors)
It seems like your question boils down to "how can I dynamically add a method to an object", the the short answer is don't do it (1). Objects can have attributes which can be functions, and that's fine, but these functions do not become methods and don't behave like methods. For example if foo.attr is sum then foo.attr(x) is the same as sum(x) not sum(foo, x).
Your question has a certain functional "aroma" to it, if you wanted to drop the class/object stuff and go the fully functional route you could do something like this:
def identity(x):
return x
def f(n):
return [i for i in range(1, 10) if (n % i == 0)]
def s(factors):
return (len(factors) == 2)
def foo(func, helper=identity):
def innerfunc(n):
return func(helper(n))
return innerfunc
a = foo(f)
print a(6)
# [1, 2, 3, 6]
b = foo(s, a)
print b(5)
# True
If that doesn't appeal to you, I would suggest thinking of the func and parent attributes on your Foo class as data attached to your objects, not as methods, and work out the problem from there. The logic associated with your class should live inside proper methods. These methods can refer to the data as needed. Here's my very simple example:
class Foo(object):
def __init__(self, func, parent=None):
self.func = func
self.parent = parent
def run(self, n):
if self.parent is None:
return self.func(n)
else:
return self.func(self.parent.run(n))
a = Foo(f)
print a.run(6)
# [1, 2, 3, 6]
b = Foo(s, a)
print b.run(5)
# True
(1) Methods belong to a class not an object, so the question should really be how can I attach something to my object that behaves like a method.
As Matthew said, "parental relationship" would point to inheritance. But if you want/have to do it this way, you could use functools.partial:
from functools import partial
class Foo(object):
def __init__(self, func, parent=None):
self.func = partial(func, self)
self.parent = parent
self.parent_func = self.parent.func if parent is not None else None
def f(self, x):
return str(x).title()
def g(self, x):
return self.parent_func(x)
if __name__ == '__main__':
a = Foo(f)
b = Foo(g, a)
print b.func("april is the cruellest month")
When you call a object method, it is called with self as first parameter.
def f(self,x): return str(x).title()
def g(self,x): return self.parent_func(x)
Related
I want to build an object dynamically which allow use to mix the class properties in whichever way they like base on multiple inheritance. This is the expected behaviour. These classes are dataclasses so there won't be many methods in them, mostly data properties.
class Foo():
def bar(self, x):
return x
class FooA(Foo):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
class FooB(Foo):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
class FooC(FooA, FooB):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
f = FooC()
f.bar('S') # SFooBFooAFooC
However this code violate the DRY principle in broad daylight, hence I want to avoid the bar method completely, if there is no special operations in the current class.
Ideally I want something like
#bar_wrapper
class FooA(Foo):
pass
# OR
class FooA(Foo):
__metaclass__ = BarBase
Instead of this full implementation
class FooA(Foo):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
Essentially is there a way that I extract the middle layer class information in a multi-level inheritance class through a decorator or metaclass (the two options that I can think of)? Anyone has any idea on how to do this?
Write a class decorator that adds the bar method to the class:
def bar_wrapper(cls):
def bar(self, x):
p = super(cls, self).bar(x)
p += cls.__name__
return p
bar.__module__ = cls.__module__
bar.__qualname__ = '{}.{}'.format(cls.__qualname__, bar.__name__)
cls.bar = bar
return cls
class Foo():
def bar(self, x):
return x
#bar_wrapper
class FooA(Foo):
pass
#bar_wrapper
class FooB(Foo):
pass
#bar_wrapper
class FooC(FooA, FooB):
pass
f = FooC()
print(f.bar('S')) # SFooBFooAFooC
I have a situation where I'm using #classmethod to create a constructor for a class. Within this constructor, a function gets called, which then in turn calls another function. But either this doesn't work or (more probably) I'm doing something to make it not work. Here's an example in miniature:
class testclass:
def __init__(self, x):
self.x = x
#classmethod
def constructor(cls, x):
adj_x = cls.outer_adjust(cls, x)
return testclass(adj_x)
def outer_adjust(self, x):
return self.inner_adjust(x)
def inner_adjust(self, x):
return x + 1
test_instance = testclass.constructor(4)
This produces an error message:
inner_adjust() missing 1 required positional argument: 'x'
I can make it work by explicitly passing self to inner_adjust, eg
def outer_adjust(self, x):
return self.inner_adjust(self, x)
But this then means that the outer_adjust method can't be used outside of the constructor, which is not what I want.
Any assistance gratefully received.
Here's a more detailed example, with two constructors shown. I'm trying to follow the approach to constructors described in
What is a clean, pythonic way to have multiple constructors in Python?
Which is essentially that the constructors do some processing to figure out what variables they should pass to init when instantiating the class.
Both constructors give the same error:
if_char_is_z_make_it_a() missing 1 required positional argument: 'char_input'
As before, I need to be able to use the if_char_is_make_it_a function outside of the constructor (ie, when using the class normally).
class testclass:
def __init__(self, char):
self.char = char
#classmethod
def constructor_from_int(cls, int_input):
as_char = chr(int_input)
char = cls.process_char(cls, as_char)
return testclass(char)
#classmethod
def constructor_from_char(cls, char_input):
char = cls.process_char(cls, char_input)
return testclass(char)
def process_char(self, char_input):
processed_char = '(' + char_input + ')'
output_char = self.if_char_is_z_make_it_a(processed_char)
return output_char
def if_char_is_z_make_it_a(self, char_input):
if char_input == '(z)':
return '(a)'
return char_input
test_instance = testclass.constructor_from_char('a')
When you call cls.outer_adjust from constructor you are calling the unbound outer_adjust method.
Thus, you pass the class itself as self and not an instance to a method that expects to receive an instance as argument.
Although, there is no real reason to have a constructor method. This is exactly what __init__ is for.
class testclass:
def __init__(self, x):
self.x = self.outer_adjust(x)
def outer_adjust(self, x):
return self.inner_adjust(x)
def inner_adjust(self, x):
return x + 1
test_instance = testclass(4)
If you absolutely need the transformation on x to be done before the instantiation, then use __new__ instead. Although, this is generally not necessary.
Multiple constructors
If for some reason you still need to have a constructor method, by example if you want multiple constructors. Then keep in mind that outer_adjust and inner_adjust are instance methods, this means they must be called after you have created an instance.
class testclass:
def __init__(self, x):
self.x = x
#classmethod
def constructor1(cls, x):
instance = cls(x)
instance.outer_adjust()
return instance
#classmethod
def constructor2(cls, x):
instance = cls(x)
instance.inner_adjust()
return instance
def outer_adjust(self):
print('Do something else')
return self.inner_adjust()
def inner_adjust(self):
self.x += 1
As a sidenote, notice how I did not need to call testclass, but simply called cls in the constructor methods. Since this is a class method, we do not need to explicitly name the class. This is better, especially if you are to use inheritance.
Basically what you are doing here shall be done via the __new__ which serve as constructor.
class testclass:
def __init__(self, x):
self.x = x
def __new__(cls, *args, **kwargs):
instance = super(testclass, cls).__new__(cls, *args, **kwargs)
instance.outer_adjust(args[0])
return instance
def outer_adjust(self, x):
return self.inner_adjust(x)
def inner_adjust(self, x):
self.x = x + 1
test_instance = testclass(4)
You are abusing self. The point of the class method is to use the cls argument as constructor, instead of explicitly naming the class by testclass(adj_x). Also, during the cls.outer_adjust(cls, x) call, you are passing the class instead of the instance, which happens to work because you are not using any instance attributes.
As to your questions, there's no way to avoid the x argument. inner_adjust increases some value by 1, so you must give it something to increase. The idea would be to have
def constructor(cls, x):
return cls(x)
def inner_adjust(self):
return self.x += 1
and then do something like
object= testclass.constructor(12)
object.inner_adjust()
I am trying to define a python decorator (my_decorator) for a class method (f), shown below in a simplified scenario. my_decorator is parametrized by param, which depends on the class attribute (in this case level).
class my_decorator:
def __init__(self, param):
self.param = param
def __call__(self, f):
def f_decorated(instance, c):
print("decorated with param = %d" % self.param)
return f(c)
return f_decorated
class A:
def __init__(self, level):
self.level = level
#my_decorator(param=self.level) # Here is the problematic line!
def f(x):
return x
if __name__ == "__main__":
a = A(level=2)
a.f(1) # name "self" is not defined
The above code does not work, and I get a "self" is not defined error. So my question is, is there any way to achieve the goal of context-parametrized decorator?
BTW, the use case is: I am trying to achieve persistent memoization technique (described at
memoize to disk - python - persistent memoization)
The file where the cache persists to depends on the class A, specifically 'level'. For instance, I would like to persist to the file cache_%d.txt % self.level .
Chen,
Decorator are executed during the compiled time or during the import as the class body is executed during import. So, if you execute your snippet without creating an instance of that class also will throw error.
And more over that parameter self.level inside decorator doesn't make much sense to me as its an instance variable so you can directly use inside the function f(x):
Here is some more details:
Python decorator function called at compile time
As the error says, self doesn't exist at that point. That should be clear to you: self only exists as a parameter to a method, and you're not even in a method at that time. Decorators, like all class-level code are evaluated at define time.
I'm not totally sure what you want to achieve, but you could use a string along with getattr:
class my_decorator:
def __init__(self, param_name):
self.param_name = param_name
def __call__(self, f):
def f_decorated(instance, c):
param = getattr(instance, self.param_name)
print("decorated with param = %d" % param)
return f(c)
...
class A:
def __init__(self, level):
self.level = level
#my_decorator(param_name='level')
def f(x):
return x
self is a variable as any. It's only defined inside of methods, the decorator is outside. If you need attributes of a object inside an decorator, you have the possibility to access it by string-name:
class my_decorator:
def __init__(self, param):
self.param = param
def __call__(self, f):
def f_decorated(instance, c):
print("decorated with param = %d" % getattr(instance, self.param))
return f(instance, c)
return f_decorated
class A:
def __init__(self, level):
self.level = level
#my_decorator(param='level') # Here is the problematic line!
def f(self, x):
return x
if __name__ == "__main__":
a = A(level=2)
a.f(1) # name "self" is not defined
I've got a class which contains a number of lists where whenever something is added to one of the lists, I need to trigger a change to the instance's state. I've created a simple demonstration class below to try to demonstrate what I'm trying to do.
Suppose I have a class like this:
class MyClass:
added = False
def _decorator(self, f):
def func(item):
added = true
return f(item)
return func
def __init__(self):
self.list = [1, 2, 3]
self.list.append = self._decorator(self.list.append)
Since a list is built in, I cannot change it's .append method
cls = MyClass() #gives me an AttributeError since '.append' is readonly
Ideally, I could do the following:
cls = MyClass()
cls.list.append(4)
cls.added #would be true
How should I go about this? Would subclassing list allow me to change it's behavior in this way? If so, how would I pass in the class's state without changing the methods signature?
Thanks!
You cannot monkey-patch builtins, so subclassing is the only way (and actually better and cleaner IMHO). I'd go for something like this:
class CustomList(list):
def __init__(self, parent_instance, *args, **kwargs):
super(CustomList, self).__init__(*args, **kwargs)
self.parent_instance = parent_instance
def append(self, item):
self.parent_instance.added = True
super(CustomList, self).append(item)
class MyClass(object):
added = False
def __init__(self):
self.list = CustomList(self, [1,2,3])
c = MyClass()
print c.added # False
c.list.append(4)
print c.added # True
Would this suit your needs?
class MyClass(object):
added = False
def __init__(self):
self.list = [1,2,3]
def append(self, obj):
self.added = True
self.list.append(obj)
cls = MyClass()
cls.append(4)
cls.added #true
It might be helpful to know what exactly you're trying to achieve.
Is it possible to pass a whole class (not an instance) as a parameter to another class method in Python? If I have several instances of the class first and need to pass any of them not specifying which one to method of class Second, can I do something like this:
class First():
def __init__(self, a, b):
pass
class Second():
def __init__(self, c, d):
pass
def method(self, First):
#and how do I call here the whole class First
#without calling a particular instance here?
Straightforward.
def method(self, First):
First() #instantiation
First.classmethod()
First.staticmethod()
In python classes are objects itself, so you are able to call your method like this
second_instance.method(Any_Class_You_Want)
First, you don't need to specify types in Python. So, if you want method to take a First instance, just do this:
class Second():
def __init__(self, c, d):
pass
def method(self, first):
pass
my_first = First(0, 1)
my_second = Second(2, 3)
my_second.method(my_first)
I believe that answers your real question, which is:
If I have several instances of the class first and need to pass any of them not specifying which one to method of class Second…
If you want to ensure that the parameter actually is a First, you can always add an assert isinstance(first, First) or if not isinstance(first, First): raise TypeError or whatever, but usually you don't want to do that in Python. The whole point of "duck typing" is that you write a function that takes "anything that acts like a First instance" rather than a function that takes "a First instance".
You then say:
Now I need to mutate variables from the First class inside the method of a second class:
So… just do it. Your example doesn't have any attributes in the First class, so let's add some:
class First():
def __init__(self, a, b):
self.total = a + b
And now, let's use them in Second.method:
class Second():
def __init__(self, c, d):
self.total = c + d
def method(self, first):
first.total += self.total
So:
>>> my_first = First(0, 1)
>>> my_first.total
1
>>> my_second = Second(2, 3)
>>> my_second.total
5
>>> my_first.total += 2
>>> my_first.total
3
>>> my_second.method(my_first)
>>> my_first.total
8
Or, if you meant that you wanted to mutate the class attributes in class First… you don't even need a First instance for that:
First.my_class_attribute = 1
If you really do need to pass a class itself… well, a class is a regular value like anything else:
class Second():
def __init__(self, c, d):
pass
def method(self, cls):
pass
my_second = Second(1, 2)
my_second.method(First)
And you can access the class attributes of cls from within method, just as easily as you can access instance attributes when an instance is passed.
You can do:
class Model1:
def get():
return '1'
class Model2:
def get(Model1):
print('test: '+ str(Model1.get()))
if __name__ == '__main__':
Model2.get(Model1)
the output is;: test: 1