Difference between 'function' and 'method'

Ì

Ìð¹Ï

Howdy everyone,

This is a big problem puzzles me for a long time. The core question is:
How to dynamically create methods on a class or an instance?

Let me state it step by step.
1.
def gunc(self):
pass
class A(object):
def func(self):
pass
a = A()
a.func # gives "bound method", type is "instancemethod"
A.func # gives "unbound method", type is "instancemethod"
gunc # gives "function", type if "function"

# ?? Does this line attach a method to instance? ... I don't think so.
a.gunc = gunc

I found stardard library 'new' may help. Is that right?

2.
a = A() # instance of old class A
# Do attach a new method to class A...
b = A() # instance of new class A
Does "a" can get the new method automatically?
Does new method have the *same* concept level with old methods?
Especially, if there
are classes inherit from class A, how does name resolution work on this case?

3.
How do I write a decroator for a method? Eg:
class A(object):
@my_dec
def func(self):
pass
Here, my_dec should return a method rathar than a function/lambda. Am I right?
What does @property @staticmethod... really do? I cannot step-into them for
source code.

4.
If most of above questions can be solved, then it would be easy to implement
the feature: "dynamic property attach".
Eg:
One class can read/store settings from/to some file based on
the file content.
# File: cfg.ini
x = 1
y = python
config = SettingClass('cfg.ini') # dynamically build up properties x and y.
x = config.x # x will be set to 1 (str -> int convertion would be
done by 'property x')
y = config.y # y will be set to 'python'
config.x = 9 # 'x = 9' is written to cfg.ini.

How to implement
^_^ Maybe there are some library does the same thing. What is it? How
to implement ?


Thank you for your attention!
 
P

Paul Boddie

This is a big problem puzzles me for a long time. The core question is:
How to dynamically create methods on a class or an instance?

Let me state it step by step.
1.
def gunc(self):
pass
class A(object):
def func(self):
pass
a = A()
a.func # gives "bound method", type is "instancemethod"
A.func # gives "unbound method", type is "instancemethod"
gunc # gives "function", type if "function"

# ?? Does this line attach a method to instance? ... I don't think so.
a.gunc = gunc

No, unfortunately not. You might get the detailed explanation from
someone else, but generally, you have to assign functions to classes;
these are then exposed as methods via instances of such classes.

A.gunc = gunc
I found stardard library 'new' may help. Is that right?

Yes, it can help:

import new
a.gunc = new.instancemethod(gunc, a, A)
2.
a = A() # instance of old class A
# Do attach a new method to class A...
b = A() # instance of new class A
Does "a" can get the new method automatically?

Can "a" get the new method automatically? Apparently, yes:

class A:
pass

a = A()

def f(self, x):
print x

A.f = f
a.f(123) # works, printing 123
Does new method have the *same* concept level with old methods?
Especially, if there
are classes inherit from class A, how does name resolution work on this case?

As far as I'm aware, after you've added a method to a class, instances
will regard the method like all the previously existing methods, since
method lookup is a dynamic operation.

I'll not address your other questions in this message since I'm not a
heavy user of decorators and don't want to provide a quick answer
without fully testing it first. However, it is important to remember
that the "magic" occurs for class attributes, not instance attributes.
So, for example, it's quite possible that you'd want to assign a
function to an instance attribute, but you wouldn't want the instance
to suddenly "own" that function...

def somefunc(x, y):
# Do something with x and y...
return x + y

a = A()
a.somefunc = somefunc # store the function somewhere

# Later...

adder = a.somefunc

# Later still...

result = adder(p, q) # wouldn't work if somefunc became a method

Python seems to do the most intuitive thing, I think, but it's quite
tricky to contemplate all the implications.

Paul

P.S. I can never really remember all the different situations and
outcomes with method assignment, but then it's something I hardly ever
do. I'd be interested to know whether my situation is unusual, however.
 
B

Bruno Desthuilliers

?? a écrit :
Howdy everyone,

This is a big problem puzzles me for a long time. The core question is:
How to dynamically create methods on a class or an instance?

class Foo(object):
pass

def bar(self, arg):
print "in bar : self == % - arg == %s" % (self, str(arg))

def baaz(self, arg):
print "in baaz : self == % - arg == %s" % (self, str(arg))


