How can I call the metaclass's __call__? - python

Given the following example on an instance of a X class:
class X():
def __call__(self, incoming_list):
print incoming_list
X()([x for x in range(10)])
How can I obtain the same output by using the __call__ magic method from the class itself instead of the instance? Example:
X([x for x in range(10)])
Calling directly, as if passing to __init__. But, before it calls __call__ that calls __new__ that passes the arguments to __init__. How can I access that "metaclass __call__" ? Is it possible?
Just to make it easier to understand, this gives me the same output from up there:
class X:
def __call__(self, incoming_list):
print incoming_list
X().__call__([x for x in range(10)])
I want something like this:
class X:
def X.__call__(incoming_list): # Syntax Error
print incoming_list
X.__call__([x for x in range(10)])

I think you think too complicated.
Probably you want something like
class X:
def __init__(self, incoming_list):
self.data = incoming_list # to keep them for later, if needed
print incoming_list
X([x for x in range(10)])
Everything without a meta class, just on definition of the class.
If you need a meta class, you can do it like
class MC(type):
def __call__(self, *a, **k):
super(MC, self).__call
print a, k
r = super(MC, self).__call__(*a, **k)
print "R", r
return r
class X(object):
__metaclass__ = MC
def __init__(self, x): print "Init", x
Using it with
>>> X(1)
(1,) {}
Init 1
R <__main__.X object at 0x00000000022907B8>
<__main__.X object at 0x00000000022907B8>
shows that the meta-__call__ is called, which, in turn, calls __init__.
But I am sure that you don't need that and that you just want __init__.

Related

How to have multiple inits for a class

I want to create a class called Chain.
I want to be able to call __init__ method multiple times.
For example:
>> Chain(1)
1
>> Chain(1)(2)
3
How can I do this in Python?
You just need a callable int:
>>> class Chain(int):
... def __call__(self, other: int) -> Chain:
... return Chain(self + other)
...
>>> Chain(10) == 10
True
>>> Chain(1)(2)(3)
6
To do exactly what you have shown (the usefulness of which I question), you need to override __repr__ and define __call__. For example,
class Chain:
def __init__(self, x):
self.x = x
def __repr__(self):
return repr(self.x)
def __call__(self, x):
return Chain(self.x + x)
Since __call__ returns a new instance of Chain, you can chain calls indefinitely.
>>> Chain(1)
1
>>> Chain(1)(2)
3
>>> Chain(1)(2)(3)
6
Chain itself will always return an instance of Chain (unless you define Chain using a metaclass other than the default of type). Chain.__call__ is what allows you to call an instance of Chain like a function, returning a function to allow the actual chain of calls to continue. __repr__ is used so that each attempt to "show" the instance produces the value of its attribute.
As far as I know, you cannot implement multiple __inits__ since it's the function which initializes variables etc.
What you can do is implement the __call__ function, which is the one being called when you call an instance e.g
class MyClass:
def __init__(self,a):
self.a = a
print("Init")
def __call__(self,b):
print("call")
self.b=b
inst = MyClass(1) # "Init"
inst(2) #"call"
Does this answer your question?
class Chain:
def __init__(self, value):
self.value = value
def __call__(self, value):
return Chain(self.value + value)
one = Chain(1)
three = Chain(1)(2)
print(three.value)
Just to explain what __call__ does is:
call is method enables Python programmers to write classes where the instances
behave like functions and can be called like a function.

The self parameter with a dictionary of functions within a class

