What is and isn't available to class methods in python? - python

My limited understand is that the second argument to types.FunctionTypes (dict) determines what is available to the function code. I'm curious how it gets gets decided when instantiating functions internally. To illustrate what I mean, if I try to copy a function dynamically:
a = 'test'
def foo():
print(a)
bar = types.FunctionType(
foo.__code__,
globals(),
'bar',
foo.__defaults__,
foo.__closure__
)
This seems to work fine with globals(), but am I missing anything? More confusing is a class method. If I do something like this:
a = 'test'
class Foo(object):
b = 'Foo prints this'
def myfunc():
print(a, self.b)
Bar = type('Bar', tuple(), dict())
Bar.b = 'Bar prints this'
ns = globals()
#should I do ns.update(something) here?
f = Foo.myfunc
Bar.myfunc = types.FunctionType(f.__code__, ns, 'myfunc', ...)
That example works, but not this more complicated one:
import imp
import builtins
class Foo(object):
def __init__(self):
super().__init__() # super(Foo, self) also fails
mod = imp.new_module('test')
mod.__builtins__ = builtins
mod.Foo = type('Foo', tuple(), dict())
f = Foo.__init__
ns = {}
ns.update(mod.__dict__) #missing something here
mod.Foo.__init__ = types.FunctionTypes(f.__code__, ns, '__init__', ...)
Could someone illuminate what should be in ns? What is available to a class method, and what isn't?
I'm not specifically trying to get the above code to work, I'm more looking for an explanation of why it doesn't.

The problem seems to be that "copying" the __closure__ attribute doesn't create a copy; that's the execution context in which the function body, (the def __init__) was itself executed; in support of the lexical scoping rules in the python language. Taking a look:
>>> [cell.cell_contents for cell in f.__closure__]
[<class '__main__.Foo'>]
Unsurprisingly, it's the class it was defined in. I'm not sure of a simple way of creating a new cell object besides using exec, to create a new class and method; You could probably copy the new cell around to additional methods to be added to the new class, but both the cell and the class would be brand new.

Related

Python How to create method of class in runtime

I am curious how to create a custom method for a class at runtime...
I mean for example with name of method, name of parameters, body of method read from database and assign this method to a class or to an instance.
I have a found possibility to add method that is already written:
class A:
def __init__(self):
pass
def method(self):
return True
A.method = method
a = A()
print(a.method())
but I am interested in completely assembling a new method from scratch:
name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"
# To create method from pieces
Is it possible using __dict__ ? Or how else this be done?
Methods are another attribute on the object that is the class. They can be added like other attributes:
Code:
class A:
def __init__(self):
pass
def method(self):
return True
def another_method(self):
return False
setattr(A, 'another_method', another_method)
Test Code:
a = A()
print(a.another_method())
Results:
False
Methods from a string:
Add if you really need to get your methods from a database or such you can use exec like:
method_string = """
def yet_another_method(self):
return type(self).__name__
"""
exec(method_string)
setattr(A, 'yet_another_method', yet_another_method)
a = A()
print(a.yet_another_method())
Results:
A
This answer has to be treated with care, using exec or eval can run arbitary code and may compromise your system. So if you rely on user-input to create the function you mustn't use this!!!
The warning aside you can simply create anything using exec:
exec("""
def method():
return True
""")
>>> method()
True
So what you basically need is just a way to get your requirements in there:
functionname = 'funfunc'
parameters = ['a', 'b']
body = 'return a + b'
exec("""
def {functionname}({parameters}):
{body}
""".format(
functionname=functionname,
parameters=', '.join(parameters),
body='\n'.join([' {line}'.format(line=line) for line in body.split('\n')])))
The body will be indented so that it's valid syntax and the parameter list will be joined using ,. And the test:
>>> funfunc(1, 2)
3
One of the best solutions that I have found is the following:
def import_code(code, name, add_to_sys_modules=0):
"""
Import dynamically generated code as a module. code is the
object containing the code (a string, a file handle or an
actual compiled code object, same types as accepted by an
exec statement). The name is the name to give to the module,
and the final argument says wheter to add it to sys.modules
or not. If it is added, a subsequent import statement using
name will return this module. If it is not added to sys.modules
import will try to load it in the normal fashion.
import foo
is equivalent to
foofile = open("/path/to/foo.py")
foo = importCode(foofile,"foo",1)
Returns a newly generated module.
"""
import sys,imp
module = imp.new_module(name)
exec(code,module.__dict__)
if add_to_sys_modules:
sys.modules[name] = module
return module
class A:
def __init__(self):
pass
name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"
scratch = "def {0}({1}):\n\t{2}".format(name, ','.join(params), body)
new_module = import_code(scratch, "test")
A.method = new_module.method
a = A()
print(a.method())
Original function import_code by the following link http://code.activestate.com/recipes/82234-importing-a-dynamically-generated-module/
Using this solution I can dynamically create methods, load them in runtime and link to whatever I want object !!

