getting the state of an object

F

Franck Ditter

Hi !

Another question. When writing a class, I have often to
destructure the state of an object as in :

def foo(self) :
(a,b,c,d) = (self.a,self.b,self.c,self.d)
... big code with a,b,c,d ...

So I use the following method :

def state(self) :
return (self.a,self.b,self.c,self.d)

so as to write :

def foo(self) :
(a,b,c,d) = self.state()
... big code with a,b,c,d ...

This is probably not the best Python way to code, is it ?
Is there a simple way to get the *ordered* list of instance
variables as given in the parameter list of __init__ ?
__dict__ gives it but not in order...
Thanks a lot,

franck
 
C

Chris Angelico

def foo(self) :
(a,b,c,d) = (self.a,self.b,self.c,self.d)
... big code with a,b,c,d ...

This strikes me as ripe for bug introduction. There's no problem if
you're just reading those values, and mutating them is equally fine,
but suddenly you need a different syntax for modifying instance
members.

def foo(self) :
(a,b,c,d) = (self.a,self.b,self.c,self.d)
e = a+b
c.append(1234)
d=self.d = 57 # Oops, mustn't forget to assign both!


Since Python lacks the extensive scoping rules of (say) C++, it's much
simpler and safer to be explicit about scope by adorning your instance
variable references with their "self." tags. There's a guarantee that
you can use "self.a" in any situation where you want to manipulate
that member, a guarantee that's not upheld by the local "a".

In theory, I suppose you could use a C-style preprocessor to help you.

class Foo(object):
#define asdf self.asdf
#define qwer self.qwer

def __init__(self,a,q):
asdf=a; qwer=q

def __repr__(self):
return "Foo(%s,%s)"%(asdf,qwer)

This is not, however, Pythonic code. But if you made some kind of
better declaration than #define, and used a preprocessor that
understood Python indentation rules and flushed its token list at the
end of the class definition, you could perhaps make this look
not-ugly. I still wouldn't recommend it, though.

ChrisA
 
S

Steven D'Aprano

Hi !

Another question. When writing a class, I have often to destructure the
state of an object as in :

def foo(self) :
(a,b,c,d) = (self.a,self.b,self.c,self.d)
... big code with a,b,c,d ...

There's your problem right there: "big code". Methods should be small,
ideally no more than a dozen lines or so. In my experience, small methods
that have a very tight focus on doing one thing make it much easier to
write, debug and maintain the method, and as a bonus having to write
"self.a" is less of a burden.

I've just looked at one of my classes, picked randomly, and the largest
method is twelve lines, the second largest is eight, and the average is
three lines.

So I use the following method :

def state(self) :
return (self.a,self.b,self.c,self.d)

so as to write :

def foo(self) :
(a,b,c,d) = self.state()
... big code with a,b,c,d ...

This is probably not the best Python way to code, is it ?

Not really the best. But I've seen worse.

If you *have* to write "big code with a,b,c,d" then this is probably
acceptable. But better to refactor your big method into smaller methods
that don't need to use self.a, self.b, self.c, self.d so many times that
writing them explicitly is a nuisance.
Is there a
simple way to get the *ordered* list of instance variables as given in
the parameter list of __init__ ?

What you have written in method "state" is the simple way.

By the way, we prefer "instance attribute" or even "instance member" over
"instance variable" here.
 
M

Miki Tebeka

Is there a simple way to get the *ordered* list of instance
Here's one way to do it (weather doing it is a good idea or not is debatable):

from operator import attrgetter

def __init__(self, a, b, c, d):
self.a, self.b, self.c, self.d = a, b, c, d
get = attrgetter('a', 'b', 'c', 'd')
self.state = lambda: get(self)
 
R

Roy Smith

Steven D'Aprano said:
I've just looked at one of my classes, picked randomly, and the largest
method is twelve lines, the second largest is eight, and the average is
three lines.

I took a look at a subtree of the project I'm working on now. 116
python files, 20 kloc, 330 functions (mostly class methods). I did a
quick-and-dirty "grep -n" job on them to find the line numbers of the
def statements, then another quick-and-dirty python script to find the
differences, and summarize. Results below (second column is length of
'def' block in lines, first column is number of blocks of that length).

This is just dumb line counting; no attempt to exclude block comments,
white space, docstrings, etc.

There's three different authors represented here, but I'd guess 70% of
the code is mine. Of the three, I'm probably the one who writes the
most refactored code (i.e. smallest functions).

I just went and found the longest of these (193 lines). It starts with
a 95 line block comment. Of the 100-or so lines of real code, I suppose
with some effort it could have been refactored some, but not hugely.


7 3
19 4
12 5
17 6
10 7
16 8
10 9
6 10
8 11
11 12
4 13
8 14
9 15
13 16
4 17
8 18
9 19
5 20
9 21
3 22
6 23
5 24
4 25
4 26
4 27
3 28
2 29
1 30
3 31
4 32
4 33
8 34
2 35
2 36
3 37
2 39
1 40
3 41
1 42
3 43
2 44
2 45
1 46
2 47
1 48
1 51
2 54
1 55
2 56
2 59
1 60
1 62
1 63
1 64
1 65
1 74
1 75
1 78
1 94
1 100
1 105
1 148
1 164
1 193
 

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
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top