473,406 Members | 2,707 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Function creation (what happened?)

Can somebody give me an explanation what happened here (or point me to
some docs)?

Code:

HMMM = None

def w(fn):
print 'fn:', id(fn)
HMMM = fn
print 'HMMM:', id(HMMM)
def wrapper(*v, **kw):
fn(*v, **kw)
wrapper.i = fn
print 'wrapper:', id(wrapper)
return wrapper

class A:
@w
def __init__(self): pass

print 'A.__init__:', id(A.__init__)
print 'A.__init__.i:', id(A.__init__.i)
print 'HMMM:', id(HMMM)

Output:

fn: 10404208
HMMM: 10404208
wrapper: 10404272
A.__init__: 10376136
A.__init__.i: 10404208
HMMM: 505264624

Why did HMMM changed his id?!
Jun 27 '08 #1
8 1505
On May 9, 8:25 am, Viktor <alefn...@gmail.comwrote:
Can somebody give me an explanation what happened here (or point me to
some docs)?

Code:

HMMM = None

def w(fn):
print 'fn:', id(fn)
HMMM = fn
print 'HMMM:', id(HMMM)
def wrapper(*v, **kw):
fn(*v, **kw)
wrapper.i = fn
print 'wrapper:', id(wrapper)
return wrapper

class A:
@w
def __init__(self): pass

print 'A.__init__:', id(A.__init__)
print 'A.__init__.i:', id(A.__init__.i)
print 'HMMM:', id(HMMM)

Output:

fn: 10404208
HMMM: 10404208
wrapper: 10404272
A.__init__: 10376136
A.__init__.i: 10404208
HMMM: 505264624

Why did HMMM changed his id?!
The HMMM inside w is local to that function and is not the same HMMM
that is defined just before w.
Have a look at http://docs.python.org/ref/global.html

cheers
Jun 27 '08 #2
Viktor <al******@gmail.comwrote:
Can somebody give me an explanation what happened here (or point me to
some docs)?

Code:

HMMM = None

def w(fn):
print 'fn:', id(fn)
HMMM = fn
print 'HMMM:', id(HMMM)
def wrapper(*v, **kw):
fn(*v, **kw)
wrapper.i = fn
print 'wrapper:', id(wrapper)
return wrapper

class A:
@w
def __init__(self): pass

print 'A.__init__:', id(A.__init__)
print 'A.__init__.i:', id(A.__init__.i)
print 'HMMM:', id(HMMM)

Output:

fn: 10404208
HMMM: 10404208
wrapper: 10404272
A.__init__: 10376136
A.__init__.i: 10404208
HMMM: 505264624

Why did HMMM changed his id?!
It didn't: global HMMM refers to None both before and after executing
the rest of your code. The other HMMM is local to a particular
invocation of w. Try the same steps interactively (and try printing the
values not just the ids) and it may be more obvious:
>>HMMM = None
print 'HMMM:', id(HMMM)
HMMM: 505264624
>>def w(fn):
print 'fn:', id(fn)
HMMM = fn
print 'HMMM:', id(HMMM)
def wrapper(*v, **kw):
fn(*v, **kw)
wrapper.i = fn
print 'wrapper:', id(wrapper)
return wrapper
>>class A:
@w
def __init__(self): pass
fn: 18299952
HMMM: 18299952
wrapper: 18300016
>>print 'HMMM:', id(HMMM), HMMM
HMMM: 505264624 None
>>>
Jun 27 '08 #3
Viktor wrote:
Can somebody give me an explanation what happened here (or point me to
some docs)?

Code:

HMMM = None

def w(fn):
print 'fn:', id(fn)
HMMM = fn
print 'HMMM:', id(HMMM)
This prints the id() of the local (to the function w()) HMMM variable
def wrapper(*v, **kw):
fn(*v, **kw)
wrapper.i = fn
print 'wrapper:', id(wrapper)
return wrapper

class A:
@w
def __init__(self): pass

print 'A.__init__:', id(A.__init__)
print 'A.__init__.i:', id(A.__init__.i)
print 'HMMM:', id(HMMM)
while this prints the id() of the global HMMM variable. Python assumes that
a variable is local to a function if there is an assignment to that
variable anywhere inside that function.

If you want to change the variable (Python-lingo "rebind the name") HMMM
declare it as global in the function:

def w(fn):
global HMMM
# ...
HMMM = fn
# ...

Otherwise I've no idea what you are trying to do here...

Peter
Jun 27 '08 #4
This completely slipped of my mind... :)

I'm trying to change the:
http://wordaligned.org/svn/etc/echo/echo.py

So if the function is method it prints ClassName.MethodName instead of
MethodName(self|klass|cls=<... ClassName>).

But it turned out that in the decorator, the wrapped function is
always just a TypeFunction (I cannot find out if the function is
method, classmethod, staticmethod or just a plain function - tried
with inspect also)... And what is most interesting, when I do:

def w(fn):
print 'fn:', id(fn)
return fn

class A:
@w
def __init__(self): pass

print 'A.__init__:', id(A.__init__)