f = Foo()

# adding bar as a method to class Foo
Foo.bar = bar

# f now can use bar:
f.bar(42)

# as well as new instances of Foo, of course
g = Foo()
g.bar()

# adding baaz as a method to f, the old way:
import new
f.baaz = new.instancemethod(baaz, f, type(f))

f.baaz()

# adding baaz as a method to g, the other way:
g.baaz = baaz.__get__(g, type(g))

g.baaz()

Let me state it step by step.
1.
def gunc(self):
pass
class A(object):
def func(self):
pass
a = A()
a.func # gives "bound method", type is "instancemethod"
A.func # gives "unbound method", type is "instancemethod"
gunc # gives "function", type if "function"

# ?? Does this line attach a method to instance? ... I don't think so.
a.gunc = gunc

It doesn't.

I found stardard library 'new' may help. Is that right?

cf above. If you work with old-style classes, you'll need
new.instancemethod.
2.
a = A() # instance of old class A
# Do attach a new method to class A...
b = A() # instance of new class A
Does "a" can get the new method automatically?

Yes. In Python, a class is itself an object, and is an attribute of it's
instances (instance.__class__). Names are resolved at runtime, and
attributes not found in the instance's __dict__ are looked up in the
class (and then in the superclasses etc).
Does new method have the *same* concept level with old methods?

The newly added method works exactly the same way as already existing
ones. Not a single difference. The class statement is just syntactic
sugar anyway. The following snippets are equivalent:

# sugar-coated:
class Boo(object):
faaz = 0

def far(self):
type(self).faaz += 1
print self

def frob(self):
print "yadda"

# raw:
def far(self):
type(self).faaz += 1
print self

Boo = type('Boo', (object,), dict(faaz=0, far=far))

def frob(self):
print "yadda"

Boo.frob = frob
Especially, if there
are classes inherit from class A, how does name resolution work on this case?

As usual.
3.
How do I write a decroator for a method?

Mostly the same way you'd write a decorator for a function
Eg:
class A(object):
@my_dec
def func(self):
pass
Here, my_dec should return a method rathar than a function/lambda. Am I right?

Nope. Functions defined within a class statement are plain ordinary
functions. It's the lookup mechanism that "turns them into methods" when
they are looked up as attribute of a class. In fact, Python "methods"
are thin callable wrappers around a function, a class and (most of the
time) an instance, wrappers which are created - usually at lookup time -
by the __get__ method of the function type (you may want to read about
the descriptor protocol on python.org - in the section about new style
classes IIRC).

Anyway, you can explore this by yourself:
>>> Boo.far
>>> b.far
>>> Boo.__dict__['far']
>>> Boo.__dict__['far'] is far True
>>> f1 = b.far
>>> f2 = b.far
>>> f1 is f2 False
>>> f1()
>>> dir(f1)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'im_class', 'im_func', 'im_self']

So, to answer your question: what you are decorating are functions, not
methods.
What does @property @staticmethod... really do? I cannot step-into them for
source code.

staticmethod wraps the function into an object that, when looked up as
an attribute, will return the raw function instead of returning a method.

property is a type that provides a simple generic implementation for
computed attributes. You'll find more detailed explanations in the doc
(but perhaps not in the most obvious place - it's somewhere in the peps
or in the 'nws style classes' stuff IIRC). Anyway, using it as a
decorator is a somewhat special case (well... to me at least), that will
defined a property with only a getter (the decorated function).
4.
If most of above questions can be solved, then it would be easy to implement
the feature: "dynamic property attach".
Eg:
One class can read/store settings from/to some file based on
the file content.
# File: cfg.ini
x = 1
y = python
config = SettingClass('cfg.ini') # dynamically build up properties x and y.
x = config.x # x will be set to 1 (str -> int convertion would be
done by 'property x')
y = config.y # y will be set to 'python'
config.x = 9 # 'x = 9' is written to cfg.ini.

How to implement

