Dynamically creating properties?

Discussion in 'Python' started by Andy Dingley, Oct 27, 2011.

  1. Andy Dingley

    Andy Dingley Guest

    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,
    Andy Dingley, Oct 27, 2011
    #1
    1. Advertising

  2. Andy Dingley

    John Gordon Guest

    In <> Andy Dingley <> 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
    B is for Basil, assaulted by bears
    -- Edward Gorey, "The Gashlycrumb Tinies"
    John Gordon, Oct 27, 2011
    #2
    1. Advertising

  3. Andy Dingley

    DevPlayer Guest

    On Oct 27, 3:59 pm, Andy Dingley <> 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.
    DevPlayer, Oct 27, 2011
    #3
  4. Andy Dingley

    DevPlayer Guest

    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.
    DevPlayer, Oct 28, 2011
    #4
  5. Andy Dingley

    DevPlayer Guest

    At least one error:
    change:
    > for astr in dir(__builtins__):

    to:
    for astr in __builtins__.__dict__:
    DevPlayer, Oct 28, 2011
    #5
  6. Andy Dingley

    DevPlayer Guest

    Second error

    def isvalid_named_reference( astring ):
    # "varible name" is really a named_reference
    import __builtin__ # add line
    DevPlayer, Oct 28, 2011
    #6
  7. Andy Dingley

    Lie Ryan Guest

    On 10/28/2011 08:48 AM, DevPlayer wrote:
    > On Oct 27, 3:59 pm, Andy Dingley<> 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().
    Lie Ryan, Oct 28, 2011
    #7
  8. 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
    Steven D'Aprano, Oct 28, 2011
    #8
  9. Andy Dingley

    DevPlayer Guest

    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) )
    DevPlayer, Oct 30, 2011
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Nathan Sokalski
    Replies:
    0
    Views:
    891
    Nathan Sokalski
    Oct 17, 2005
  2. =?Utf-8?B?Q2hyaXN0b3BoZSBQZWlsbGV0?=

    CompositeControls: ViewState properties w/ Mapped properties probl

    =?Utf-8?B?Q2hyaXN0b3BoZSBQZWlsbGV0?=, Jan 19, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    1,128
    Steven Cheng[MSFT]
    Jan 19, 2006
  3. Kent Lichty
    Replies:
    0
    Views:
    822
    Kent Lichty
    Apr 16, 2004
  4. Victor Porton
    Replies:
    1
    Views:
    687
    Steven T. Hatton
    Aug 29, 2004
  5. Karlo Lozovina

    Dynamically creating class properties

    Karlo Lozovina, Oct 4, 2007, in forum: Python
    Replies:
    3
    Views:
    256
    Michael Spencer
    Oct 5, 2007
Loading...

Share This Page