473,396 Members | 1,760 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Local variables initialization

Hi!

I'm building a class that most of methods have similar intro, something
like this:

def method(self):
var_one = self.attr_one
var_two = self.attr_two.another_attr

empty_list = []

# significant code goes here
# ...

It's done for clarity reasons, aliasing most used variables to shorted
names and initializing some other common variables. I'm wondering if I
can generalize it in any way. So far I couldn't come up with any
solution. It smells like macros (which won't be implemented in Python, I
know, I know ;), but maybe there is a way? I would like to code it that way:

@init_local_variables
def method(self):
# significant code goes here
# ...

If only such a decorator exists...

Thanks for any hints.

mk
--
. o . >> http://joker.linuxstuff.pl <<
. . o It's easier to get forgiveness for being wrong
o o o than forgiveness for being right.
Feb 27 '06 #1
5 2414
Michal Kwiatkowski <ru**@no.spam> wrote:
...
def method(self):
var_one = self.attr_one
var_two = self.attr_two.another_attr
empty_list = []
# significant code goes here ... know, I know ;), but maybe there is a way? I would like to code it that way:

@init_local_variables
def method(self):
# significant code goes here


Such a decorator would have to do very substantial bytecode rewriting,
to turn all references to the magic names within the body of the method
into local-variable references (and a lot of other things besides).
Check the difference...:
import dis
def f1(): .... x = 23
.... return x
.... dis.dis(f1) 2 0 LOAD_CONST 1 (23)
3 STORE_FAST 0 (x)
3 6 LOAD_FAST 0 (x)
9 RETURN_VALUE def f2(): .... return x
.... dis.dis(f2)

2 0 LOAD_GLOBAL 0 (x)
3 RETURN_VALUE

Every access to 'x' within f1 is a LOAD_FAST, because the compiler knows
that x is local; but within f2 it's a different opcode, LOAD_GLOBAL,
because the compiler knows that x ISN'T local (it's not assigned to
within the body) and therefore it guesses it must be local.

The whole function object, as well as the code object it contains, must
be rewritten extensively to add the 'magic' names among the local
variables -- not being assigned-to, they're used in all ways as globals
in the code obejct and function object that the decorator receives.

I would suggest that the issue is hairy enough to apply one of the least
understood points of the "Zen of Python", namely:
"If the implementation is hard to explain, it's a bad idea."

If I absolutely HAD to implement such a "micromacro" system, after
pushing back for all I'm worth and presumably failing, I'd punt and go
for SOURCE manipulation instead (which does in turn give heavy
constraints -- no bytecode-only distribution). For example, here's a
WAY over-fragile example, intended STRICTLY as such:

import inspect

def manip(f):
s = inspect.getsourcelines(f)[0]
delta = len(s[0])-len(s[0].lstrip())
del s[0]
s[:] = [x[delta:] for x in s]
delta = len(s[1])-len(s[1].lstrip())
s.insert(1, delta*' '+'x=23\n')
d = {}
exec ''.join(s) in d
return d[f.func_name]

class X(object):

@manip
def a(self):
print x

@manip
def b(self):
print x+2

x = X()
x.a()
x.b()
The 'manip' example decorator places many implicit constraints on the
sourcecode of the method that it decorates (single-line def clause, NO
docstring to follow, no use of tabs for indentation but rather only
spaces, etc, etc), which is why it's WAY over-fragile -- but, it does
insert an 'x=23' assignment at the very top, as requested. It can, of
course, be reimplemented in a MUCH more solid way, too (e.g., by using
the Python interface to the AST compiler which seems likely to get
introduced in Python 2.5 -- apparently, a prototype of such a Python
module HAS been already implemented during Pycon, i.e., today).

Personally, I would keep pushing back against this approach even after
I'd gone to the trouble of implementing it more solidly -- in no way is
clarity served by having magic local variables appear out of the blue
(or, rather, the black of black magic). However, whether something CAN
be done, and whether it SHOULD be done, are separate issues.
Alex
Feb 27 '06 #2
Alex Martelli wrote:
Michal Kwiatkowski <ru**@no.spam> wrote:
...
def method(self):
var_one = self.attr_one
var_two = self.attr_two.another_attr
empty_list = []
# significant code goes here ...

Personally, I would keep pushing back against this approach even after
I'd gone to the trouble of implementing it more solidly -- in no way is
clarity served by having magic local variables appear out of the blue
(or, rather, the black of black magic). However, whether something CAN
be done, and whether it SHOULD be done, are separate issues.


I agree with your approach to local variables appearing out of nowhere,
but still, it's a real pain to copy-and-paste few lines of this standard
initialization to each new method I add. And then imagine another local
variable will be needed and I have to change every single method...
That's even more bug prone than magic-variables approach, if you ask me.
The problem wouldn't be such a problem if Python had implicit self...
but on the other side, it's another ambiguity.

Well, maybe you can help me in refactoring this code, so that it won't
be such a pain to easily modify groups of methods? I'm thinking about this:

def init_arguments(fun):
def new_f(self):
var_one = self.attr_one
var_two = self.attr_two.another_attr
empty_list = []

fun(self, var_one, var_two, empty_list)

return new_f

@init_arguments
def method(self, var_one, var_two, empty_list):
# significant code goes here
# ...

But the bad thing about this approach is that actual method doesn't
really look like its definition, because of different number of arguments.