In this case, I'd rather use the __getattr__/__setattr__ hooks. It won't
work with properties nor custom descriptors, since descriptors only work
as class attributes - not as instance attributes (which BTW is why
setting a function as an instance attribute doesn't make it a method...)


here are a couple links to relevant documentation and stuffs:
http://www.python.org/download/releases/2.2.3/descrintro/
http://users.rcn.com/python/download/Descriptor.htm
http://www.python.org/doc/newstyle/
^_^ Maybe there are some library does the same thing.

Indeed:
http://www.voidspace.org.uk/python/configobj.html
http://wiki.python.org/moin/ConfigParserShootout


HTH
 
C

castironpi

?? a écrit :
Howdy everyone,
     This is a big problem puzzles me for a long time. The core question is:
How to dynamically create methods on a class or an instance?

class Foo(object):
    pass

def bar(self, arg):
    print "in bar : self == % - arg == %s" % (self, str(arg))

def baaz(self, arg):
    print "in baaz : self == % - arg == %s" % (self, str(arg))

f = Foo()

# adding bar as a method to class Foo
Foo.bar = bar

# f now can use bar:
f.bar(42)

# as well as new instances of Foo, of course
g = Foo()
g.bar()

# adding baaz as a method to f, the old way:
import new
f.baaz = new.instancemethod(baaz, f, type(f))

f.baaz()

# adding baaz as a method to g, the other way:
g.baaz = baaz.__get__(g, type(g))

g.baaz()
Let me state it step by step.
1.
def gunc(self):
    pass
class A(object):
    def func(self):
        pass
a = A()
a.func   # gives "bound method", type is "instancemethod"
A.func  # gives "unbound method", type is "instancemethod"
gunc    # gives "function", type if "function"
# ?? Does this line attach a method to instance?  ... I don't think so..
a.gunc = gunc

It doesn't.
I found stardard library 'new' may help. Is that right?

cf above. If you work with old-style classes, you'll need
new.instancemethod.
2.
a = A()  # instance of old class A
# Do attach a new method to class A...
b = A()  # instance of new class A
Does "a" can get the new method automatically?

Yes. In Python, a class is itself an object, and is an attribute of it's
instances (instance.__class__). Names are resolved at runtime, and
attributes not found in the instance's __dict__ are looked up in the
class (and then in the superclasses etc).
Does new method have the *same* concept level with old methods?

The newly added method works exactly the same way as already existing
ones. Not a single difference. The class statement is just syntactic
sugar anyway. The following snippets are equivalent:

# sugar-coated:
class Boo(object):
     faaz = 0

     def far(self):
         type(self).faaz += 1
         print self

     def frob(self):
         print "yadda"

# raw:
def far(self):
     type(self).faaz += 1
     print self

Boo = type('Boo', (object,), dict(faaz=0, far=far))

def frob(self):
    print "yadda"

Boo.frob = frob
Especially, if there
are classes inherit from class A, how does name resolution work on this case?

As usual.
3.
How do I write a decroator for a method?

Mostly the same way you'd write a decorator for a function
Eg:
class A(object):
    @my_dec
    def func(self):
        pass
Here, my_dec should return a method rathar than a function/lambda. Am I right?

Nope. Functions defined within a class statement are plain ordinary
functions. It's the lookup mechanism that "turns them into methods" when
they are looked up as attribute of a class. In fact, Python "methods"
are thin callable wrappers around a function, a class and (most of the
time) an instance, wrappers which are created - usually at lookup time -
by the __get__ method of the function type (you may want to read about
the descriptor protocol on python.org - in the section about new style
classes IIRC).

Anyway, you can explore this by yourself:

 >>> Boo.far
<unbound method Boo.far>
 >>> b.far
<bound method Boo.far of <__main__.Boo object at 0xb787f96c>>
 >>> Boo.__dict__['far']
<function far at 0xb7c28aac>
 >>> Boo.__dict__['far'] is far
True
 >>> f1 = b.far
 >>> f2 = b.far
 >>> f1 is f2
False
 >>> f1()
<__main__.Boo object at 0xb787f96c>
 >>> f2()
<__main__.Boo object at 0xb787f96c>
 >>> dir(f1)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'im_class', 'im_func', 'im_self']
 >>> f1.im_class
<class '__main__.Boo'>
 >>> f1.im_func
<function far at 0xb7c28aac>
 >>> f1.im_func is far
True
 >>> f1.im_self
<__main__.Boo object at 0xb787f96c>
 >>> f1.im_self is b
True
 >>> bf = Boo.far
 >>> bf.im_func
