473,890 Members | 1,262 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Descriptors and side effects

Hello everyone,

I'm trying to do seemingly trivial thing with descriptors: have
another attribute updated on dot access in object defined using
descriptors.

For example, let's take a simple example where you set an attribute s
to a string and have another attribute l set automatically to its
length.
>>class Desc(str):
def __init__(self,v al):
self.s=val
self.l=len(val)
print "creating value: ", self.s
print "id(self.l) ", id(self.l)
def __set__(self, obj, val):
self.s=val
self.l=len(val)
print "setting value:", self.s, "length:", self.l
def __get__(self, obj, type=None):
print "getting value:", self.s, "length:", self.l
return self.l

>>class some(str):
m=Desc('abc')
l=m.l
creating value: abc
id(self.l) 10049688
>>ta=some()
ta.m='test string'
setting value: test string length: 11

However, the attribute ta.l didn't get updated:
>>ta.l
3

This is so much weirder that object id of ta.l is the same as id of
instance of descriptor:
>>id(ta.l)
10049688

A setter function should have updated self.l just like it updated
self.s:

def __set__(self, obj, val):
self.s=val
self.l=len(val)
print "setting value:", self.s, "length:", self.l

Yet it didn't happen.
>From my POV, the main benefit of a descriptor lies in its side effect:
on dot access (getting/setting) I can get other attributes updated
automatically: say, in class of Squares I get area automatically
updated on updating side, etc.

Yet, I'm struggling with getting it done in Python. Descriptors are a
great idea, but I would like to see them implemented in Python in a
way that makes it easier to get desireable side effects.

Nov 5 '07 #1
7 1358
mr****@gmail.co m a écrit :
Hello everyone,

I'm trying to do seemingly trivial thing with descriptors: have
another attribute updated on dot access in object defined using
descriptors.

For example, let's take a simple example where you set an attribute s
to a string and have another attribute l set automatically to its
length.
>>>class Desc(str):
def __init__(self,v al):
self.s=val
self.l=len(val)
print "creating value: ", self.s
print "id(self.l) ", id(self.l)
def __set__(self, obj, val):
self.s=val
self.l=len(val)
print "setting value:", self.s, "length:", self.l
def __get__(self, obj, type=None):
print "getting value:", self.s, "length:", self.l
return self.l

>>>class some(str):
m=Desc('abc')
l=m.l
First point : I don't get why Desc and some derive from str. Second
point: I don't get why you're storing the value and it's length in the
descriptor itself - obviously, you can't expect one descriptor instance
to be mapped to 2 distinct attributes. Third point: you understand that,
the way you wrote it, your descriptor will behave as a class (ie:shared)
attribute, don't you. Fourth point: if you hope some.l to be rebound
when m.l is, then you should learn Python basics before trying to jump
into descriptors.

The obvious, simple way to some your problem is to use a couple of
properties:

class Some(object):
@apply
def m():
def fget(self):
return self._m
def fset(self, val):
self._m = val
self._l = len(val)
return property(**loca ls())
@apply
def l():
def fget(self):
return self._l
def fset(self):
raise AttributeError( "%s.l is readonly" % self)
def __init__(self, m):
self.m = m

Now if you absolutely insist on using custom descriptors, you'll need
two of them: one to manage access to s, and the second to manage access
to l (which btw is a very bad name):

class DescS(object):
def __init__(self, val):
self._default = val

def __set___(self, obj, val):
obj._s = val
obj._l = len(val)

def __get__(self, obj, cls):
if obj is None:
return self # or self._default, or whatever
try:
return obj._s
except AttributeError:
return self._default
class DescL(object):
def __init__(self, descS):
self._descS = descS
def __get__(self, obj, cls):
if obj is None:
return self # or self._default, or whatever
try:
return obj._l
except AttributeError:
return len(self._descS ._default)
class Test(object):
m = DescS('abc')
l = DescL(m)

(nb : not tested)
Nov 5 '07 #2
mr****@gmail.co m wrote:
Hello everyone,

I'm trying to do seemingly trivial thing with descriptors: have
another attribute updated on dot access in object defined using
descriptors.
[snip]
A setter function should have updated self.l just like it updated
self.s:

def __set__(self, obj, val):
self.s=val
self.l=len(val)
print "setting value:", self.s, "length:", self.l