Using getattr function on self in python

I am trying to write call multiple functions through a loop using the getattr(...). Snippet below:
class cl1(module):
I =1
Name= 'name'+str(I)
Func= 'func'+str(I)
Namecall = gettattr(self,name)
Namecall = getattr(self,name)()
This is when get the following code: self.name1 = self.func1()
The desire is to loop multiple of these but the code is not working. Can you please advise?
Firstly, do use CapitalLetters for Classes and lowercase_letters for variables as it is easier to read for other Python programmers :)
Now, you don't need to use getattr() inside the class itself
Just do :
self.attribute
However, an example will be:
class Foo(object): # Class Foo inherits from 'object'
def __init__(self, a, b): # This is the initialize function. Add all arguments here
self.a = a # Setting attributes
self.b = b
def func(self):
print('Hello World!' + str(self.a) + str(self.b))
>>> new_object = Foo(a=1, b=2) # Creating a new 'Foo' object called 'new_object'
>>> getattr(new_object, 'a') # Getting the 'a' attribute from 'new_object'
1
However, an easier way would just be referencing the attribute directly
>>> new_object.a
1
>>> new_object.func()
Hello World!12
Or, by using getattr():
>>> getattr(new_object, 'func')()
Hello World!12
Although I explained the getattr() function,
I don't seem to understand what you want to achieve, do post a sample output.

Does there exist empty class in python?

Does there exist special class in python to create empty objects? I tried object(), but it didn't allow me to add fields.
I want to use it like this:
obj = EmptyObject()
obj.foo = 'far'
obj.bar = 'boo'
Should I each time(in several independent scripts) define new class like this?
class EmptyObject:
pass
I use python2.7
types.SimpleNamespace was introduced with Python 3.3 to serve this exact purpose. The documentation also shows a simple way to implement it yourself in Python, so you can add it to your pre-Python 3.3 setup and use it as if it was there (note that the actual implementation is done in C):
class SimpleNamespace (object):
def __init__ (self, **kwargs):
self.__dict__.update(kwargs)
def __repr__ (self):
keys = sorted(self.__dict__)
items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
return "{}({})".format(type(self).__name__, ", ".join(items))
def __eq__ (self, other):
return self.__dict__ == other.__dict__
But of course, if you don’t need its few features, a simple class Empty: pass does just the same.
If you are looking for a place holder object to which you can add arbitrary static members, then the closest I got is an empty lambda function.
obj = lambda: None # Dummy function
obj.foo = 'far'
obj.bar = 'boo'
print obj.foo, obj.bar
# far boo
Remember: obj is not an object of a class, object doesn't mean class instance, because in Python classes and functions are objects at runtime just like class instances
There is no types.SimpleNamespace in Python 2.7, you could use collections.namedtuple() for immutable objects instead:
>>> from collections import namedtuple
>>> FooBar = namedtuple('FooBar', 'foo bar')
>>> FooBar('bar', 'foo')
FooBar(foo='bar', bar='foo')
Or argparse.Namespace:
>>> from argparse import Namespace
>>> o = Namespace(foo='bar')
>>> o.bar = 'foo'
>>> o
Namespace(bar='foo', foo='bar')
See also, How can I create an object and add attributes to it?
You can create a new type dynamically with the fields you want it to have using the type function, like this:
x = type('empty', (object,), {'foo': 'bar'})
x.bar = 3
print(x.foo)
This is not entirely what you want though, since it will have a custom type, not an empty type.

How to automatically expose and decorate function versions of methods in Python?