<function far at 0xb7c28aac>
 >>> bf.im_func is far
True
 >>> bf.im_class
<class '__main__.Boo'>
 >>> bf.im_self
 >>> bf.im_self is None
True
 >>> far.__get__(b, Boo)
<bound method Boo.far of <__main__.Boo object at 0xb787f96c>>
 >>> far.__get__(b, Boo).im_func is far
True
 >>>

So, to answer your question: what you are decorating are functions, not
methods.

Can you overload -type-'s decision of what to 'bind'?... whenever it
is it makes it.
 
C

castironpi

So, to answer your question: what you are decorating are functions, not
Can you overload -type-'s decision of what to 'bind'?... whenever it
is it makes it.
....
Traceback (most recent call last):
....
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'method' is not an acceptable base type

Unacceptable.
 
G

Gabriel Genellina

...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'function' is not an acceptable base type

Use delegation instead of inheritance. This class is almost
indistinguishable from a true function (when used as a method):

py> class myfunction(object):
.... __slots__ = ('func',)
.... #
.... def __init__(self, func):
.... object.__setattr__(self, 'func', func)
.... #
.... def __get__(self, instance, owner):
.... print "__get__ called for",instance
.... return self.func.__get__(instance, owner)
.... #
.... def __getattr__(self, name):
.... return getattr(self.func, name)
.... #
.... def __setattr__(self, name, value):
.... object.__setattr__(self.func, name, value)
....
py>
py> class P(object):
.... def foo(self, x): print 'foo',x
.... #
.... @myfunction
.... def bar(self, x): print 'bar',x
....
py> p = P()
py> p.foo(1)
foo 1
py> p.bar(2)
__get__ called for <__main__.P object at 0x00A3D650>
bar 2
py> P.foo(p, 1)
foo 1
py> P.bar(p, 2)
__get__ called for None
bar 2
py> print "p.foo", p.foo, type(p.foo)
p.foo <bound method P.foo of <__main__.P object at 0x00A3D650>> <type
'instancem
ethod'>
py> print "p.bar", p.bar, type(p.bar)
p.bar __get__ called for <__main__.P object at 0x00A3D650>
<bound method P.bar of <__main__.P object at 0x00A3D650>> __get__ called
for <__
main__.P object at 0x00A3D650>
<type 'instancemethod'>
py> print set(dir(p.foo))==set(dir(p.bar))
__get__ called for <__main__.P object at 0x00A3D650>
True
py> print "P.foo", P.foo, type(P.foo)
P.foo <unbound method P.foo> <type 'instancemethod'>
py> print "P.bar", P.bar, type(P.bar)
P.bar __get__ called for None
<unbound method P.bar> __get__ called for None
<type 'instancemethod'>
py> print set(dir(P.foo))==set(dir(P.bar))
__get__ called for None
True
py> P.__dict__['foo']
<function foo at 0x00A3BCB0>
py> P.__dict__['bar']
<__main__.myfunction object at 0x00A3D690>


Ok, let's try returning a different thing from __get__: bound method ->
partial with self already bound; unbound method -> the original function.

py> from functools import partial
py>
py> class myfunction2(myfunction):
.... def __get__(self, instance, owner):
.... if instance is None:
.... return self.func
.... return partial(self.func, instance)
....
py> @myfunction2
.... def baz(self, x): print 'baz',x
....
py> P.baz = baz
py> print p.baz
<functools.partial object at 0x00A3E5A0>
py> print P.baz
<function baz at 0x00AB1030>
py> p.baz(3)
baz 3
py> P.baz(p,3)
baz 3
 
C

castironpi

...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type 'function' is not an acceptable base type

Use delegation instead of inheritance. This class is almost  
indistinguishable from a true function (when used as a method):