Yet it didn't happen.
[snip]

I noticed that Python will block all attribute overrides (either via
__dict__ through setattr) if the property has a __set__ method. The
standard property has this method and there is no way that I can find to
defeat it. So, here is what I use:

class ConstProperty(o bject):
"""
Provides a property that keeps its return value. The function will
only be called on the first access. After that the same value can
be used over and over again with no function call penalty. If the
cached value needs to be cleared, simply del the attribute.
>>class MyClass(object) :
... def __init__(self, x):
... self.x = x
... @ConstProperty
... def y(self):
... print "HERE"
... return self.x ** 2
...
>>obj = MyClass(5)
obj.y
HERE
25
>>obj.y
25
"""

def __init__(self, fn):
self.fn = fn

def __get__(self, target, cls=None):
if target is None:
return self.fn # Helps pydoc
else:
obj = self.fn(target)
setattr(target, self.fn.__name_ _, obj)
return obj

This is a little different than what you originally posted, but
hopefully it is close enough to be helpful.

Cheers!
Rich

Nov 5 '07 #3
Rich Harkins a écrit :
mr****@gmail.co m wrote:
>Hello everyone,

I'm trying to do seemingly trivial thing with descriptors: have
another attribute updated on dot access in object defined using
descriptors.

[snip]
>A setter function should have updated self.l just like it updated
self.s:

def __set__(self, obj, val):
self.s=val
self.l=len(val)
print "setting value:", self.s, "length:", self.l

Yet it didn't happen.
[snip]

I noticed that Python will block all attribute overrides (either via
__dict__ through setattr) if the property has a __set__ method.
It doesn't "block", it controls access to... Of course, if the __set__
method is a no-op, then nothing will happen.
The
standard property has this method and there is no way that I can find to
defeat it.
"defeat" ? Why don't you just pass the appropriate fset function to
property ?
So, here is what I use:

class ConstProperty(o bject):
"""
Provides a property that keeps its return value. The function will
only be called on the first access. After that the same value can
be used over and over again with no function call penalty. If the
cached value needs to be cleared, simply del the attribute.
>>class MyClass(object) :
... def __init__(self, x):
... self.x = x
... @ConstProperty
... def y(self):
... print "HERE"
... return self.x ** 2
...
>>obj = MyClass(5)
>>obj.y
HERE
25
>>obj.y
25
"""

def __init__(self, fn):
self.fn = fn

def __get__(self, target, cls=None):
if target is None:
return self.fn # Helps pydoc
else:
obj = self.fn(target)
setattr(target, self.fn.__name_ _, obj)
return obj

>>m = MyClass(5)
m.__dict__
{'x': 5}
>>m.y
HERE
25
>>m.__dict__
{'y': 25, 'x': 5}
>>m.x = 42
m.y
25
>>m.__dict__
{'y': 25, 'x': 42}
>>>

I'm sorry, but this looks like a very complicated way to do a simple thing:

class MySimpleClass(o bject):
def __init__(self, x):
self.x = x
self.y = x ** 2
Nov 5 '07 #4
Bruno Desthuilliers wrote:
[snip]
I'm sorry, but this looks like a very complicated way to do a simple thing:

class MySimpleClass(o bject):
def __init__(self, x):
self.x = x
self.y = x ** 2

Sure, for the absurdly simplified case I posed as an example. ;)

Here's another:

class Path(tuple):
@ConstProperty
def pathstr(self):
print "DEBUG: Generating string"
return '/'.join(self)

def __add__(self, other):
if isinstance(othe r, tuple):
return Path(tuple.__ad d__(self, other))
else:
return Path(tuple.__ad d__(self, (other,)))
>>ROOT = Path(())
path = ROOT + 'x' + 'y' + 'z'
path.pathst r
DEBUG: Generating string
/x/y/z
>>path.pathst r
/x/y/z

Basically, you can use ConstProperty above for items you don't want to
calculate automatically, but only when someone actually WANTS it. After
it is applied, then the penalties for function call of the property and
the computation are wiped out once the second access is requested.

Now, in the original example, len() might be considered too little for
this use and should be just generated in the constructor "for free".
OTOH, that assumes that __len__ hasn't been overridden to do something
more complicated and time consuming. If the antecedent object is
static, and the derivative consequent is also static, then ConstProperty
works very well and shouldn't cost more on the first access than any
other built-in property function.

