setattr() oddness

T

Terry Reedy

Should the following be legal?

'123'

Different people have different opinions as to whether setattr (and
correspondingly getattr) should be strict or permissive as to whether or
not the 'name' string is a legal name. CPython is permissive. The
rationale is that checking would take time and prevent possible
legitimate use cases.

CPython is actually looser than this. Try

t.__dict__[1] = 2

Now there is an 'attribute' whose 'name' is an int! -- and which can
only be accessed via the same trick of delving into the internals. This
is, however, implementation behavior that would go away if an
implementation used string-key-only dicts to store attributes.

Terry Jan Reedy
 
S

Steve Holden

Terry said:
Should the following be legal?

'123'

Different people have different opinions as to whether setattr (and
correspondingly getattr) should be strict or permissive as to whether or
not the 'name' string is a legal name. CPython is permissive. The
rationale is that checking would take time and prevent possible
legitimate use cases.

CPython is actually looser than this. Try

t.__dict__[1] = 2

Now there is an 'attribute' whose 'name' is an int! -- and which can
only be accessed via the same trick of delving into the internals. This
is, however, implementation behavior that would go away if an
implementation used string-key-only dicts to store attributes.
Good question, great answer!

regards
Steve
 
S

Sean DiZazzo

Should the following be legal?
'123'

Different people have different opinions as to whether setattr (and
correspondingly getattr) should be strict or permissive as to whether or
not the 'name' string is a legal name. CPython is permissive. The
rationale is that checking would take time and prevent possible
legitimate use cases.

CPython is actually looser than this. Try

t.__dict__[1] = 2

Now there is an 'attribute' whose 'name' is an int! -- and which can
only be accessed via the same trick of delving into the internals. This
is, however, implementation behavior that would go away if an
implementation used string-key-only dicts to store attributes.

Terry Jan Reedy

Interesting. I can understand the "would take time" argument, but I
don't see any legitimate use case for an attribute only accessible via
getattr(). Well, at least not a pythonic use case.

Thanks for the info!

~Sean
 
T

Terry Reedy

Should the following be legal?
class TEST(object): pass
...
t = TEST()
setattr(t, "", "123")
getattr(t, "")
'123'

Different people have different opinions as to whether setattr (and
correspondingly getattr) should be strict or permissive as to whether or
not the 'name' string is a legal name. CPython is permissive. The
rationale is that checking would take time and prevent possible
legitimate use cases.

CPython is actually looser than this. Try

t.__dict__[1] = 2

Now there is an 'attribute' whose 'name' is an int! -- and which can
only be accessed via the same trick of delving into the internals. This
is, however, implementation behavior that would go away if an
implementation used string-key-only dicts to store attributes.

Terry Jan Reedy

Interesting. I can understand the "would take time" argument, but I
don't see any legitimate use case for an attribute only accessible via
getattr(). Well, at least not a pythonic use case.

That was my first thought, but one thing I thought of would be a proxy
object for remote objects coded in a language with different name rules,
or any situation where 'names' and values come over the wire to be
stored and later retrieved, so that all 'foreign' attribute access was
done with set/get/del/attr.

I expect that creative Python programmers have found other uses too.

Terry Jan Reedy
 
L

Lie Ryan

Interesting. I can understand the "would take time" argument, but I
don't see any legitimate use case for an attribute only accessible via
getattr(). Well, at least not a pythonic use case.

mostly for people (ab)using attributes instead of dictionary.
 
D

Dieter Maurer

Lie Ryan said:
mostly for people (ab)using attributes instead of dictionary.

Here is one use case:

A query application. Queries are described by complex query objects.
For efficiency reasons, query results should be cached.
For this, it is not unnatural to use query objects as cache keys.
Then, query objects must not get changed in an uncontrolled way.
I use "__setattr__" to control access to the objects.

Dieter
 
S

Steven D'Aprano

Here is one use case:

A query application. Queries are described by complex query objects.
For efficiency reasons, query results should be cached. For this, it is
not unnatural to use query objects as cache keys. Then, query objects
must not get changed in an uncontrolled way. I use "__setattr__" to
control access to the objects.


(1) Wouldn't it be more natural to store these query keys in a list or
dictionary rather than as attributes on an object?

e.g. instead of:

cache.__setattr__('complex query object', value)

use:

cache['complex query object'] = value



(2) How does __setattr__ let you control access to the object? If a user
wants to modify the cache, and they know the complex query object, what's
stopping them from using __setattr__ too?
 
D

Dieter Maurer

Steven D'Aprano said:
Here is one use case:

A query application. Queries are described by complex query objects.
For efficiency reasons, query results should be cached. For this, it is
not unnatural to use query objects as cache keys. Then, query objects
must not get changed in an uncontrolled way. I use "__setattr__" to
control access to the objects.


(1) Wouldn't it be more natural to store these query keys in a list or
dictionary rather than as attributes on an object?

e.g. instead of:

cache.__setattr__('complex query object', value)

use:

cache['complex query object'] = value

Few will use "cache.__setattr__(...)" but "cache.attr = ..." which
is nicer than "cache['attr'] = ...".

Moreover, it is not the cache but the query of which I want to protect
modification. My cache indeed uses "cache[query_object] = ...".
But I want to prevent "query_object" from being changed after a potential
caching.


(2) How does __setattr__ let you control access to the object? If a user
wants to modify the cache, and they know the complex query object, what's
stopping them from using __setattr__ too?

In my specific case, "__setattr__" prevents all modifications via attribute
assignment. The class uses "__dict__" access to set attributes when
it knows it is still safe.

Of course, this is no real protection against attackers (which could
use "__dict__" as well). It only protects against accidental change
of query objects.


Meanwhile, I remembered a more important use case for "__setattr__":
providing for transparent persistancy. The "ZODB" (Zope Object DataBase)
customizes "__setattr__" in order to intercept object modifications
and register automatically that the change needs to be persisted at
the next transaction commit.


Dieter
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,177
Messages
2,570,953
Members
47,507
Latest member
codeguru31

Latest Threads

Top