py> class myfunction(object):
...   __slots__ = ('func',)
...   #
...   def __init__(self, func):
...     object.__setattr__(self, 'func', func)
...   #
...   def __get__(self, instance, owner):
...     print "__get__ called for",instance
...     return self.func.__get__(instance, owner)
...   #
...   def __getattr__(self, name):
...     return getattr(self.func, name)
...   #
...   def __setattr__(self, name, value):
...     object.__setattr__(self.func, name, value)
...
py>
py> class P(object):
...   def foo(self, x): print 'foo',x
...   #
...   @myfunction
...   def bar(self, x): print 'bar',x
...
py> p = P()
py> p.foo(1)
foo 1
py> p.bar(2)
__get__ called for <__main__.P object at 0x00A3D650>
bar 2
py> P.foo(p, 1)
foo 1
py> P.bar(p, 2)
__get__ called for None
bar 2
py> print "p.foo", p.foo, type(p.foo)
p.foo <bound method P.foo of <__main__.P object at 0x00A3D650>> <type  
'instancem
ethod'>
py> print "p.bar", p.bar, type(p.bar)
p.bar __get__ called for <__main__.P object at 0x00A3D650>
<bound method P.bar of <__main__.P object at 0x00A3D650>> __get__ called  
for <__
main__.P object at 0x00A3D650>
<type 'instancemethod'>
py> print set(dir(p.foo))==set(dir(p.bar))
__get__ called for <__main__.P object at 0x00A3D650>
True
py> print "P.foo", P.foo, type(P.foo)
P.foo <unbound method P.foo> <type 'instancemethod'>
py> print "P.bar", P.bar, type(P.bar)
P.bar __get__ called for None
<unbound method P.bar> __get__ called for None
<type 'instancemethod'>
py> print set(dir(P.foo))==set(dir(P.bar))
__get__ called for None
True
py> P.__dict__['foo']
<function foo at 0x00A3BCB0>
py> P.__dict__['bar']
<__main__.myfunction object at 0x00A3D690>

Ok, let's try returning a different thing from __get__: bound method ->  
partial with self already bound; unbound method -> the original function.

py> from functools import partial
py>
py> class myfunction2(myfunction):
...   def __get__(self, instance, owner):
...     if instance is None:
...         return self.func
...     return partial(self.func, instance)
...
py> @myfunction2
... def baz(self, x): print 'baz',x
...
py> P.baz = baz
py> print p.baz
<functools.partial object at 0x00A3E5A0>
py> print P.baz
<function baz at 0x00AB1030>
py> p.baz(3)
baz 3
py> P.baz(p,3)
baz 3

I actually don't believe you-- bar is not bound to an instance when P
is initialized... er, instantiated. However, the evidence indicates
my belief mechanism is faulty... and rather conclusively at that.
<moves to acquire new evidence> If P calls __get__( you ), is p a
gotcha?
 
G

Gabriel Genellina

[... long interactive example ...]
I actually don't believe you-- bar is not bound to an instance when P
is initialized... er, instantiated. However, the evidence indicates
my belief mechanism is faulty... and rather conclusively at that.
<moves to acquire new evidence> If P calls __get__( you ), is p a
gotcha?

I didn't cheat, that was an actual Python interactive session. So you'll
have to formulate a new theory taking into account the new facts... or
read how the descriptor protocol works http://www.python.org/doc/newstyle/
I don't understand your last sentence.
 
C

castironpi

[... long interactive example ...]
I actually don't believe you-- bar is not bound to an instance when P
is initialized... er, instantiated.  However, the evidence indicates
my belief mechanism is faulty... and rather conclusively at that.
<moves to acquire new evidence>  If P calls __get__( you ), is p a
gotcha?

I didn't cheat, that was an actual Python interactive session. So you'll  
have to formulate a new theory taking into account the new facts... or  
read how the descriptor protocol workshttp://www.python.org/doc/newstyle/
I don't understand your last sentence.

<joke>
If P gets, p gotcha.
</joke>

gotcha= partial( get, you ). bor hor hor. Yes... regarding the
descriptoring, just make it official! UserFunctionType or smg.
 
C

castironpi

If P gets, p gotcha.
</joke>

gotcha= partial( get, you ).  bor hor hor.  Yes...

Notwithstanding. Now bar has a name.

class myfunction:
__slots__ = ('func','name')
#
def __init__(self, func):
object.__setattr__(self, 'func', func)
object.__setattr__(self, 'name', None)
#
def __get__(self, instance, owner):
print( "__get__ called for",instance )
return self.func.__get__(instance, owner)
#
def __getattr__(self, name):
return getattr(self.func, name)
#
def __setattr__(self, name, value):
object.__setattr__(self.func, name, value)

class mymeta( type ):
def __init__( self, name, bases, namespace ):
for k,v in namespace.items():
if isinstance( v, myfunction ):
v.name= k