It turns out that the function I receive in the wrapper (even when I
return the same function) is not the function which will finally be
attached to the class...

Is there a way to find out in the decorator "what will the decorated
function be"?
Jun 27 '08 #5
On May 9, 9:02*am, Viktor <alefn...@gmail.comwrote:
This completely slipped of my mind... :)

I'm trying to change the:http://wordaligned.org/svn/etc/echo/echo.py

So if the function is method it prints ClassName.MethodName instead of
MethodName(self|klass|cls=<... ClassName>).

But it turned out that in the decorator, the wrapped function is
always just a TypeFunction (I cannot find out if the function is
method, classmethod, staticmethod or just a plain function - tried
with inspect also)... And what is most interesting, when I do:

def w(fn):
* * print 'fn:', id(fn)
* * return fn

class A:
* * @w
* * def __init__(self): pass

print 'A.__init__:', id(A.__init__)

It turns out that the function I receive in the wrapper (even when I
return the same function) is not the function which will finally be
attached to the class...

Is there a way to find out in the decorator "what will the decorated
function be"?
The decorator does receive the correct function. The problem is that
at this point __init__ is still a plain function, not a method, i.e.
the sequence is:
function -decorated function -method

There are several workarounds if you really want to differentiate
between functions and methods, none of them perfect:

- Apply the decorator after the class has been built, i.e. after the
functions have been wrapped in (unbound) methods:
A.__init__ = w(A.__init__)

- (Risky Hack): Guess whether a function is intended to be wrapped in
a method by checking whether its first argument is named "self".
Obviously this is not foolproof and it doesn't work for static/class
methods.

- Have two different decorators, one intended for plain functions and
one for functions-to-be-methods (e.g. @deco, @decomethod).

George
Jun 27 '08 #6
I figured out the first two solutions, but the third looks like the
most cleaner, think I'll use that one...

Thank you everyone. :)

On May 9, 3:24 pm, George Sakkis <george.sak...@gmail.comwrote:
The decorator does receive the correct function. The problem is that
at this point __init__ is still a plain function, not a method, i.e.
the sequence is:
function -decorated function -method

There are several workarounds if you really want to differentiate
between functions and methods, none of them perfect:

- Apply the decorator after the class has been built, i.e. after the
functions have been wrapped in (unbound) methods:
A.__init__ = w(A.__init__)

- (Risky Hack): Guess whether a function is intended to be wrapped in
a method by checking whether its first argument is named "self".
Obviously this is not foolproof and it doesn't work for static/class
methods.

- Have two different decorators, one intended for plain functions and
one for functions-to-be-methods (e.g. @deco, @decomethod).

George
Jun 27 '08 #7
En Fri, 09 May 2008 10:02:01 -0300, Viktor <al******@gmail.comescribió:
This completely slipped of my mind... :)

I'm trying to change the:
http://wordaligned.org/svn/etc/echo/echo.py

So if the function is method it prints ClassName.MethodName instead of
MethodName(self|klass|cls=<... ClassName>).

But it turned out that in the decorator, the wrapped function is
always just a TypeFunction (I cannot find out if the function is
method, classmethod, staticmethod or just a plain function - tried
with inspect also)... And what is most interesting, when I do:
The decorator receives the original, plain function (unless you chain decorators) and whatever it returns is used instead of the original function.
def w(fn):
print 'fn:', id(fn)
return fn

class A:
@w
def __init__(self): pass

print 'A.__init__:', id(A.__init__)

It turns out that the function I receive in the wrapper (even when I
return the same function) is not the function which will finally be
attached to the class...
Is there a way to find out in the decorator "what will the decorated
function be"?
Whatever you return from the decorator.
But the decorator returns a *function* and A.__init__ is a *method*, an instance method in fact. The function can be found as A.__dict__['__init__']. Try this:

m = A.__init__
print m, type(m), id(m)
f = A.__dict__['__init__']
print f, type(f), id(f)

A method combines a function with an instance that becomes the "self" argument. In your case you're building an "unbound" method because it's not tied to a particular instance, but even such unbound method is not the same thing as a plain function (it must ensure that its first argument, when called, is an A instance and not any other object).
The "magic" that converts a simple function into an instance method, for old-style classes like yours, was in the Class type itself. For new style classes, the descriptor protocol is used. See http://www.python.org/doc/newstyle/

--
Gabriel Genellina

Jun 27 '08 #8
Viktor a écrit :
This completely slipped of my mind... :)

I'm trying to change the:
http://wordaligned.org/svn/etc/echo/echo.py

So if the function is method it prints ClassName.MethodName instead of
MethodName(self|klass|cls=<... ClassName>).

But it turned out that in the decorator, the wrapped function is
always just a TypeFunction
s/TypeFunction/function/
(I cannot find out if the function is
method, classmethod, staticmethod or just a plain function
The latter, unless you decorate it with a classmethod or staticmethod
object before.
- tried
with inspect also)... And what is most interesting, when I do:

def w(fn):
print 'fn:', id(fn)
return fn

class A:
@w
def __init__(self): pass

print 'A.__init__:', id(A.__init__)

