Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #15057 > unrolled thread
| Started by | Andy Dingley <dingbat@codesmiths.com> |
|---|---|
| First post | 2011-10-27 12:59 -0700 |
| Last post | 2011-10-28 14:42 +1100 |
| Articles | 9 — 5 participants |
Back to article view | Back to comp.lang.python
Dynamically creating properties? Andy Dingley <dingbat@codesmiths.com> - 2011-10-27 12:59 -0700
Re: Dynamically creating properties? John Gordon <gordon@panix.com> - 2011-10-27 20:14 +0000
Re: Dynamically creating properties? DevPlayer <devplayer@gmail.com> - 2011-10-27 14:48 -0700
Re: Dynamically creating properties? DevPlayer <devplayer@gmail.com> - 2011-10-27 16:00 -0700
Re: Dynamically creating properties? DevPlayer <devplayer@gmail.com> - 2011-10-27 16:15 -0700
Re: Dynamically creating properties? DevPlayer <devplayer@gmail.com> - 2011-10-27 17:35 -0700
Re: Dynamically creating properties? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-10-28 07:42 +0000
Re: Dynamically creating properties? DevPlayer <devplayer@gmail.com> - 2011-10-30 07:11 -0700
Re: Dynamically creating properties? Lie Ryan <lie.1296@gmail.com> - 2011-10-28 14:42 +1100
| From | Andy Dingley <dingbat@codesmiths.com> |
|---|---|
| Date | 2011-10-27 12:59 -0700 |
| Subject | Dynamically creating properties? |
| Message-ID | <a47fb589-520a-49ec-9864-cac1d7ea11eb@s9g2000yqi.googlegroups.com> |
I have some XML, with a variable and somewhat unknown structure. I'd like to encapsulate this in a Python class and expose the text of the elements within as properties. How can I dynamically generate properties (or methods) and add them to my class? I can easily produce a dictionary of the required element names and their text values, but how do I create new properties at run time? Thanks,
[toc] | [next] | [standalone]
| From | John Gordon <gordon@panix.com> |
|---|---|
| Date | 2011-10-27 20:14 +0000 |
| Message-ID | <j8ce3m$g7g$1@reader1.panix.com> |
| In reply to | #15057 |
In <a47fb589-520a-49ec-9864-cac1d7ea11eb@s9g2000yqi.googlegroups.com> Andy Dingley <dingbat@codesmiths.com> writes:
> How can I dynamically generate properties (or methods) and add them to
> my class? I can easily produce a dictionary of the required element
> names and their text values, but how do I create new properties at run
> time?
You can set dynamic attributes on class objects without any special
processing at all. Just do it, like so:
class X(object):
pass
myx = X()
myx.color = 'red'
myx.food = 'french fries'
myx.lucky_number = 7
Or, if you don't know the attribute name beforehand:
setattr(myx, 'occupation', 'programmer')
For methods, use an existing method name (without the trailing parentheses)
as the attribute value, like so:
myx.method = float # assigns the built-in method float()
--
John Gordon A is for Amy, who fell down the stairs
gordon@panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"
[toc] | [prev] | [next] | [standalone]
| From | DevPlayer <devplayer@gmail.com> |
|---|---|
| Date | 2011-10-27 14:48 -0700 |
| Message-ID | <b955b690-8045-4de1-b0dd-dcf0a05cc92f@v5g2000vbh.googlegroups.com> |
| In reply to | #15057 |
On Oct 27, 3:59 pm, Andy Dingley <ding...@codesmiths.com> wrote:
> I have some XML, with a variable and somewhat unknown structure. I'd
> like to encapsulate this in a Python class and expose the text of the
> elements within as properties.
>
> How can I dynamically generate properties (or methods) and add them to
> my class? I can easily produce a dictionary of the required element
> names and their text values, but how do I create new properties at run
> time?
>
> Thanks,
class MyX(object):
pass
myx = myx()
xml_tag = parse( file.readline() )
# should be a valid python named-reference syntax,
# although any object that can be a valid dict key is allowed.
# generally valid python named reference would be the answer to
your question
attribute = validate( xml_tag )
# dynamicly named property
setattr( myx, attribute, property(get_func, set_func, del_func,
attr_doc) )
# "dynamicly named method"
# really should be a valid python named-reference syntax
myfunc_name = validate(myfunc_name)
def somefunc(x):
return x+x
# or
somefunc = lambda x: x + x
setattr( myx, myfunc_name, somefunc )
So beaware of:
# \\\\\\\\\\\\\\\\\\\\\\\\\
setattr(myx, '1', 'one')
myx.1
File "<input>", line 1
x.1
^
SyntaxError: invalid syntax
# \\\\\\\\\\\\\\\\\\\\\\\\\
x.'1'
File "<input>", line 1
x.'1'
^
SyntaxError: invalid syntax
# \\\\\\\\\\\\\\\\\\\\\\\\\
x.__dict__['1'] # returns
'one'
x.__dict__ # returns
{'1': 'one'}
So you should validate your variable names if you are getting them
from somewhere.
[toc] | [prev] | [next] | [standalone]
| From | DevPlayer <devplayer@gmail.com> |
|---|---|
| Date | 2011-10-27 16:00 -0700 |
| Message-ID | <f66cde69-ee97-4da3-824d-18051cb860ff@hv4g2000vbb.googlegroups.com> |
| In reply to | #15061 |
Personally I like to use this function instead of a "try: except:"
because try-except will allow names like __metaclass__.
Remember, setattr(obj, attr_name, value) allows attr_name to be any
valid str().
For example: '!@kdafk11', or '1_1', '1e-20', '0.0', '*one', '\n%%',
etc.
def isvalid_named_reference( astring ):
# "varible name" is really a named_reference
# import string # would be cleaner
valid_first_char =
'_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
valid_rest =
'_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
# I think it's ok here for the rare type-check
# as unicode named-references are not allowed
if type(astring) is not str: return False
if len(astring) == 0: return False
if astring[0] not in valid_first_char: return False
for c in astring[1:]:
if c not in valid_rest: return False
# Python keywords not allowed as named references (variable names)
for astr in ['and', 'assert', 'break', 'class', 'continue',
'def', 'del', 'elif', 'else', 'except', 'exec',
'finally', 'for', 'from', 'global', 'if',
'import', 'in', 'is', 'lambda', 'not', 'or',
'pass', 'print', 'raise', 'return', 'try',
'while', 'yield',]:
if astring == astr: return False
# valid names but bad idea
if astring == '__builtins__': return None
if astring == '__metaclass__': return None
for astr in dir(__builtins__):
if astring == astr: return None # use None as a warning
# there might be more like __slots__, and other
# module level effecting special names like '__metaclass__'
return True
Also when using dynamically created "varible names" to check if your
objects have an attribute with that name already.
[toc] | [prev] | [next] | [standalone]
| From | DevPlayer <devplayer@gmail.com> |
|---|---|
| Date | 2011-10-27 16:15 -0700 |
| Message-ID | <43b77f11-fc3e-4e73-8e94-9ad43e2f6d49@a17g2000yqj.googlegroups.com> |
| In reply to | #15067 |
At least one error:
change:
> for astr in dir(__builtins__):
to:
for astr in __builtins__.__dict__:
[toc] | [prev] | [next] | [standalone]
| From | DevPlayer <devplayer@gmail.com> |
|---|---|
| Date | 2011-10-27 17:35 -0700 |
| Message-ID | <ed512573-386a-450e-a6db-93e6bbf2c332@r28g2000yqj.googlegroups.com> |
| In reply to | #15068 |
Second error
def isvalid_named_reference( astring ):
# "varible name" is really a named_reference
import __builtin__ # add line
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-10-28 07:42 +0000 |
| Message-ID | <4eaa5cfa$0$29968$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #15067 |
On Thu, 27 Oct 2011 16:00:57 -0700, DevPlayer wrote:
> def isvalid_named_reference( astring ):
> # "varible name" is really a named_reference
> # import string # would be cleaner
I don't understand the comment about "variable name".
> valid_first_char =
> '_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
> valid_rest =
> '_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
This would be better:
import string
valid_first_char = '_' + string.ascii_letters
valid_rest = string.digits + valid_first_char
> # I think it's ok here for the rare type-check
> # as unicode named-references are not allowed
> if type(astring) is not str: return False
In Python 3 they are:
http://www.python.org/dev/peps/pep-3131/
> if len(astring) == 0: return False
> if astring[0] not in valid_first_char: return False
> for c in astring[1:]:
> if c not in valid_rest: return False
>
> # Python keywords not allowed as named references (variable names)
> for astr in ['and', 'assert', 'break', 'class', 'continue',
> 'def', 'del', 'elif', 'else', 'except', 'exec',
> 'finally', 'for', 'from', 'global', 'if', 'import',
> 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print',
> 'raise', 'return', 'try', 'while', 'yield',]:
> if astring == astr: return False
You missed 'as' and 'with'. And 'nonlocal' in Python 3. Possibly others.
Try this instead:
from keywords import iskeyword
if iskeyword(astring): return False
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | DevPlayer <devplayer@gmail.com> |
|---|---|
| Date | 2011-10-30 07:11 -0700 |
| Message-ID | <4382a97c-0517-4fca-be14-181d480038a6@4g2000yqu.googlegroups.com> |
| In reply to | #15093 |
To be honest, I was hoping someone would have posted a link to a well
known and tested recipe. You'd think this function would be in the
standard library or a specific Exception tied directly with setattr()
and getattr() (and possibly __getattr__(), __getattribute__(),
__setattr__())
The main thing I wanted to point out though is when you start using
dynamically named references, there's more to it then just letting a
dynamic file define it.
If there's a way to reference a set of data, it really shouldn't be
with a "dynamically named reference" too often.
Databases are a good example. Perhaps this is a better way for
example: If you have a bunch of tables in your DB -is- it better to
get the table def and create a Python class with dynamically named
"fields"?
Or is it better to create a Table class with name attribute and a
Field class with a name attribute (named "name")
SO instead of :
field_name = xml_parse.get_next_field_name(xml_table_definition)
my_table = Table()
setattr(my_table, field_name,
empty_list_to_later_contain_field_data)
Perhaps:
field_name = xml_parse.get_next_field_name(xml_table_definition)
my_table = Table()
my_table.fields[field_name] =
empty_list_to_later_contain_field_data
# or
my_table.add_field( Field(field_name) )
[toc] | [prev] | [next] | [standalone]
| From | Lie Ryan <lie.1296@gmail.com> |
|---|---|
| Date | 2011-10-28 14:42 +1100 |
| Message-ID | <mailman.2274.1319773376.27778.python-list@python.org> |
| In reply to | #15061 |
On 10/28/2011 08:48 AM, DevPlayer wrote:
> On Oct 27, 3:59 pm, Andy Dingley<ding...@codesmiths.com> wrote:
>> I have some XML, with a variable and somewhat unknown structure. I'd
>> like to encapsulate this in a Python class and expose the text of the
>> elements within as properties.
>>
>> How can I dynamically generate properties (or methods) and add them to
>> my class? I can easily produce a dictionary of the required element
>> names and their text values, but how do I create new properties at run
>> time?
>>
>> Thanks,
>
> class MyX(object):
> pass
> myx = myx()
>
> xml_tag = parse( file.readline() )
>
> # should be a valid python named-reference syntax,
> # although any object that can be a valid dict key is allowed.
> # generally valid python named reference would be the answer to
> your question
> attribute = validate( xml_tag )
>
> # dynamicly named property
> setattr( myx, attribute, property(get_func, set_func, del_func,
> attr_doc) )
>
> # "dynamicly named method"
> # really should be a valid python named-reference syntax
> myfunc_name = validate(myfunc_name)
>
> def somefunc(x):
> return x+x
> # or
> somefunc = lambda x: x + x
>
> setattr( myx, myfunc_name, somefunc )
>
>
> So beaware of:
> # \\\\\\\\\\\\\\\\\\\\\\\\\
> setattr(myx, '1', 'one')
>
> myx.1
> File "<input>", line 1
> x.1
> ^
> SyntaxError: invalid syntax
>
> # \\\\\\\\\\\\\\\\\\\\\\\\\
> x.'1'
> File "<input>", line 1
> x.'1'
> ^
> SyntaxError: invalid syntax
>
> # \\\\\\\\\\\\\\\\\\\\\\\\\
> x.__dict__['1'] # returns
> 'one'
>
> x.__dict__ # returns
> {'1': 'one'}
>
> So you should validate your variable names if you are getting them
> from somewhere.
XML does not allow attribute names to start with a number, so I doubt
you need to worry about that. In addition, if you also need to
dynamically access attributes and you have zero control of the name, you
can use getattr().
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web