class P( metaclass= mymeta ):
def foo(self, x): print( 'foo',x )
#
@myfunction
def bar(self, x): print( 'bar',x )

p= P()
p.foo( 0 )
p.bar( 1 )
print( p.bar )
print( p.bar.name )

'''
output:
'''
foo 0
__get__ called for <__main__.P object at 0x00B481F0>
bar 1
__get__ called for <__main__.P object at 0x00B481F0>
<bound method P.bar of <__main__.P object at 0x00B481F0>>
__get__ called for <__main__.P object at 0x00B481F0>
bar
 
C

castironpi

Can you overload -type-'s decision of what to 'bind'?... whenever it
Notwithstanding.  Now bar has a name.

Now func has it.

from functools import wraps
class myfunction:
__slots__ = ('func','name')
#
def __init__(self, func):
@wraps( func )
def f( *ar, **kws ):
return func( self, *ar, **kws )
object.__setattr__(self, 'func', f)
object.__setattr__(self, 'name', None)
#
def __get__(self, instance, owner):
print( "__get__ called for",instance )
return self.func.__get__(instance, owner)
#
def __getattr__(self, name):
return getattr(self.func, name)
#
def __setattr__(self, name, value):
object.__setattr__(self.func, name, value)

class mymeta( type ):
def __init__( self, name, bases, namespace ):
for k,v in namespace.items():
if isinstance( v, myfunction ):
v.name= k

class P( metaclass= mymeta ):
def foo(self, x): print( 'foo',x )
#
@myfunction
def bar( fob,self, x): print( 'bar',fob,x )

p= P()
p.foo( 0 )
p.bar( 1 )
print( p.bar )
print( p.bar.name )
 
C

castironpi

Now func has it.

from functools import wraps
class myfunction:
    __slots__ = ('func','name')
    #
    def __init__(self, func):
      @wraps( func )
      def f( *ar, **kws ):
         return func( self, *ar, **kws )
      object.__setattr__(self, 'func', f)
      object.__setattr__(self, 'name', None)

Now:

Where is partialobject.__get__, why is 'attribute "__get__" read-
only', and for self.__get__= func.__get__, why is "'member_descriptor'
object is not callable"?
 
G

Gabriel Genellina

Now func has it.

from functools import wraps
class myfunction:
__slots__ = ('func','name')
#
def __init__(self, func):
@wraps( func )
def f( *ar, **kws ):
return func( self, *ar, **kws )
object.__setattr__(self, 'func', f)
object.__setattr__(self, 'name', None)
#
def __get__(self, instance, owner):
print( "__get__ called for",instance )
return self.func.__get__(instance, owner)
#
def __getattr__(self, name):
return getattr(self.func, name)
#
def __setattr__(self, name, value):
object.__setattr__(self.func, name, value)

class mymeta( type ):
def __init__( self, name, bases, namespace ):
for k,v in namespace.items():
if isinstance( v, myfunction ):
v.name= k

class P( metaclass= mymeta ):
def foo(self, x): print( 'foo',x )
#
@myfunction
def bar( fob,self, x): print( 'bar',fob,x )

p= P()
p.foo( 0 )
p.bar( 1 )
print( p.bar )
print( p.bar.name )

Mmm, looks too complicated and I don't see any advantage over the original
code. Functions already know their (original) name: func_name. If `name`
was just an example, note that functions already have writeable attributes
too, and my code exposes them as well. This should work with that version
(untested):

p = P()
print p.bar.func_name # -> bar
p.bar.im_func.anotherattribute = 1
print p.bar.anotherattribute # -> 1

(the attribute must be set on the *function* itself if you want it to be
somewhat persistent; methods are usually volatile objects)
 
C

castironpi

En Wed, 05 Mar 2008 02:57:58 -0200, <[email protected]> escribi�:










Mmm, looks too complicated and I don't see any advantage over the original  
code. Functions already know their (original) name: func_name. If `name`  
was just an example, note that functions already have writeable attributes  
too, and my code exposes them as well. This should work with that version  
(untested):

p = P()
print p.bar.func_name # -> bar
p.bar.im_func.anotherattribute = 1
print p.bar.anotherattribute # -> 1