I would like to expose the methods of a class as functions (after decoration) in my local scope. For example if I had a class and decorator:
def some_decorator(f):
...transform f...
return decorated_f
class C(object):
def __init__(self,x):
self.x = x
def f(self,y):
"Some doc string"
return self.x + y
def g(self,y,z):
"Some other doc string"
return self.x + y + z
and if I didn't care about automizing the process I could add the following code to my module the following:
#some_decorator
def f(C_instance,x):
"Some doc string."
return C_instance.f(x)
#some_decorator
def g(C_instance,x,y):
"Some other doc string."
return C_instance.g(x,y)
to the effect that the following evaluate to True
c = C(0)
f(c,1) == c.f(1)
But I would like to be able to do this automatically. Something like:
my_funs = expose_methods(MyClass)
for funname, fun in my_funs.iteritems():
locals()[funname] = some_decorator(fun)
foo = MyClass(data)
some_functionality(foo,*args) == foo.some_functionality(*args)
would do the trick (although it feels a little wrong declaring local variables this way). How can I do this in a way so that all the relevant attributes of the method correctly transform into the function versions? I would appreciate any suggestions.
P.S.
I am aware that I can decorate methods of class instances, but this is not really what I am after. It is more about (1) a preference for the function version syntax (2) the fact that my decorators make functions map over collections of objects in fancy and optimized ways. Getting behavior (2) by decorating methods would require my collections classes to inherit attributes from the objects they contain, which is orthogonal to the collection semantics.
Are you aware that you can use the unbound methods directly?
obj.foo(arg) is equivalent to ObjClass.foo(obj, arg)
class MyClass(object):
def foo(self, arg):
...
obj = MyClass()
print obj.foo(3) == MyClass.foo(obj, 3) # True
See also Class method differences in Python: bound, unbound and static and the documentation.
You say you have a preference for the function syntax. You could just define all your methods outside the class instead, and they would work exactly as you desire.
class C(object):
def __init__(self,x):
self.x = x
def f(c,y):
"Some doc string"
return c.x + y
def g(c,y,z):
"Some other doc string"
return c.x + y + z
If you want them on the class as well, you can always:
for func in f, g:
setattr(C, func.__name__, func)
Or with locals introspection instead of function name introspection:
for name in 'f', 'g':
setattr(C, name, locals()[name])
Or with no introspection, which is arguably a lot simpler and easier to manage unless you have quite a lot of these methods/functions:
C.f = f
C.g = g
This also avoids the potential issue mentioned in the comments on codeape's answer about Python checking that the first argument of an unbound method is an instance of the class.

Using Variables for Class Names in Python?

I want to know how to use variables for objects and function names in Python. In PHP, you can do this:
$className = "MyClass";
$newObject = new $className();
How do you do this sort of thing in Python? Or, am I totally not appreciating some fundamental difference with Python, and if so, what is it?
Assuming that some_module has a class named "class_name":
import some_module
klass = getattr(some_module, "class_name")
some_object = klass()
I should note that you should be careful here: turning strings into code can be dangerous if the string came from the user, so you should keep security in mind in this situation. :)
One other method (assuming that we still are using "class_name"):
class_lookup = { 'class_name' : class_name }
some_object = class_lookup['class_name']() #call the object once we've pulled it out of the dict
The latter method is probably the most secure way of doing this, so it's probably what you should use if at all possible.
In Python,
className = MyClass
newObject = className()
The first line makes the variable className refer to the same thing as MyClass. Then the next line calls the MyClass constructor through the className variable.
As a concrete example:
>>> className = list
>>> newObject = className()
>>> newObject
[]
(In Python, list is the constructor for the list class.)
The difference is that in PHP, you represent the name of the class you want to refer to as a string, while in Python you can reference the same class directly. If you must use a string (for example if the name of the class is created dynamically), then you will need to use other techniques.
If you need to create a dynamic class in Python (i.e. one whose name is a variable) you can use type() which takes 3 params:
name, bases, attrs
>>> class_name = 'MyClass'
>>> klass = type(class_name, (object,), {'msg': 'foobarbaz'})
<class '__main__.MyClass'>
>>> inst = klass()
>>> inst.msg
foobarbaz
Note however, that this does not 'instantiate' the object (i.e. does not call constructors etc. It creates a new(!) class with the same name.
If you have this:
class MyClass:
def __init__(self):
print "MyClass"
Then you usually do this:
>>> x = MyClass()
MyClass
But you could also do this, which is what I think you're asking:
>>> a = "MyClass"
>>> y = eval(a)()
MyClass
But, be very careful about where you get the string that you use "eval()" on -- if it's come from the user, you're essentially creating an enormous security hole.
Update: Using type() as shown in coleifer's answer is far superior to this solution.
I use:
newObject = globals()[className]()
I prefer using dictionary to store the class to string mapping.
>>> class AB:
... def __init__(self, tt):
... print(tt, "from class AB")
...
>>> class BC:
... def __init__(self, tt):
... print(tt, "from class BC")
...
>>> x = { "ab": AB, "bc": BC}
>>> x
{'ab': <class '__main__.AB'>, 'bc': <class '__main__.BC'>}
>>>
>>> x['ab']('hello')
hello from class AB
<__main__.AB object at 0x10dd14b20>
>>> x['bc']('hello')
hello from class BC
<__main__.BC object at 0x10eb33dc0>

Categories