Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #15057 > unrolled thread

Dynamically creating properties?

Started byAndy Dingley <dingbat@codesmiths.com>
First post2011-10-27 12:59 -0700
Last post2011-10-28 14:42 +1100
Articles 9 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  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

#15057 — Dynamically creating properties?

FromAndy Dingley <dingbat@codesmiths.com>
Date2011-10-27 12:59 -0700
SubjectDynamically 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]


#15058

FromJohn Gordon <gordon@panix.com>
Date2011-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]


#15061

FromDevPlayer <devplayer@gmail.com>
Date2011-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]


#15067

FromDevPlayer <devplayer@gmail.com>
Date2011-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]


#15068

FromDevPlayer <devplayer@gmail.com>
Date2011-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]


#15072

FromDevPlayer <devplayer@gmail.com>
Date2011-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]


#15093

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-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]


#15147

FromDevPlayer <devplayer@gmail.com>
Date2011-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]


#15085

FromLie Ryan <lie.1296@gmail.com>
Date2011-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