(the attribute must be set on the *function* itself if you want it to be  
somewhat persistent; methods are usually volatile objects)

You read my mind.

I was just getting:
assert p.bar is p.bar
and failing.

But if you set them on im_func, instances don't have their own.
 
G

Gabriel Genellina

You read my mind.

You could try to write in a way that reading your mind isn't necesary...
I was just getting:
assert p.bar is p.bar
and failing.

But if you set them on im_func, instances don't have their own.

Instances don't have their own methods either. What do you actually want
to do? If you need a method with per-instance attributes, that looks like
another object to me.
 
C

castironpi

You could try to write in a way that reading your mind isn't necesary...



Instances don't have their own methods either. What do you actually want  
to do? If you need a method with per-instance attributes, that looks like  
another object to me.

Hi, great thanks for giving me your ear this far.

First of all, -I have it working-. But the design isn't encapsulated
quite right. Here's what I have. 69 lines, so I'll ask to post it
first. The gist is:

class ISS( SS, metaclass= autonaming ):
message= MessageDec()
@message
def user_act( msg, self, change ):
print( 'user act self change',
msg, self, change )

IncomingServer... but it originally came from 'clientsideserver.'

iss= ISS()

class OSS( SS, metaclass= autonaming ):
message= MessageDec()
user_act= message.out()

oss= OSS()

oss.message is a abstraction class that writes the method name into a
string, then sends it to OSS... outgoingserver or serverside.

Now that I'm writing it, and this is important, -to- the -newsgroup-,
I realize you could do it with a simple wrapper... include the
function name in parameters and call the pickler and send.

OSS then looks like this:

def something_happens( *ar ):
self.user_act( something_about( *ar ) )

So the message.out() instance pickles ( 'user_act', ar ) and sends
it. Then iss.incoming receives it, unpickles that string, gets
'user_act' from self, and invokes.

The cool part is the declaration of user_act= message.out(), which
uses a metaclass to assign its own name, and returns a function which
includes the object in its signature. Cool.

Yes it's working and a little slack. However-: this is the cool
part. I'd like messages to know which instance they came from, and
perform the sending & receiving encapsulated on their own--- not to
subclass class SS( Sending ): with various behaviors: that is, to
assign them as class attributes rather than superclasses.

The dreaming comes in here--- I'd like the class to look just like
this. Tell me it's possible.

And I changed my mind on posting the code, here's the whole thing.
Just get SS.send and SS.incoming into MessageDec. har har har har
har. Change anything before class OSS:. How does a weak reference
lookup in doublebound sound?



from functools import wraps
import pickle

class doublebound:
__slots__ = ( '_func', 'assname', '_orig' )
def __init__( self, func ):
@wraps( func )
def f( *ar, **kws ):
return func( self, *ar, **kws )
self.assname= None
self._func, self._orig= f, func
def __get__( self, instance, owner ):
return self._func.__get__( instance, owner )

class autonaming( type ):
def __init__( self, name, bases, namespace ):
for k,v in namespace.items():
if isinstance( v, doublebound ):
v.assname= k

class Sending:
def send( *ar, **kws ): raise NotImplemented

class MessageDec:
def __call__( self, fun ):
return doublebound( fun )
def out( self ):
return doublebound( self._send )
def _send( self, message, other, *ar, **kws ):
return other.send(
message.assname, *ar, **kws )

class SS( Sending ):
def send( self, methn, *ar, **kws ):
transpmessage= methn, ar, kws
transpstr= pickle.dumps( transpmessage )
self.far.incoming( transpstr )
def incoming( self, transpstr ):
transpmessage= pickle.loads( transpstr )
methn, ar, kws= transpmessage
meth= getattr( self, methn )
meth( *ar, **kws )

class OSS( SS, metaclass= autonaming ):
message= MessageDec()
user_act= message.out()
somethingelse= message.out()
@message
def amessage( msg, self, *change ):
print( 'something else', change )

class ISS( SS, metaclass= autonaming ):
message= MessageDec()
@message
def user_act( msg, self, change ):
print( 'user act self change',
msg, self, change )
@message
def somethingelse( msg, self, change= 'and' ):
print( 'something else', change )
amessage= message.out()

