Recognising whether a method is written in Python or Cython - python

I have a function which receives a method. I would like to recognise whether this method is written in Python or in Cython. Is there some reliable way to do this?

Just a thought but, assuming that "pure Python" means "not built-in" where the term “built-in” means “written in C” (according to Python's documentation):
We could then distinguish those two kinds by doing:
>>> import types
>>> types.BuiltinFunctionType
<type 'builtin_function_or_method'>
This is not C-compiled function :
>>> def foo(x):
... pass
>>> isinstance(foo, types.BuiltinFunctionType)
False
This is C-compiled function :
>>> from numpy import array
>>> isinstance(array, types.BuiltinFunctionType)
True
So any third-party module with C extensions will also report its functions as type builtin_function_or_method.
Related link:
http://docs.python.org/2/library/types.html
EDIT :
Another idea (a dirty one, but as Sage is not cooperative...):
>>> def foo(x):
... pass
>>> foo.some_attr = 0
is accepted, while:
>>> array.some_attr = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'builtin_function_or_method' object has no attribute 'some_attr'
Hoping this can be helpful... You tell me.

Related

What is the type, 'function' in Python? [duplicate]

I have a variable f. How can I determine its type? Here is my code, typed into a Python interpreter, showing that I get an error using the successful pattern of the many examples I have found with Google. (Hint: I am very new to Python.)
>>> i=2; type(i) is int
True
>>> def f():
... pass
...
>>> type(f)
<class 'function'>
>>> type(i)
<class 'int'>
>>> type(f) is function
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'function' is not defined
>>> f=3
>>> type(f) is int
True
The pythonic way to check the type of a function is using isinstance builtin.
i = 2
type(i) is int # not recommended
isinstance(i, int) # recommended
Python includes a types module for checking functions among other things.
It also defines names for some object types that are used by the
standard Python interpreter, but not exposed as builtins like int or
str are.
So, to check if an object is a function, you can use the types module as follows
def f():
print("test")
import types
type(f) is types.FunctionType # Not recommended but it does work
isinstance(f, types.FunctionType) # Recommended.
However, note that it will print false for builtin functions. If you wish to include those as well, then check as follows
isinstance(f, (types.FunctionType, types.BuiltinFunctionType))
However, use the above if you only want specifically functions. Lastly, if you only care about checking if it is one of function, callable or method, then just check if it behaves like a callable.
callable(f)

Add __getitem__ to module [duplicate]

This question already has an answer here:
Python: subscript a module
(1 answer)
Closed 7 years ago.
So it's quite a simple question. how do I add __getitem__ to a Python module. I mostly just want it as an ease of use, however it's confusing why it wouldn't let me 'just set it'. Below is a simple example of __getitem__ semi-working, however I wish for the other['test'] to work.
Here's the full output:
hello
hello
Traceback (most recent call last):
File "main.py", line 4, in <module>
print other['test']
TypeError: 'module' object has no attribute '__getitem__'
main.py
import other
print other.get('test')
print other.__getitem__('test')
print other['test']
other.py
test = 'hello'
def __getitem__(name):
return globals()[name]
get = __getitem__
I've tried to set __getitem__ using globals() aswell, globals()['__getitem__'] = __getitem__. It didn't work. And I tried to set it in main.py. So I'm confused as to why it's so adamant in not allowing me to use other['test'].
If it's impossible, then a short reason would be good.
Special methods are looked up on the type, not on an instance. Python looks for type(other).__getitem__() and that isn't available. You'd have to add the __getitem__ method to the module type; you can't in Python.
You'd have to replace the whole module instance in sys.modules with an instance of your own class to achieve what you want:
class MyModule(object):
def __init__(self, namespace):
self.__dict__.update(namespace)
def __getitem__(name):
return self.__dict__[name]
import other
import sys
sys.modules[other.__name__] = MyModule(other.__dict__)
This limitation doesn't just apply for modules, it applies for anything such that the type is not object or some subclass of object, or something with a metaclass that never bottoms out with object in the mro.
For example, you can also see this happening with type type:
In [32]: class Foo(type):
....: pass
....:
In [33]: type(Foo)
Out[33]: type
In [34]: Foo.__getitem__ = lambda x, y: x.__dict__.get(y)
In [35]: Foo.foo = "hello"
In [36]: Foo['foo']
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-38-e354ca231ddc> in <module>()
----> 1 Foo['foo']
TypeError: 'type' object has no attribute '__getitem__'
In [37]: Foo.__dict__.get('foo')
Out[37]: 'hello'
The reason is that at the C-API level, both module and type are particular instances of PyTypeObject which don't implement the required protocol for inducing the same search mechanism that the PyTypeObject implementation of object and friends does implement.
To change this aspect of the language itself, rather than hacking a replacement of sys.modules, you would need to change the C source definitions for PyModule_Type and PyType_Type such that there were C functions created for __getitem__ and added to the appropriate location in the C-API big PyTypeObject struct-o-magic-functions (a lot of which is expanded by the macro PyObject_HEAD) instead of 0 (which is the sentinel for does not exist), and recompile Python itself with these modified implementations of module and type.

type() in python 2.5 returning error when passing in string

Using Python 2.5.2 (r252:60911, Sep 30 2008, 15:42:03)
I try to use
type(x)
and receive the following error when passing in this string '2014-02-06 00:00:00'
TypeError: 'str' object is not callable
why does it not return str?
You probably shadowed the python function type with a string by doing the following:
>>> type = 'some string'
>>> # Lots of code
>>> x = 'other string'
>>> type(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
You can fix this by not using variable names that are also python builtin functions.
If you absolutely cannot rename your variable to be something other than type (_type or type_ will do), you can access the builtin function using the __builtin__ module
>>> type = 'some string'
>>> # Lots of code
>>> x = 'other string'
>>> import __builtin__
>>> __builtin__.type(x)
<type 'str'>
Anyone reading your code will hate you, though.

How to check for a function type in Python?

I've got a list of things, of which some can also be functions. If it is a function I would like to execute it. For this I do a type-check. This normally works for other types, like str, int or float. But for a function it doesn't seem to work:
>>> def f():
... pass
...
>>> type(f)
<type 'function'>
>>> if type(f) == function: print 'It is a function!!'
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'function' is not defined
>>>
Does anybody know how I can check for a function type?
Don't check types, check actions. You don't actually care if it's a function (it might be a class instance with a __call__ method, for example) - you just care if it can be called. So use callable(f).
Because function isn't a built-in type, a NameError is raised. If you want to check whether something is a function, use hasattr:
>>> hasattr(f, '__call__')
True
Or you can use isinstance():
>>> from collections import Callable
>>> isinstance(f, Callable)
True
>>> isinstance(map, Callable)
True
collections.Callable can be used:
import collections
print isinstance(f, collections.Callable)
import types
if type(f) == types.FunctionType:
print 'It is a function!!'

How to generate a module object from a code object in Python

Given that I have the code object for a module, how do I get the corresponding module object?
It looks like moduleNames = {}; exec code in moduleNames does something very close to what I want. It returns the globals declared in the module into a dictionary. But if I want the actual module object, how do I get it?
EDIT:
It looks like you can roll your own module object. The module type isn't conveniently documented, but you can do something like this:
import sys
module = sys.__class__
del sys
foo = module('foo', 'Doc string')
foo.__file__ = 'foo.pyc'
exec code in foo.__dict__
As a comment already indicates, in today's Python the preferred way to instantiate types that don't have built-in names is to call the type obtained via the types module from the standard library:
>>> import types
>>> m = types.ModuleType('m', 'The m module')
note that this does not automatically insert the new module in sys.modules:
>>> import sys
>>> sys.modules['m']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'm'
That's a task you must perform by hand:
>>> sys.modules['m'] = m
>>> sys.modules['m']
<module 'm' (built-in)>
This can be important, since a module's code object normally executes after the module's added to sys.modules -- for example, it's perfectly correct for such code to refer to sys.modules[__name__], and that would fail (KeyError) if you forgot this step. After this step, and setting m.__file__ as you already have in your edit,
>>> code = compile("a=23", "m.py", "exec")
>>> exec code in m.__dict__
>>> m.a
23
(or the Python 3 equivalent where exec is a function, if Python 3 is what you're using, of course;-) is correct (of course, you'll normally have obtained the code object by subtler means than compiling a string, but that's not material to your question;-).
In older versions of Python you would have used the new module instead of the types module to make a new module object at the start, but new is deprecated since Python 2.6 and removed in Python 3.

Categories

Resources