It turns out that the function I receive in the wrapper (even when I
return the same function) is not the function which will finally be
attached to the class...
Yes it is. But A.__init__ is *not* a function, it's a method. To get at
the function, you must use A.__dict__['__init__'] or A.__init__.im_func
Is there a way to find out in the decorator "what will the decorated
function be"?
Yes : the decorated function is the function you decorate with the
decorator.

Ok, this requires some explanations (nb: only valid for new-style classes):

- First point : what you declare in the class statement are plain
ordinary function. When the class statement is executed - that is,
usually[1], at import time - these function objects become attributes of
the class object.
[1] IOW : if your class statement is at the top-level of your module

- Second point: the function class implements the descriptor
protocol[2], so when an attribute lookup resolves to a function object,
the function's class __get__ method is invoked
[2] http://users.rcn.com/python/download/Descriptor.htm

- Third point: the function's __get__ method returns a method object,
either bound (if lookup was done on an instance) or unbound (if the
lookup was done on a class).

The function's class __get__ method could be implemented this way:

def __get__(self, instance, cls):
return types.MethodType(self, instance, cls)
- Fourth point: a method object is a thin callable wrapper around the
function, the instance (if provided), and the class. It could look like
this:

class Method(object):
def __init__(self, func, instance, cls):
self.im_func = func
self.im_self = instance
self.im_class = cls

def __repr__(self):
if self.im_self is None:
# unbound
return "<unbound method %s.%s>" \
% (self.im_class.__name__, self.im_func.__name__)
else:
# bound
return "<bound method %s.%s of %s>" \
% (self.im_class.__name__,
self.im_func.__name__,
self.im_self)

def __call__(self, *args, **kw):
if self.im_self is None:
try:
instance, args = args[0], args[1:]
except IndexError:
raise TypeError(
"unbound method %s() must be called with %s instance "
" as first argument (got nothing instead)" \
% (self.im_func.__name__, self.im_class.__name__)
if not isinstance(instance, self.im_class):
raise TypeError(
"unbound method %s() must be called with %s instance "
" as first argument (got %s instead)" \
% (self.im_func.__name__, self.im_class.__name__, instance)

else:
instance = self.im_self
return self.im_func(instance, *args, **kw)

The classmethod and staticmethod classes (yes, they are classes...) have
their own implementation for the descriptor protocol -
classmethod.__get__ returns a Method instanciated with func, cls,
type(cls), and staticmethod.__get__ returns the original function.
So as you can see - and classmethods and staticmethods set aside -, what
you decorate is *always* a function. And you just can't tell from within
the decorator if this function is called "directly" or from a method
object. The only robust solution is to decorate the function with your
own custom callable descriptor. Here's a Q&D untested example that
should get you started (warning : you'll have to check for classmethods
and staticmethods)

class wmethod(object):
def __init__(self, method):
self.method = method

def __call__(self, *args, **kw):
# called as a method
# your tracing code here
# NB : you can access the method's
# func, class and instance thru
# self.method.im_*,
return self.method(*args, **kw)

class w(object):
def __init__(self, func):
self.func = func

def __get__(self, instance, cls):
return wmethod(self.func.__get__(instance, cls))

def __call__(self, *args, **kw):
# called as a plain function
# your tracing code here
return self.func(*args, **kw)
HTH
Jun 27 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

58
by: jr | last post by:
Sorry for this very dumb question, but I've clearly got a long way to go! Can someone please help me pass an array into a function. Here's a starting point. void TheMainFunc() { // Body of...
4
by: anonymous | last post by:
Thanks your reply. The article I read is from www.hakin9.org/en/attachments/stackoverflow_en.pdf. And you're right. I don't know it very clearly. And that's why I want to understand it; for it's...
2
by: DFS | last post by:
The .mde creation just sits there, until I click on the blank screen and I get a (Not Responding) message in the title bar. The code compiles fine. Other systems of a similar large size compile...
8
by: vasudevram | last post by:
Hi, Is there any C library (free software or open source) for PDF creation, other than PDFLib? I'm looking for such a library to use for: 1. Porting my xtopdf PDF creation/conversion...
4
by: Ray | last post by:
Hello, I think I've had JavaScript variable scope figured out, can you please see if I've got it correctly? * Variables can be local or global * When a variable is declared outside any...
4
by: alex | last post by:
I am so confused with these three concept,who can explained it?thanks so much? e.g. var f= new Function("x", "y", "return x * y"); function f(x,y){ return x*y } var f=function(x,y){
1
by: Ricardo | last post by:
Hello, I have just happened on a nice Borland C++ 5.5 tutorial at http://www.webnotes.org/bcc55eng.htm, meant for the very novice like myself :) I got stuck at creation of .res file needed to...
2
by: Steven W. Orr | last post by:
I have some functions I need to create at runtime. The way I'm creating them is by calling a function which returns the string representation. Then I exec the string. Here's the code I use to...
1
by: Steven W. Orr | last post by:
I have this which works: #! /usr/bin/python strfunc = """ def foo( a ): print 'a = ', a """ exec strfunc globals() = foo foo( 'Hello' )
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.