oss= OSS()
iss= ISS()
oss.far= iss
iss.far= oss
oss.user_act(2)
oss.somethingelse( 'butwhat?')
iss.amessage( 2, 3, 4, 5 )
 
G

Gabriel Genellina

oss.message is a abstraction class that writes the method name into a
string, then sends it to OSS... outgoingserver or serverside.

Now that I'm writing it, and this is important, -to- the -newsgroup-,
I realize you could do it with a simple wrapper... include the
function name in parameters and call the pickler and send.

OSS then looks like this:

def something_happens( *ar ):
self.user_act( something_about( *ar ) )

So the message.out() instance pickles ( 'user_act', ar ) and sends
it. Then iss.incoming receives it, unpickles that string, gets
'user_act' from self, and invokes.

The cool part is the declaration of user_act= message.out(), which
uses a metaclass to assign its own name, and returns a function which
includes the object in its signature. Cool.

Yes it's working and a little slack. However-: this is the cool
part. I'd like messages to know which instance they came from, and
perform the sending & receiving encapsulated on their own--- not to
subclass class SS( Sending ): with various behaviors: that is, to
assign them as class attributes rather than superclasses.

You may look at the SimpleXMLRPCServer class and see how it implements
introspection. It's rather easy (and doesn't require metaclasses nor
decorators nor any other fancy stuff; I think it works the same since
Python 2.1). Apparently you're doing a similar thing, but using pickles
instead of xmlrpc.
 
S

Sion Arrowsmith

Gabriel Genellina said:
You may look at the SimpleXMLRPCServer class and see how it implements
introspection. It's rather easy (and doesn't require metaclasses nor
decorators nor any other fancy stuff; I think it works the same since
Python 2.1). Apparently you're doing a similar thing, but using pickles
instead of xmlrpc.

It's not that difficult to graft pickles into SimpleXMLRPCServer --
I've done it, and if you're trying to sling large data structures
over the connection it's a massive performance win (even with
sgmlop in place to speed up XML parsing).
 
C

castironpi

Gabriel Genellina said:
You may look at the SimpleXMLRPCServer class and see how it implements  
introspection. It's rather easy (and doesn't require metaclasses nor  
decorators nor any other fancy stuff; I think it works the same since  
Python 2.1). Apparently you're doing a similar thing, but using pickles  
instead of xmlrpc.

It's not that difficult to graft pickles into SimpleXMLRPCServer --
I've done it, and if you're trying to sling large data structures
over the connection it's a massive performance win (even with
sgmlop in place to speed up XML parsing).
   her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump

Yeah, but I'd be grafting a non-blocking RPC sequence too.

-Instantiate- attributes of ISS upon instantiation.

class C:
d= D

c= C()
assert isinstance( c.d, D )
assert c.d is c.d

Which ones?
 
C

castironpi

Gabriel Genellina said:
En Thu, 06 Mar 2008 23:46:43 -0200, <[email protected]> escribi�:
[ ... ]
You may look at the SimpleXMLRPCServer class and see how it implements  
introspection. It's rather easy (and doesn't require metaclasses nor  
decorators nor any other fancy stuff; I think it works the same since  
Python 2.1). Apparently you're doing a similar thing, but using pickles  
instead of xmlrpc.
It's not that difficult to graft pickles into SimpleXMLRPCServer --
I've done it, and if you're trying to sling large data structures
over the connection it's a massive performance win (even with
sgmlop in place to speed up XML parsing).
   her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump

Yeah, but I'd be grafting a non-blocking RPC sequence too.

-Instantiate- attributes of ISS upon instantiation.

class C:
  d= D

c= C()
assert isinstance( c.d, D )
assert c.d is c.d

Which ones?

Two options: instantiate all attributes, or ones with a certain
property, such as name or superclass.

class C:
inst_d= D
#actually gets bound to 'd', optionally

class C:
d= inst( D )

I think what I'm looking for is an attribute wrapper.

class C:
@inst
d= D

But the closest the syntax goes is:

class C:
class d( D ): pass

(which takes us back to one of Steven's posts some days ago.) ( def
f(x=None):/class C:/x= X/return C. ) and the d= inst( D ) solution.)

You either need to assign something to assign something to its name,

class C:
d= X

or declare it, but that only allows def and class statements
(correct?).

class C:
attr d: D

is ideal.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top