During my Python (3.1) programming I often find myself having to repeat
code such as...
class1.attr1 = 1
class1.attr2 = 2
class1.attr3 = 3
class1.attr4 = 4
etc.
Is there any way to achieve the same result without having to repeat the
class1 prefix? Before Python my previous main language was Visual
Foxpro, which had the syntax...
with class1
.attr1 = 1
.attr2 = 2
.attr3 = 3
.attr4 = 4
etc.
endwith
Is there any equivalent to this in Python?
Any help would be appreciated.
Alan Harris-Reid
There's more than one way to do this, depending on your actual needs and
the source of the attributes. I assume this is done in __init__?
This might work for you:
self.__dict__.update(attr1=1, attr2=2, attr3=3, attr4=4)
You should also think once more about the use of the code you presented
above, having to set all those attributes may have a little smell. Maybe
that's totally ok, but since you mention that you "often" find yourself
doing the above, you may also have a mental design problem somewhere. We
can't tell unless you provide a more concrete example than what you show above.
Stefan
The pythonic equivalent of VB 'with' is to assign to a short variable
name, for example '_':
_ = class1
_.attr1 = 1
_.attr2 = 2
_.attr3 = 3
_.attr4 = 4
alternatively, you could use the __setattr__ method:
for attr, value in (
('attr1', 1),
('attr2', 2),
('attr3', 3),
('attr4', 4)):
class1.__setattr__(attr, value)
and to get a bit crunchy, with this your specific example can be
written:
for i in xrange(1, 5):
class1.__setattr__('attr%d' % i, i)
Iain
No. You could write a helper function
>>> def update(obj, **kw):
... for k, v in kw.items():
... setattr(obj, k, v)
...
and then use keyword arguments:
>>> class A: pass
...
>>> a = A()
>>> update(a, foo=42, bar="yadda")
>>> a.foo, a.bar
(42, 'yadda')
>>>
But if you are doing that a lot and if the attributes are as uniform as
their names suggest you should rather use a Python dict than a custom class.
>>> d = {}
>>> d.update(foo=42, bar="whatever")
>>> d
{'foo': 42, 'bar': 'whatever'}
>>> d["bar"]
'whatever'
Peter
Use an effective text editor, repeating stuff should not be a problem.
In a more general manner, avoid trying to speed your writing while you
should care speeding the reading.
Most of the tricks you could use will confuse the reader (unless the
reader is familiar with Visual foxpro).
Anyway,
for attrName, value in [
('attr1', 1),
('attr2', 2),
('attr3', 3),
]:
setattr(class1, attrName, value)
or
class Foo:
def __init__(self):
self.attr1=None
self.attr2=None
self.attr3=None
def set(self, *args, **kwargs):
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
else:
raise AttributeError('%s instance has no attribute "%s"' %
(self.__class__.__name__, k))
f = Foo()
f.set(attr1=25)
print f.__dict__
f.set(attr3=4, attr2=89)
print f.__dict__
f.set(bar= 8)
output:
{'attr2': None, 'attr3': None, 'attr1': 25}
{'attr2': 89, 'attr3': 4, 'attr1': 25}
AttributeError: Foo instance has no attribute "bar"
JM
Interesting solutions, but I think for the effort involved (and
readability) I'll stick to repeating the class.
Regards,
Alan
The code is not usually in class.__init__ (otherwise I would have used
the self. prefix), but I like your self.__dict__.update(...) solution
and I'll try and remember it.
The code I was thinking of goes something like as follows (don't have a
specific example to hand, but the principal is the same)...
NewClass = BaseClass()
NewClass.attr1 = value1
NewClass.attr2 = value2
NewClass.attr3 = value3
etc.
So if there are more than a couple of attributes to set for a class
instance, how would you approach it (short of passing the values as
parameters to BaseClass)?
Regards,
Alan
Why are you against passing them as parameters?
If your constructor would have a lot of parameters, it may be a sign that:
(A) you have some Data Clumps
(http://martinfowler.com/bliki/DataClump.html) among the parameters
that ought to be made into full objects
(B) your class is doing too many things and needs to be split into
multiple classes
(http://www.refactoring.com/catalog/extractClass.html)
Cheers,
Chris
--
Yay Refactoring!
http://blog.rebertia.com
Unless I'm missing something (your use-case, perhaps? ;) in this example
NewClass is *not* a class -- it's an instance of BaseClass, and you are
dynamically adding attributes to it.
It's definitely a switch coming from FoxPro (me, too!), but it is well
worth it once your brain starts working pythonically.
~Ethan~
Good to see ex-Fox people on this list. I have recently got stuck-into
learning Python after my last VFP contract finished last December - wish
I had started years ago. Really glad I went for Python, which I thought
would be the easiest transition from Foxpro (I looked at other
languages, but none came near to Python in terms of popularity and
developer-friendly syntax). What's your story?
Regards,
Alan
JM
>>> class A(): pass
>>> inst=A()
>>> exec("""
... a=1
... b=2
... c=3
... d=4
... """) in inst.__dict__
>>> inst.a
1
>>>
This executes the Statement in the exec function and uses inst.__dict__
as namespace. But be aware, that this is not recommended. If you mess
with __dict__, you won't be able to replace it with some logic
(parameter) if you need to do something more than setting a variable.
Best
Please don't take this as in invitation to disregard the excellent
advice already received in this thread - I just want to point out that
python can usually be bent to your will. Observe:
from withhacks import namespace
with namespace(class1):
attr1 = 1
attr2 = 2
This will do pretty much what you get from the "with" statement in
javascript (I assume it's similar to Visual Foxpro).
But don't use this in any real code. Seriously, don't even think about
it. You don't want to know the kind of abuses that go on under the
covers to make this kind of syntax hacking work...
Cheers,
Ryan
--
Ryan Kelly
http://www.rfk.id.au | This message is digitally signed. Please visit
ry...@rfk.id.au | http://www.rfk.id.au/ramblings/gpg/ for details
Your withhacks module looks very interesting.
http://pypi.python.org/pypi/withhacks
What are your specific concerns about its use? Are there portability
concerns?
Malcolm
It combines two things you just don't see in respectable python programs
- bytecode hacking and trace-function hacking. And I'm sure its
performance is less than stellar, although much of that could be fixed
with some careful bytecode caching.
I'd be surprised if it runs under alternative python implementations,
and not surprised if it doesn't even work on Python 3 - although I
haven't tried it to confirm either way.
Having said that, it should work as advertised on Python 2.X with
minimal fuss. So if you don't care about portability or about that dirty
feeling you get from messing with the Python internals, then have at
it :-)
> So if you don't care about portability or about that dirty feeling you get from messing with the Python internals, then have at it :-)
Warnings aside, its very clever code. Thanks for sharing!
Malcolm