mk
--
. o . >> http://joker.linuxstuff.pl <<
. . o It's easier to get forgiveness for being wrong
o o o than forgiveness for being right.
Feb 27 '06 #3
Michal Kwiatkowski <ru**@no.spam> wrote:
...
The problem wouldn't be such a problem if Python had implicit self...
but on the other side, it's another ambiguity.
In your example, you could avoid assigning var_one, but the purpose of
assigning var_two and empty_list obviously would not go away with
implicit self (and attendant ambiguities).

Well, maybe you can help me in refactoring this code, so that it won't
be such a pain to easily modify groups of methods? I'm thinking about this:

def init_arguments(fun):
def new_f(self):
var_one = self.attr_one
var_two = self.attr_two.another_attr
empty_list = []

fun(self, var_one, var_two, empty_list)
You probably want a 'return fun(...)' here, for generality.
return new_f

@init_arguments
def method(self, var_one, var_two, empty_list):
# significant code goes here
# ...

But the bad thing about this approach is that actual method doesn't
really look like its definition, because of different number of arguments.


Yep, but to avoid black magic those names DO have to be identified as
locals to the compiler at the time of the 'def method(...', which
happens before the decorator gets to play. If you're keen on using
those barenames as locals in method, there's no clean way out.

Personally, I would give up on the bareness of the names and bunch them
up into a specially named bunch, say _ (single underscore) assuming you
don't need that for other purposes such as i18n. The method's signature
would be a formulaic 'def method(_, self [other args if any])' -- or you
could swap _ and self, if you wish; and the decorator could supply as _
a magic object (nothing black about it;-) with the suitable behavior,
not just for getting attributes, but also for setting them. If you're
sure you don't need to set them, then a simple Bunch instance with the
usual 'class Bunch: pass', or any other such approach, will suffice.

But of course, then the method's body would have to use _.one rather
than var_one, _.two rather than var_two, and _.empty_list rather than
empty_list (what a strange name -- does it STAY empty throughout the
method's execution?!). To me this looks like a small price to pay, and
the 'def method(_, self, ...)' signature a clear, strong indication that
something weird, but not TOO weird, is going on. YMMV...
Alex
Feb 27 '06 #4
Alex Martelli wrote:
But of course, then the method's body would have to use _.one rather
than var_one, _.two rather than var_two, and _.empty_list rather than
empty_list (what a strange name -- does it STAY empty throughout the
method's execution?!). To me this looks like a small price to pay, and
empty_list name was chosen only for sake of an example.
the 'def method(_, self, ...)' signature a clear, strong indication that
something weird, but not TOO weird, is going on. YMMV...


Thanks for your reply, I'll consider your suggestion.

mk
--
. o . >> http://joker.linuxstuff.pl <<
. . o It's easier to get forgiveness for being wrong
o o o than forgiveness for being right.
Feb 27 '06 #5
Michal Kwiatkowski wrote:
def init_arguments(fun):
def new_f(self):
var_one = self.attr_one
var_two = self.attr_two.another_attr
empty_list = []

fun(self, var_one, var_two, empty_list)

return new_f

@init_arguments
def method(self, var_one, var_two, empty_list):
# significant code goes here
# ...

But the bad thing about this approach is that actual method doesn't
really look like its definition, because of different number of arguments.


I've come up with a solution that don't have this disadvantage. Here we go:

def wrap_method(self, do):
var_one = self.attr_one
var_two = self.attr_two.another_attr
empty_list = []

return do(self, var_one, var_two, empty_list)

def method(self):
def do(self, var_one, var_two, empty_list):
# significant code goes here
# ...
return self.wrap_method(do)

All is implicit and have an advantage of being clear in < 2.4, where
there are no nice @ decorator syntax. Again, simple things proved to be
better. :)

mk
--
. o . >> http://joker.linuxstuff.pl <<
. . o It's easier to get forgiveness for being wrong
o o o than forgiveness for being right.
Feb 27 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
by: Olumide | last post by:
I'm studying Nigel Chapman's Late Night Guide to C++ which I think is an absolutely fantastic book; however on page 175 (topic: operator overlaoding), there the following code snippet: inline...
7
by: Edward Yang | last post by:
A few days ago I started a thread "I think C# is forcing us to write more (redundant) code" and got many replies (more than what I had expected). But after reading all the replies I think my...
4
by: vooose | last post by:
Consider { bool var; if(var) Console.WriteLine("var is true"); } results in the compilation error
5
by: Jesper Schmidt | last post by:
When does CLR performs initialization of static variables in a class library? (1) when the class library is loaded (2) when a static variable is first referenced (3) when... It seems that...
28
by: RickHodder | last post by:
I'm getting frustrated with using try...catch with local variables: The code below wont compile in .NET 1.1: I get the following error: "Use of unassigned local variable 'oProcessFileReader' " ...
21
by: Sriram Rajagopalan | last post by:
Hi, Which of these two would be a better way of initializing the local variables? and why? 1) At the time of their declaration. Eg: void func()
55
by: Zytan | last post by:
I see that static is more restricted in C# than in C++. It appears usable only on classes and methods, and data members, but cannot be created within a method itself. Surely this is possible in...
4
by: subramanian100in | last post by:
I read in C++ Primer 4th Edition by Stanley Lippman, in page 57, that const variables at global scope are local to a file by default. What is the advantage of this rule ? Suppose I have the...
2
by: auspicious | last post by:
Hi, I would like to know what does the standard say about initialization of local static variable's default initialization. void f(int a) { static int b; b+=a; }
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.