I'm attempting to create a dictionary of executable functions within a class. But having trouble getting the self parameter to work correctly.
Consider the following code:
class myclass(object):
def x(self):
return 'x'
def y(self):
return 'y'
EF= {
'a':x,
'b':y,
}
def test(self):
print self.EF['a']()
When I attempt to execute the 'test' function of the class, I get an error around the number of parameters as it evaluates and executes one of the functions in the dictionary.
>>> class myclass(object):
... def x(self):
... return 'x'
... def y(self):
... return 'y'
... EF= {
... 'a':x,
... 'b':y,
... }
... def test(self):
... print self.EF['a']()
...
>>>
>>>
>>> m=myclass()
>>> m.test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in test
TypeError: x() takes exactly 1 argument (0 given)
I've tried a few variations, including this which doesn't work.
EF= {
'a':self.x,
'b':self.y,
}
The only thing that did work was when I explicitly passed self as a parameter, like this.
... def test(self):
... print self.EF['a'](self)
...
>>> m=myclass()
>>> m.test()
x
I've seen other questions about using a dictionary to index functions, but none from within a class.
Here are my questions:
What is the proper way to do handle the self parameter?
I'd prefer to move my dictionary constant outside of the class into my constants section. Can I do that, and if so how? Should I do that?
If I should/have to have my dictionary within my class, why can't I move it to the top of the class?
That's all I got. Thanks for the help.
What is the proper way to do handle the self parameter?
Python uses the self identifier in similar ways to other imperative languages using the this identifier, but it is explicit (as explicit is better than implicit!)
This allows you to use the class as either an instantiated object, or the static class itself.
For an instantiated version, you are probably looking for
>>> class myclass:
def __init__(self):
self.EF = {'a':self.x,'b':self.y}
def x(self):
return 'x'
def y(self):
return 'y'
def test(self):
print self.EF['a']()
>>> my_test_class = myclass()
>>> my_test_class.test()
x
I'd prefer to move my dictionary constant outside of the class into my constants section. Can I do that, and if so how? Should I do that?
If you wanted to use them as static method in a dict outside your class definition, you would need to use the #staticmethod decorator
>>> class myclass(object):
#staticmethod
def x():
return 'x'
#staticmethod
def y():
return 'y'
>>> EF = {'a':myclass.x,'b':myclass.y}
>>> EF['a']()
'x'
If I should/have to have my dictionary within my class, why can't I move it to the top of the class?
Any object attributes should be defined either in the __init__ function, or by explicitly setting them.
Having the dictionary in an init method will make it work
class Myclass(object):
def x(self):
return 'x'
def y(self):
return 'y'
def __init__(self):
self.EF= {
'a':self.x,
'b':self.y
}
def test(self):
print self.EF['a']()
m=Myclass()
m.test()
In reference to your questions. The class is kind of a dictionary or named tuple of attributes and executable functions. The functions themselves only define behavior. self is a sack of state related to your instance. if you save a pointer to that function somewhere else and provide it with a given self that is an instance of your class it should work as normal.
class MyClass(object):
def __init__(self, x):
self.x = x
def fun(self):
return self.x
i = MyClass(1)
print i.fun()
f = MyClass.fun
i2 = MyClass(2)
print f(i2)
When you call using the standard i.fun() all it's doing is passing i in implicitly as the selfargument.

How to access "self" inside the scope of a class?

I've crossed an interesting problem.
Suppose we have a class, and in its constructor we take a boolean as an argument. How can I define methods inside the class based on the instance's condition/boolean? For example:
class X():
def __init__(self, x):
self.x = x
if self.x == true: # self is unreachable outside a method.
def trueMethod():
print "The true method was defined."
if self.x == false: # self is unreachable outside a method.
def falseMethod():
print "The false method was defined."
You can't, but you can define methods with different names and expose them under certain circumstances. For example:
class X(object):
def __init__(self, flag):
if flag:
self.method = self._method
def _method(self):
print "I'm a method!"
Testing it:
>>> X(True).method()
I'm a method!
>>> X(False).method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'X' object has no attribute 'method'
No, because self refers to an instance, and there are no instances yet at the time the class is defined.
There are ways to achieve similar effects (like renaming, adding or deleting methods on a per-instance basis within __init__), but there's no real reason to do this anyway.
You cannot do that, but to define a method on the fly you can use types.MethodType:
from types import MethodType
def trueMethod(self):
print "The true method was defined."
def falseMethod(self):
print "The false method was defined."
class X():
def __init__(self, x):
self.x = x
if self.x:
self.trueMethod = MethodType(trueMethod, self, X)
elif not self.x:
self.falseMethod = MethodType(falseMethod, self, X)
You can create dict and on the bases of value you can access function like
def __init__(self, x):
self.x = x
self.my_dict = {True : lambda *a : print "True method", False: lambda *a: print "False method"}
Then you can access self.my_dict[self.x].

Python: Dynamically adding function to a class, whose name is contained in a string

