I am really curious as to how Python's interpreter makes an attribute x out of a method x through x=property(x). If I could take a look at the C code, I would feel much better.
The type is defined in the descrobject.c file.
You can locate Python types like these by first looking for the function name in bltinmodule.c; in this case the following line defines the property() function:
SETBUILTIN("property", &PyProperty_Type);
then grep for the PyProperty_Type definition in the Objects subdirectory.
Related
I'm writing some code for a calculus package in python. Ideally, I would like to support compositions of user-defined functions. For example, a user could define functions within my SingleVariable class like so:
f = SingleVariable('sin(x)')
g = SingleVariable('x+4')
and then a composition
h = SingleVariable('f(g(x))')
These functions can be integrated, differentiated, etc. The method used to evaluate the function at a point is as follows:
def infix_to_function(infix, variable):
def f(x):
expression = infix.replace(variable, str(x)).replace('^', '**')
return eval(expression)
return f
This works fine for functions like sin and ln because they can be loaded ahead of time so as to be recognized by eval. However, this obviously doesn't work for user-defined functions because they don't exist in the namespace in which the function is actually evaluated. Returning to the example functions f and g, i would like a function defined as
h = SingleVariable('f(g(x))')
to be equivalent to
h = SingleVariable('sin(x+4)')
I'm writing the package in PyCharm and testing it by importing to a Jupyter Notebook. I thought about adding the function to a list of some sort when a new SingleVariable object is initialized, but that would require somehow grabbing the name of the variable it is being assigned to.
Is there any way to add the functions I define in the Jupyter Notebook to the namespace of the PyCharm package so that they can be recognized by eval and have the behavior described?
You can try passing in globals() to eval like eval(expression, globals()). I believe Jupyter Notebooks will put any functions that have been defined into the global namespace.
However, using exec() and globals() can cause a lot of problems - so make sure you really understand what you are doing.
It will be a bit more complicated but if you plan to build this out to be very general you may want to look at a lexing libraries like http://www.dabeaz.com/ply/example.html which can help you ensure that the input provide is valid and parsed correctly.
As a small example of the type of problems you can have - based on your sample code I think:
f = SingleVariable('sin(s)')
may not work the way you expect...
I would like to assign an another function to len in __init__.py file of my package the following way:
llen = len
len = lambda x: llen(x) - 1
It works fine, but only in the __init__.py file. How can I make it affect other modules in my package?
This may not be the answer you're looking for, but I wouldn't do this if I were you (and I'm pretty sure you can't easily, anyway).
The reason why you shouldn't is that python uses len internally on it's objects to perform certain operations.
Another reason is pure broken logic. Your len function defined above would return a negative length for empty lists, or empty things. This seems quite broken to me.
What you can do, is override the length method only on certain classes (this might make a lot of sense for you). For this you can use operator overloading, just override the method __len__ in your class:
class MyList(object):
def __len__(self,):
# Do your thing
You may also want to look into meta classes, there is a very good stack overflow question on this subject.
When you try to load a name that is not defined as a module-level global or a function local, Python looks it up in the __builtin__(builtins in Python 3) module. In both versions of Python, this module is also availabe as __builtins__ in the global scope. You can modify this module and this will affect not only your code but any python code anywhere that runs after your code runs!!
import __builtin__ as builtins # import builtins in python 3
llen = len
builtins.len = lambda a:llen(a) - 1
I already use this function to change some string to class object.
But now I have defined a new module. How can I implement the same functionality?
def str2class(str):
return getattr(sys.modules[__name__], str)
I want to think some example, but it is hard to think. Anyway, the main problem is maybe the file path problem.
If you really need an example, the GitHub code is here.
The Chain.py file needs to perform an auto action mechanism. Now it fails.
New approach:
Now I put all files under one filefold, and it works, but if I use the modules concept, it fails. So if the problem is in a module file, how can I change the string object to relative class object?
Thanks for your help.
You can do this by accessing the namespace of the module directly:
import module
f = module.__dict__["func_name"]
# f is now a function and can be called:
f()
One of the greatest things about Python is that the internals are accessible to you, and that they fit the language paradigm. A name (of a variable, class, function, whatever) in a namespace is actually just a key in a dictionary that maps to that name's value.
If you're interested in what other language internals you can play with, try running dir() on things. You'd be surprised by the number of hidden methods available on most of the objects.
You probably should write this function like this:
def str2class(s):
return globals()[s]
It's really clearer and works even if __name__ is set to __main__.
I try to list all the attributes of an object in Python pdb.
Let's say I want to list all the attributes and all methods of sys.stderr.
How can I do that?
For pdb, you should be able to do p dir(a).
If a is your object, use dir(a) to get a list of its symbols. See the documentation about the dir function for more information.
print dir(object_name) will list all the attributes of object for you.
pdb is like a python shell, what you can do in pdb is what you can do in Python (except maybe some very exotic stuff)
You can set variables, call functions, ...
dir is the right function to call. It should work on any objects as it can either default to the builtin or be implemented but I have indeed seen objects on which it fails. I guess it has to do with "old" python code (in my failing case : the suds library)
Usually __dict__ can be of some help too on the pdb debugger
question pretty much says it all.
i'd like to look at the code in this fashion:
>>>f = open("x.txt")
>>>print contents of f.__enter__() #<- how can I do this?
No. (Other than looking at the Python source code.)
>>> f = open("x.txt")
>>> f.__enter__
<built-in method __enter__ of file object at 0x022E4E90>
So the implementation of __enter__ is somewhere inside Python's C code.
It's actually in Objects/fileobject.c which you can find in the Python source tree [note: I think that's the currently-latest thing on the 2.7 branch; there's probably a better way to link to it] and looking at the code you'll see that actually f.__enter__ returns f itself. Of course that's just what happens in this particular case; other objects' __enter__ methods will do entirely different things.
In this case, it happens that the __enter__ method is native code. In others it may be Python code, but you still can't generally see it from inside Python.
>>> import decimal
>>> decimal.localcontext().__enter__
<bound method _ContextManager.__enter__ of <decimal._ContextManager object at 0x02192B50>>
That's Python bytecode rather than native code. You can see the bytecode:
import dis
dis.dis(decimal.localcontext().__enter__)
but the original Python source code is not guaranteed to be available. But you can try:
import inspect
print inspect.getsource(decimal.localcontext().__enter__)
which will sometimes do what you want.
You can't, at least not from an abritary callable (or any other) object. You can try to find the source code, and there's even a function in the standard library that can do this in many cases. However, the I/O modules are propably written in C, so you'd have to go and search the repository.