BTW, another use is to avoid creating lots of unnecessary objects for
free unless they are accessed. Another quickie example:

class Node(object):
hasChildList = False
hasAttributesDi ct = False

@ConstProperty
def children(self):
self.hasChildLi st = True
return []

@ConstProperty
def attributes(self ):
self.hasAttribu tesDict = True
return {}

The extra class/object attributes can be used to test for whether the
associated objects were created. When used in a large tree, not
creating a lot of extra lists and dictionaries can save a lot of memory
and CPU as the children and attributes are not created or explored
unless they were manipulated.

Rich
Nov 5 '07 #5
Bruno Desthuilliers wrote:
Rich Harkins a écrit :
>mr****@gmail.co m wrote:
>>Hello everyone,

I'm trying to do seemingly trivial thing with descriptors: have
another attribute updated on dot access in object defined using
descriptors .
[snip]
>>A setter function should have updated self.l just like it updated
self.s:

def __set__(self, obj, val):
self.s=val
self.l=len(val)
print "setting value:", self.s, "length:", self.l

Yet it didn't happen.
[snip]

I noticed that Python will block all attribute overrides (either via
__dict__ through setattr) if the property has a __set__ method.

It doesn't "block", it controls access to... Of course, if the __set__
method is a no-op, then nothing will happen.
>The
standard property has this method and there is no way that I can find to
defeat it.

"defeat" ? Why don't you just pass the appropriate fset function to
property ?
> So, here is what I use:

class ConstProperty(o bject):
"""
Provides a property that keeps its return value. The function will
only be called on the first access. After that the same value can
be used over and over again with no function call penalty. If the
cached value needs to be cleared, simply del the attribute.
> >>class MyClass(object) :
... def __init__(self, x):
... self.x = x
... @ConstProperty
... def y(self):
... print "HERE"
... return self.x ** 2
...
> >>obj = MyClass(5)
>>obj.y
HERE
25
> >>obj.y
25
"""

def __init__(self, fn):
self.fn = fn

def __get__(self, target, cls=None):
if target is None:
return self.fn # Helps pydoc
else:
obj = self.fn(target)
setattr(target, self.fn.__name_ _, obj)
return obj


>>m = MyClass(5)
>>m.__dict__
{'x': 5}
>>m.y
HERE
25
>>m.__dict__
{'y': 25, 'x': 5}
>>m.x = 42
>>m.y
25
>>m.__dict__
{'y': 25, 'x': 42}
>>>


I'm sorry, but this looks like a very complicated way to do a simple thing:

class MySimpleClass(o bject):
def __init__(self, x):
self.x = x
self.y = x ** 2

Nov 5 '07 #6
Rich Harkins a écrit :
Bruno Desthuilliers wrote:
[snip]
>>I'm sorry, but this looks like a very complicated way to do a simple thing:

class MySimpleClass(o bject):
def __init__(self, x):
self.x = x
self.y = x ** 2



Sure, for the absurdly simplified case I posed as an example. ;)

Here's another:

class Path(tuple):
Ok, for an immutable type, it might eventually work.
@ConstProperty
def pathstr(self):
print "DEBUG: Generating string"
return '/'.join(self)
import os.path
help(os.path)
def __add__(self, other):
if isinstance(othe r, tuple):
return Path(tuple.__ad d__(self, other))
else:
return Path(tuple.__ad d__(self, (other,)))

>>>>ROOT = Path(())
path = ROOT + 'x' + 'y' + 'z'
path.pathst r

DEBUG: Generating string
/x/y/z
>>>>path.pathst r

/x/y/z
>>p = Path(('home', 'bruno'))
p += ['toto', 'tata']
p.pathstr
DEBUG: Generating string
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/tmp/python-8690chu", line 31, in __get__
File "/usr/tmp/python-8690chu", line 40, in pathstr
TypeError: sequence item 2: expected string, list found
>>>
Basically, you can use ConstProperty above for items you don't want to
calculate automatically, but only when someone actually WANTS it.
Which is easy to do with properties too.
After
it is applied, then the penalties for function call of the property and
the computation are wiped out once the second access is requested.
Agreed. But I wouldn't use such a scheme for mutable types - which are
still the common case.
Now, in the original example, len() might be considered too little for
this use and should be just generated in the constructor "for free".
OTOH, that assumes that __len__ hasn't been overridden to do something
more complicated and time consuming. If the antecedent object is
static, and the derivative consequent is also static,
You mean 'immutable', I assume...
then ConstProperty
works very well and shouldn't cost more on the first access than any
other built-in property function.