What is the best way to create a new member function of a class with function name contained as string? Also, this new function is merely as pass-through for another object(helper class), which has the same function name but with variable arguments. I use lambda to achieve this, but I don't know how to handle the scenario, where my pass-through wrapper would be more than one-statement (which is my requirement)
# This is a helper class
class Compensation:
def bonus(self):
return 10000
def salary(self):
# Do something
def stack(self):
# Do something
# This is a employer class
class employee:
def __init__(self):
self.compensation = Compensation()
# This is a wrapper that creates the function
def passThru(funcName):
fn = "employee."+funcName+"=" + "lambda self, *arg: self.compensation." + funcName +"(*arg)"
exec(fn)
fnNames = ["bonus", "salary", "stocks"]
for items in fnNames: passThru(items)
emp = employee()
emp.bonus() # returns 1000
All that trickery with exec gives me a headache ;-) I'm not exactly clear on what you want to do, but adding a new method with a name given by a string is really quite easy. For example,
class employee:
pass
# Some multiline-function.
def whatever(self, a, b):
c = a + b
return c
e = employee()
# Make `whatever` an `employee` method with name "add".
setattr(employee, "add", whatever)
print e.add(2, 9)
Whenever you're reaching for exec, you're probably missing a straightforward way.
EDIT: an oddity here is that if someone tries to display e.add, they'll get a string claiming its name is whatever. If that bothers you, you can add, e.g.,
whatever.__name__ = "add"
Fleshing it out
Is this closer to what you want? Note that #gnibbler suggested much the same, although more telegraphically:
class Compensation:
def bonus(self, a):
return 10000 + a
def salary(self):
return 20000
def stack(self, a=2, b=3):
return a+b
class employee:
def __init__(self):
self.comp = Compensation()
e = employee()
for name in "bonus", "salary", "stack":
def outer(name):
def f(self, *args, **kw):
return getattr(self.comp, name)(*args, **kw)
f.__name__ = name
return f
setattr(employee, name, outer(name))
print e.bonus(9)
print e.salary()
print e.stack(b="def", a="abc")
That displays:
10009
20000
abcdef
All that said, you might want to re-think your architecture. It's strained.
You want setattr. Let's say you have:
>>> inst = Foo(10)
>>> class Foo(object):
def __init__(self, x):
self.x = x
>>> inst = Foo(10)
>>> inst2 = Foo(50)
If you want to add a method to all instances of the class, then setattr on the class. This function will end up being an unbound method on the class, becoming bound in each instance, so it will take the self param:
>>> setattr(inst.__class__, "twice_x", lambda self: self.x * 2)
>>> inst.twice_x()
20
>>> inst2.twice_x()
100
If you want to add the function to just one instance of the class, then setattr on the instance itself. This will be a regular function which will not take the implicit self argument:
>>> setattr(inst, "thrice_x", lambda: inst.x * 3)
>>> inst.thrice_x()
30
>>> inst2.thrice_x()
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
inst2.thrice_x()
AttributeError: 'Foo' object has no attribute 'thrice_x'
You are looking for setattr/getattr.
for func_name in fnNames:
setattr(employee, func_name, (lambda self, *args:getattr(self.compensation, func_name)(*args)))
This still has a problem because you need the lambda function to be closed over func_name. While you could create a closure with another lambda, I'll pull it out into another function for readability
for func_name in fnNames:
def f(func_name): # close the lambda over "func_name"
return lambda self, *args:getattr(self.compensation, func_name)(*args)
setattr(employee, items, f(func_name))

Type error with classmethod constructors

I'm implementing several constructors using #classobj. I'm not only setting variables, but also calling methods in the new class:
class Example:
def __init__(self):
pass
#classmethod
def constructor1(cls,x,y):
self=cls
self.__x = x
self.__somemethod(self,y)
...
I get the following error:
unbound method __somemethod() must be called with Example instance as
first argument (got classobj instance instead)
How do I resolve this problem?
If you're wanting your class method to be a constructor, you probably want to be creating an instance of the class you get passed in as cls. I suspect you're trying to do that with your self = cls line, but you're not actually creating a new instance because you've neglected to put parentheses. There are some other issues too, but I think that is the key one. Here's a fixed constructor:
#classmethod
def constructor1(cls,x,y):
self=cls() # parentheses added, to make it a call
self.__x = x
self.__somemethod(y) # self is not needed as a parameter here
return self # return the new instance
looks like __somemethod is not a classmethod, but a "normal" method.
And normal methods expect an actual instance as the first parameter, not a class.
And because constructor1 is decorated as a #classmethod, cls is the class itself - which you pass to __somemethod.
That cannot work.
You should reconsider your design approach.
Addendum:
Maybe you meant something like this?
#classmethod
def constructor1(cls, x, y):
newinst = cls()
newinst.__x = x
cls.__somemethod(newinst, y)
That'd be better written as followed, though:
#classmethod
def constructor1(cls, x, y):
newinst = cls()
newinst.__x = x
newinst.__somemethod(y)
actually, I like neighter approach - seems like a codesmell of overcomplexity to me.
This may be a template of what I think you're trying to achieve...
import random
class Something(object):
def __init__(self, value, **kwargs):
self.value = value
for k, v in kwargs.iteritems():
setattr(self, k, v)
#classmethod
def from_iterable(cls, iterable):
return cls(sum(iterable), description='came from from_iterable')
#classmethod
def make_random(cls):
return cls(random.randint(1,1000), is_random=True)
a = Something.from_iterable([1, 2, 3])
b = Something.make_random()
c = Something(56)
for obj in (a, b, c):
print type(obj), obj.value
<class '__main__.Something'> 6
<class '__main__.Something'> 308
<class '__main__.Something'> 56
Thanks to ch3ka's answer and Tim Pietzcker's comment, I found my error: I used the factory method from http://jjinux.blogspot.co.at/2008/11/python-class-methods-make-good.html and forgot the () in the line self=cls(). Now it works just fine:
class Example:
def __init__(self):
pass
#classmethod
def constructor1(cls,x,y):
self=cls()
self.__x = x
self.__somemethod(self,y)
...

Categories