473,770 Members | 1,757 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

reuse validation logic with descriptors

I am looking for a way to implement the same simple validation on many
instance attributes and I thought descriptors
(http://users.rcn.com/python/download/Descriptor.htm) looked like the
right tool.

But I am confused by their behavior on instance of my class.
I can only get the approximate behavior by using class variables.

I am looking for something like:

class SingleChar(obje ct):
def init(self):
self._char = None

def __set__(self, instance, value):
if not len(value) == 1:
raise ValueError
self._char = value

def __get__(self, instance, owner):
return self._char

class Flags(object):
def __init__(self):
self.a = SingleChar()
self.b = SingleChar()

f = Flags()
f.a = "a"
f.b = "bb"
exceptions.Valu eError
ValueError:

What I actually get when I try this is f.a and f.b become str instances.

Meanwhile, I can get this to work, except that a and b are now just class
attributes.

class CFlags(object):
a = SingleChar()
b = SingleChar()

What is the proper and clean way to accomplish this sort of thing, so that you
can reuse the logic in for many instance attributes across multiple classes?

Thanks, David S.

Jul 18 '05 #1
8 1620
David S. wrote:
I am looking for a way to implement the same simple validation on many
instance attributes and I thought descriptors
(http://users.rcn.com/python/download/Descriptor.htm) looked like the
right tool.

But I am confused by their behavior on instance of my class.
I can only get the approximate behavior by using class variables.

I am looking for something like:

class SingleChar(obje ct):
def init(self):
self._char = None

def __set__(self, instance, value):
if not len(value) == 1:
raise ValueError
self._char = value

def __get__(self, instance, owner):
return self._char

class Flags(object):
def __init__(self):
self.a = SingleChar()
self.b = SingleChar()

f = Flags()
f.a = "a"
f.b = "bb"
exceptions.Valu eError
ValueError:

What I actually get when I try this is f.a and f.b become str instances.

Meanwhile, I can get this to work, except that a and b are now just class
attributes.

class CFlags(object):
a = SingleChar()
b = SingleChar()

What is the proper and clean way to accomplish this sort of thing, so that you
can reuse the logic in for many instance attributes across multiple classes?


Looks like you're trying to reinvent the property descriptor. Try using
the builtin property instead:

py> def getchar(self):
.... if not hasattr(self, '_char'):
.... self._char = None
.... return self._char
....
py> def setchar(self, value):
.... if not len(value) == 1:
.... raise ValueError
.... self._char = value
....
py> singlechar = property(getcha r, setchar)
py> class Flags(object):
.... a = singlechar
.... b = singlechar
....
py> f = Flags()
py> f.a = "a"
py> f.b = "bb"
Traceback (most recent call last):
File "<interacti ve input>", line 1, in ?
File "<interacti ve input>", line 3, in setchar
ValueError

STeVe
Jul 18 '05 #2
Steven Bethard <steven.betha rd <at> gmail.com> writes:

David S. wrote:
I am looking for a way to implement the same simple validation on many
instance attributes and I thought descriptors
(http://users.rcn.com/python/download/Descriptor.htm) looked like the
right tool.

Looks like you're trying to reinvent the property descriptor. Try using
the builtin property instead:

py> def getchar(self):
... if not hasattr(self, '_char'):
... self._char = None
... return self._char
...
py> def setchar(self, value):
... if not len(value) == 1:
... raise ValueError
... self._char = value
...
py> singlechar = property(getcha r, setchar)
py> class Flags(object):
... a = singlechar
... b = singlechar
...
py> f = Flags()
py> f.a = "a"
py> f.b = "bb"
Traceback (most recent call last):
File "<interacti ve input>", line 1, in ?
File "<interacti ve input>", line 3, in setchar
ValueError

This still fails to work for instances variables of the class. That is
if I use your property in the following:
py> ...class Flags(object):
.... def __init__(self):
.... a = singlechar
....
py> f = Flags()
py> f.a = "a"

Now f.a.__class__._ _name__ returns 'str'. So the property was not
used at all.

Also, it seems that using a property, I can not do the other useful
things I can do with a proper class, like provide an __init__, __str__,
or __repr__.

Again, thanks,
David S.
Jul 18 '05 #3
David S. wrote:

This still fails to work for instances variables of the class. That is
if I use your property in the following:
py> ...class Flags(object):
... def __init__(self):
... a = singlechar
...
you should write that as:
class Flags(object):
a = singlechar
def __init__(self):
a = "a"

py> f = Flags()
py> f.a = "a"

Now f.a.__class__._ _name__ returns 'str'. So the property was not
used at all.

Also, it seems that using a property, I can not do the other useful
things I can do with a proper class, like provide an __init__, __str__,
or __repr__.
If you want "other useful things" then you can write a custom descriptor, like:

from weakref import WeakKeyDictiona ry

class SingleChar(obje ct):
def __init__(self):
"""raises ValueError if attribute is set to something
other than a single char"""
self.objdict = WeakKeyDictiona ry()
def __get__(self, obj, cls):
if isinstance(obj, cls):
try:
return self.objdict[obj]
except KeyError:
raise AttributeError, "property not set"
else:
return self
def __set__(self, obj, value):
if isinstance(valu e, str) and len(value) == 1:
self.objdict[obj] = value
else:
raise ValueError, value

class Flags(object):
a = SingleChar()
b = SingleChar()
See also: http://groups-beta.google.com/group/...c61a30a90133d2

for another example of this approach

Michael Again, thanks,
David S.


Jul 18 '05 #4
David S. wrote:
Steven Bethard <steven.betha rd <at> gmail.com> writes:

Looks like you're trying to reinvent the property descriptor. Try using
the builtin property instead:

py> def getchar(self):
... if not hasattr(self, '_char'):
... self._char = None
... return self._char
...
py> def setchar(self, value):
... if not len(value) == 1:
... raise ValueError
... self._char = value
...
py> singlechar = property(getcha r, setchar)
py> class Flags(object):
... a = singlechar
... b = singlechar
...
This still fails to work for instances variables of the class. That is
if I use your property in the following:
py> ...class Flags(object):
... def __init__(self):
... a = singlechar
...
py> f = Flags()
py> f.a = "a"

Yes, you need to assign it at the class level, as you will for any
descriptor. Descriptors only function as attributes of type objects.
But note that as I've used them above, they do work on a per-instance
basis. What is it you're trying to do by assigning them in __init__?
Do you want different instances of Flags to have different descriptors?
Also, it seems that using a property, I can not do the other useful
things I can do with a proper class, like provide an __init__, __str__,
or __repr__.


Well, you can write your own descriptors that do things much like
property, but note that __init__ will only be invoked when you first
create them, and __str__ and __repr__ will only be invoked when you
actually return the descriptor object itself. For example:

py> class Descr(object):
.... def __init__(self):
.... self.value = None
.... def __repr__(self):
.... return 'Descr(value=%r )' % self.value
....
py> class DescrSelf(Descr ):
.... def __get__(self, obj, type=None):
.... return self
....
py> class DescrObj(Descr) :
.... def __get__(self, obj, type=None):
.... return obj
....
py> class DescrValue(Desc r):
.... def __get__(self, obj, type=None):
.... return obj.value
....
py> class C(object):
.... s = DescrSelf()
.... o = DescrObj()
.... v = DescrValue()
....
py> C.s
Descr(value=Non e)
py> print C.o
None
py> C.v
Traceback (most recent call last):
File "<interacti ve input>", line 1, in ?
File "<interacti ve input>", line 3, in __get__
AttributeError: 'NoneType' object has no attribute 'value'
py> c = C()
py> c.s
Descr(value=Non e)
py> c.o
<__main__.C object at 0x011B65F0>
py> c.v
Traceback (most recent call last):
File "<interacti ve input>", line 1, in ?
File "<interacti ve input>", line 3, in __get__
AttributeError: 'C' object has no attribute 'value'
py> c.value = False
py> c.s
Descr(value=Non e)
py> c.o
<__main__.C object at 0x011B65F0>
py> c.v
False

The point here is that, if you define __repr__ for a descriptor, it will
only be invoked when the descriptor itself is returned. But you're
storing your string as an attribute of the descriptor (like 'value'
above), so you want the __repr__ on this attribute, not on the
descriptor itself. As you'll note from the code above, the only time
__repr__ is called is when the descriptor returns 'self'. But for
almost all purposes, you're going to want to do something like
DescrValue does (where you return an attribute of the object, not of the
descriptor).

If you want a single-character string type as an attribute, why not
subclass str and use a property?

py> class SingleChar(str) :
.... def __new__(cls, s):
.... if len(s) != 1:
.... raise ValueError
.... return super(SingleCha r, cls).__new__(cl s, s)
.... def __repr__(self):
.... return 'SingleChar(%s) ' % super(SingleCha r, self).__repr__( )
....
py> def getchar(self):
.... return self._char
....
py> def setchar(self, value):
.... self._char = SingleChar(valu e)
....
py> singlechar = property(getcha r, setchar)
py> class Flags(object):
.... a = singlechar
.... b = singlechar
....
py> f = Flags()
py> f.a = "a"
py> f.a
SingleChar('a')
py> f.b = "bb"
Traceback (most recent call last):
File "<interacti ve input>", line 1, in ?
File "<interacti ve input>", line 2, in setchar
File "<interacti ve input>", line 4, in __new__
ValueError

Note that now (unlike if you'd used only a descriptor), the __repr__ is
correctly invoked.

STeVe

P.S. If you haven't already, you should read
http://users.rcn.com/python/download/Descriptor.htm a couple of times.
It took me until about the third time I read it to really understand
what descriptors were doing. The big thing to remember is that for an
instance b,
b.x
is equivalent to
type(b).__dict_ _['x'].__get__(b, type(b))
and for a class B,
B.x
is equivalent to
B.__dict__['x'].__get__(None, B)
Note that 'x' is always retrieved from the *type* __dict__, not from the
*instance* __dict__.
Jul 18 '05 #5
Steven Bethard <steven.betha rd <at> gmail.com> writes:

P.S. If you haven't already, you should read
http://users.rcn.com/python/download/Descriptor.htm a couple of times.
It took me until about the third time I read it to really understand
what descriptors were doing. The big thing to remember is that for an
instance b,
b.x
is equivalent to
type(b).__dict_ _['x'].__get__(b, type(b))
and for a class B,
B.x
is equivalent to
B.__dict__['x'].__get__(None, B)
Note that 'x' is always retrieved from the *type* __dict__, not from the
*instance* __dict__.


Steve, and others, thanks for the help. This and Michael Spencer's reply
at http://article.gmane.org/gmane.comp....general/390478 have been very
helpful in getting the descriptor definition clear. For me, it has taken
reading http://users.rcn.com/python/download/Descriptor.htm about 4 times
along with your help to get this straight.

Peace,
David S.

Jul 18 '05 #6
David S. wrote:
Steven Bethard <steven.betha rd <at> gmail.com> writes:

David S. wrote:
I am looking for a way to implement the same simple validation on many
instance attributes and I thought descriptors
(http://users.rcn.com/python/download/Descriptor.htm) looked like the
right tool.

Looks like you're trying to reinvent the property descriptor. Try using
the builtin property instead:

py> def getchar(self):
... if not hasattr(self, '_char'):
... self._char = None
... return self._char
...
py> def setchar(self, value):
... if not len(value) == 1:
... raise ValueError
... self._char = value
...
py> singlechar = property(getcha r, setchar)
py> class Flags(object):
... a = singlechar
... b = singlechar
...
py> f = Flags()
py> f.a = "a"
py> f.b = "bb"
Traceback (most recent call last):
File "<interacti ve input>", line 1, in ?
File "<interacti ve input>", line 3, in setchar
ValueError


This still fails to work for instances variables of the class. That is
if I use your property in the following:
py> ...class Flags(object):
... def __init__(self):
... a = singlechar
...
py> f = Flags()
py> f.a = "a"

Now f.a.__class__._ _name__ returns 'str'. So the property was not
used at all.

You want assignment to a method-local variable to turn an attribute into
a property? That's programming with a magic wand ...
Also, it seems that using a property, I can not do the other useful
things I can do with a proper class, like provide an __init__, __str__,
or __repr__.

That will depend on the value returned by property access, surely?

I suspect you are a little confused about properties and descriptors.

regards
Steve
--
Meet the Python developers and your c.l.py favorites March 23-25
Come to PyCon DC 2005 http://www.pycon.org/
Steve Holden http://www.holdenweb.com/
Jul 18 '05 #7
David S. wrote:
Steve, and others, thanks for the help. This and Michael Spencer's reply
at http://article.gmane.org/gmane.comp....general/390478 have been very
helpful in getting the descriptor definition clear. For me, it has taken
reading http://users.rcn.com/python/download/Descriptor.htm about 4 times
along with your help to get this straight.


If it only takes 2 or 3 re-reads to get descriptors, does that mean Python's
black magic is really only a kind of off-white colour?

Cheers,
Nick.

--
Nick Coghlan | nc******@email. com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #8
Steve Holden <steve <at> holdenweb.com> writes:

You want assignment to a method-local variable to turn an attribute into
a property? That's programming with a magic wand ...

That will depend on the value returned by property access, surely?

I suspect you are a little confused about properties and descriptors.

regards
Steve


Quite confused, actually, which was the reason for my original post.
Thanks again to those who helped me and any other confused folks
understand this bit of Python that much better.
Peace,
David S.
Jul 18 '05 #9

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

Similar topics

2
1612
by: Steve Jorgensen | last post by:
Hi all, In the code I'm working on to learn Java, I wanted to check to see if a string can be converted to a BigDecimal, and get the BigDecimal value if so. There is no assumption that the string is probably a valid BigDecimal, just that it might be, and I want to get the converted value if so. In my code, I used a Try with an empty Catch so that the string conversion would either succeed or fail which would both test and do the...
11
1787
by: Paul Rubin | last post by:
I frequently find myself writing stuff like # compute frob function, x has to be nonnegative x = read_input_data() assert x >= 0, x # mis-use of "assert" statement frob = sqrt(x) + x/2. + 3. This is not really correct because the assert statement is supposed to validate the logical consistency of the program itself, not the input data. So, for example, when you compile with optimization on, assert
242
13458
by: James Cameron | last post by:
Hi I'm developing a program and the client is worried about future reuse of the code. Say 5, 10, 15 years down the road. This will be a major factor in selecting the development language. Any comments on past experience, research articles, comments on the matter would be much appreciated. I suspect something like C would be the best based on comments I received from the VB news group. Thanks for the help in advance James Cameron
4
10147
by: usl2222 | last post by:
Hi folks, I appreciate any assistance in the following problem: I have a form with a bunch of dynamic controls on it. All the controls are dynamically generated on a server, including all the validators. The user enters the data, presses OK. My OK button is dynamically generated as well, with some code-behind logic in
5
3247
by: Chris | last post by:
Based upon some prevoius postings on what to do for adding a 'add' row to a datagrid I utilize the footer to create the 'add' row. The only issue is that I have it sharing the 'UpDate_Command' and I use an argument to difference between an 'edit' vs. and 'add. But since I have field validation on both 'footer' and 'edit' columns I can't submit my edits since the footer validation kicks in.If I take the validation off then the both work fine...
5
1921
by: Sun Jian | last post by:
Hi, I am trying to customize the asp.net validation to achieve the following: Upon submitting the form, client side validation will run, and it will stop at the first error detected. For example if both UserID and Password text fields are required but neither is filled in, I'd like to display the error message (a dialogbox) "Please enter the User ID". And only after the user has filled in UserID, it will display "Please enter the...
3
6338
by: Bob Alston | last post by:
I have a routine to copy data to new versions of my app via insert into sql statements. Unfortunately, due to evolution of my app, sometimes the new version has more restrictive editing than an older version that I am updating. Thus I get this message. It tells me only how many records have errors, not which errors or which records. Anyone have a nice solution to identifying the specific records involved? Maybe even the specific...
4
2154
by: jehugaleahsa | last post by:
Hello: Is it me, or is handling the Validating event for every control on a form extremely annoying? It is especially annoying when my business logic repeats most of the validation. Some things you can handle in the business logic. But other things, like ensuring a textbox represents a number or null, requires a developer's intervention. I am asking whether or not there is an easier way of doing validation for data bound controls.
6
4521
by: gavy7210 | last post by:
hello i am using struts 1.2,Eclipse Platform Version: 3.4.2,mySql 5.0.1,jdk 1.5.. i have a login form(jsp) in which a user logs in,in case he doesnt enter his username and/or password an error is displayed using the <ul> tag and <html:errors> in the jsp. in the from class a vaidate method creates an actionerrors object adds all the errors to it and finally returns it. the ids are linked in messageresources.properties and appropriate...
0
9617
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
10257
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
10099
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...
1
10037
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9904
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8931
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7456
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 presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6710
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
5482
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?

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.