BTW, another use is to avoid creating lots of unnecessary objects for
free unless they are accessed. Another quickie example:

class Node(object):
hasChildList = False
hasAttributesDi ct = False

@ConstProperty
def children(self):
self.hasChildLi st = True
return []

@ConstProperty
def attributes(self ):
self.hasAttribu tesDict = True
return {}
Hmm... Perhaps not such a bad idea after all !-)
Nov 5 '07 #7
Bruno Desthuilliers wrote:
Which is easy to do with properties too.
True enough. It's the caching of the return value that's the value add
of course. ;)
>
> After
it is applied, then the penalties for function call of the property and
the computation are wiped out once the second access is requested.

Agreed. But I wouldn't use such a scheme for mutable types - which are
still the common case.
In many cases, yeah. Though I use a lot of immutable stuff in some of
my pet projects and such. ConstProperty is definitely not meant as a
replacement for property, only when something constant can be derived
from something else constant, especially when the derivation is expensive.
>Now, in the original example, len() might be considered too little for
this use and should be just generated in the constructor "for free".
OTOH, that assumes that __len__ hasn't been overridden to do something
more complicated and time consuming. If the antecedent object is
static, and the derivative consequent is also static,

You mean 'immutable', I assume...
Yeah, that's probably the better term.

[snip]

Again, I've used it quite a bit for various things and it's worked well
for the sort of thing the OP was requesting. Of course, your mileage
may vary. :)

Cheers!
Rich

PS: Sorry about the weird reposts. Thunderbird chaos.

Nov 5 '07 #8

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

Similar topics

3
2397
by: Sensorflo | last post by:
After browsing though many newsgroups articels I'm still not shure how operator precedence, operator associativity, sequence points, side effects go together. Currently I have the following view: An expression a = b() + c() * d++; can be transformed with the rules of operator associativity and operator precedence into a tree
13
2769
by: Steve Jorgensen | last post by:
== On Error Resume next, and Err.Number == If you want to call one of your procedures from another procedure, and check for errors afterward, you mayimagine that you should write code something like this... On Error Resuse Next MyFoo 123 lngErrNum = Err.Number On Error Goto 0
23
2384
by: Mantorok Redgormor | last post by:
Can emulation of the logical OR be done in standard C to obfuscate its use? So I don't have to use if(a||b) but instead make that even more obfuscated without its use but testing the same condition
9
6907
by: Rouben Rostamian | last post by:
Consider the following illustrative program: #include <stdio.h> double f(double x) { return x*x; } double g(double x)
13
1963
by: Mantorok Redgormor | last post by:
does volatile really inhibit side effects? that is the rules for sequence points and side effects do not apply to volatile objects? -- nethlek
5
3234
by: Niklaus | last post by:
This is one of the posts that i got. ------------------------------ A "side effect" of an operation is something that *happens*, not something that *is produced*. Examples: In the expression 2+2, the value 4 *is produced*. Nothing *happens*. Thus, 4 is the value of the expression, and it has no side effects. In the expression g=2.0, the value 2.0 is produced. What *happens* is that 2.0 is assigned to g. Thus, 2.0 is the value of the...
17
2361
by: dingoatemydonut | last post by:
The C99 standard states: "In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object)." Does that mean that in the following code, *p does not have to be evaluated since its side...
6
4923
by: Senthil | last post by:
Hi, Whenever i read a C++ book or a newsgroup posting, i come across the terms like " before the side effects completes" , "destructor with side effects" etc. What is this side effect mean in C++ world? Is it like something that is not desired but happens automatically and we cannot prevent it? Would be great if someone throws light on this. Thanks,
4
3047
by: Academia | last post by:
I get the following watch message: tsSource.Text.ToUpper() This expression causes side effects and will not be evaluated string The Text is &Edit
0
9978
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9820
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
11228
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10814
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
7169
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5849
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4676
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
4270
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
3276
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.