473,320 Members | 1,945 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,320 software developers and data experts.

Refactoring Dilemma

'''
I'm in the middle of a refactoring dilemma.
I have several singletons that I'm turning into modules, for ease of
access.
The usual method is noted as 'Module 1' below.
The new method is noted as 'Module 2'.
Is there any reason NOT to do this that I may be unaware of?
It's easier than remembering to declare global variables at the top of
the function.
'''

# ----------- Module 1.py ------------
# Normal module processing
var = 0

def MyRoutine():
global var
var = 1

MyRoutine()
print var
# ----------- Module 2.py ------------
# 'Self' module processing
import sys
var = 0
self = sys.modules[__name__]

def MyRoutine():
self.var = 1

MyRoutine()
print var

Sep 10 '06 #1
7 1103
Kamilche wrote:
'''
I'm in the middle of a refactoring dilemma.
I have several singletons that I'm turning into modules, for ease of
access.
The usual method is noted as 'Module 1' below.
The new method is noted as 'Module 2'.
Is there any reason NOT to do this that I may be unaware of?
It's easier than remembering to declare global variables at the top of
the function.
'''

# ----------- Module 1.py ------------
# Normal module processing
var = 0

def MyRoutine():
global var
var = 1

MyRoutine()
print var
# ----------- Module 2.py ------------
# 'Self' module processing
import sys
var = 0
self = sys.modules[__name__]

def MyRoutine():
self.var = 1

MyRoutine()
print var

What's wrong with
<code>
def MyRoutine():
return 1

var = MyRoutine()
</code>
?

George

Sep 10 '06 #2
Kamilche wrote:
'''
I'm in the middle of a refactoring dilemma.
I have several singletons that I'm turning into modules, for ease of
access.
The usual method is noted as 'Module 1' below.
The new method is noted as 'Module 2'.
Is there any reason NOT to do this that I may be unaware of?
It's easier than remembering to declare global variables at the top of
the function.
'''

# ----------- Module 1.py ------------
# Normal module processing
var = 0

def MyRoutine():
global var
var = 1

MyRoutine()
print var
# ----------- Module 2.py ------------
# 'Self' module processing
import sys
var = 0
self = sys.modules[__name__]

def MyRoutine():
self.var = 1

MyRoutine()
print var
I don't see any major problem with it. In fact, I think it's a very
good idea to do this, rather than use global statements, when using
module as a singleton class.

I recently made the same transition myself, though I solved it a bit
differently. I used a decorator to pass the module as the first
argument (actually it passes a proxy to module's global dict, since the
module itself isn't accesible from the function object).

def modmethod(func):
class modproxy(object):
__getattribute__ = func.func_globals.__getitem__
__setattr__ = func.func_globals.__setitem__
self = modproxy()
def call_with_module(*args,**kwargs):
return func(self,*args,**kwargs)
call_with_module.func_name = func.func_name
return call_with_module

@modmethod
def MyRoutine(self):
self.var = 1

MyRoutine()
print var

One problem with my decorator is it makes stack traces a little
bloated. (Also attribute errors are raised as KeyError, but that's
easily fixable.) Other than that, I've been running it for awhile
without any problems. I doubt your approach would have many problems,
either.
Carl Banks

Sep 10 '06 #3
George Sakkis wrote:
Kamilche wrote:
'''
I'm in the middle of a refactoring dilemma.
I have several singletons that I'm turning into modules, for ease of
access.
The usual method is noted as 'Module 1' below.
The new method is noted as 'Module 2'.
Is there any reason NOT to do this that I may be unaware of?
It's easier than remembering to declare global variables at the top of
the function.
'''

# ----------- Module 1.py ------------
# Normal module processing
var = 0

def MyRoutine():
global var
var = 1

MyRoutine()
print var
# ----------- Module 2.py ------------
# 'Self' module processing
import sys
var = 0
self = sys.modules[__name__]

def MyRoutine():
self.var = 1

MyRoutine()
print var


What's wrong with
<code>
def MyRoutine():
return 1

var = MyRoutine()
</code>
?

Kamilche simplified things in his example that obscured the main use
case. Short story is, var is considered a state of the module, and
MyRoutine() is designed to be called from outside the module to modify
the state. Your suggestion can only modify the state of the module
from within, so it won't do.

More detailed discussion:

A common piece of advice when people ask "how can I implement a
singleton in Python" is to use a module. A module, after all, is a
singleton object.

But there's a big problem using a module as a singleton: you need to
use then global statement to rebind module-level variables. Which
means that if you want your module to have lots of modifyable state,
most likely you'll have to use a bunch global statements. And that's a
major pain in the neck when you have to do it a lot and in many
functions.

In these cases, it would be nice if a module could access its own state
in the same way that an instance does, that is, as an attribute. My
approach of using a decorator to pass in a module proxy, and Kamilche's
approach of binding the module object to self, both accomplish this.
Internally, the module behaves very much like a class instance.
Functions in the module act almost exactly like bound methods, and
module-level variables act like instance attributes. The difference
between writing a module and a singleton class thus becomes mostly a
matter of indentation.

In fact, when I made a major switch from using singleton classes to
modules, I was able to change it by dedenting once, and pasting a
@modmethod decoration above each method, with very few other changes.

Carl Banks

Carl Banks

Sep 10 '06 #4
Carl Banks wrote:
Kamilche wrote:
'''
I'm in the middle of a refactoring dilemma.
I have several singletons that I'm turning into modules, for ease of
access.
The usual method is noted as 'Module 1' below.
The new method is noted as 'Module 2'.
Is there any reason NOT to do this that I may be unaware of?
It's easier than remembering to declare global variables at the top of
the function.
'''

# ----------- Module 1.py ------------
# Normal module processing
var = 0

def MyRoutine():
global var
var = 1

MyRoutine()
print var
# ----------- Module 2.py ------------
# 'Self' module processing
import sys
var = 0
self = sys.modules[__name__]

def MyRoutine():
self.var = 1

MyRoutine()
print var

I don't see any major problem with it. In fact, I think it's a very
good idea to do this, rather than use global statements, when using
module as a singleton class.

I recently made the same transition myself, though I solved it a bit
differently. I used a decorator to pass the module as the first
argument (actually it passes a proxy to module's global dict, since the
module itself isn't accesible from the function object).

def modmethod(func):
class modproxy(object):
__getattribute__ = func.func_globals.__getitem__
__setattr__ = func.func_globals.__setitem__
self = modproxy()
def call_with_module(*args,**kwargs):
return func(self,*args,**kwargs)
call_with_module.func_name = func.func_name
return call_with_module

@modmethod
def MyRoutine(self):
self.var = 1

MyRoutine()
print var
This looks quite hackish, both the implementation and the usage; most
people would get confused when they didn't find var's assignment at
global scope. I prefer the the simple global statements if they aren't
that many, otherwise the assignment of the module to self is also fine.

George

Sep 11 '06 #5

George Sakkis wrote:
Carl Banks wrote:
I don't see any major problem with it. In fact, I think it's a very
good idea to do this, rather than use global statements, when using
module as a singleton class.

I recently made the same transition myself, though I solved it a bit
differently. I used a decorator to pass the module as the first
argument (actually it passes a proxy to module's global dict, since the
module itself isn't accesible from the function object).

def modmethod(func):
class modproxy(object):
__getattribute__ = func.func_globals.__getitem__
__setattr__ = func.func_globals.__setitem__
self = modproxy()
def call_with_module(*args,**kwargs):
return func(self,*args,**kwargs)
call_with_module.func_name = func.func_name
return call_with_module

@modmethod
def MyRoutine(self):
self.var = 1

MyRoutine()
print var

This looks quite hackish, both the implementation and the usage;
Once again, the function MyRoutine is intended to be called from
another module. The usage I have here is just an example demonstrating
that var is in the module's dict. Please keep this in mind when
criticizing usage. The intended usage would be something like this
(from another module):

from xxx import yyy
yyy.MyRoutine()

As far as the caller is concerned, yyy could be a module using globals,
a module with this "hack", or a class instance, or something else. It
doesn't matter; usage is the same in all three cases.

As for the implementation...
most
people would get confused when they didn't find var's assignment at
global scope. I prefer the the simple global statements if they aren't
that many, otherwise the assignment of the module to self is also fine.
For ordinary modules that might have one or two serial number counters
or debug flags or whatnot, I agree. For modules that have lots of
state and act more like class instances than modules, the massive
amounts of globals are ugly and error prone. In that case you should
either use a regular class, or tolerate the "hack"; don't use a bunch
of globals.

I think a simple comment at the top could take care of any confusion
about what's happening. Since it mimics how a class works, it won't be
anything completely new.

YMMV.

Carl Banks

Sep 11 '06 #6
George Sakkis wrote:
I prefer the the simple global statements if they aren't
that many, otherwise the assignment of the module to self is also fine.
I replied to this article, and then canceled the reply (but that never
works), thinking you were criticizing the general concept of "module as
a singleton" and not just my approach. I should learn to read. I
apologize for the misunderstanding.

I do agree my implementation is a little hacky, although IMHO it feels
to fit in with the way classes work better, which appeals to me but
probably not most people :). For one thing, the methods have the
explicit self argument, like regular classes. For another, it uses a
decorator to affect the binding of the modules. In regular classes,
functions are instance methods by default, and become class methods or
static methods with a decorator. I like to think of modules as having
a special metaclass that treats functions as static methods by default,
and uses a decorator to get an instance method. (Even though that
isn't remotely how it works, it fits how it would work if you were
implementing modules based on classes.)

Having said that, I've no problem with Kamilche's approach. The real
evil in my mind is using lots of global statements, and anything you
can do to stay away from that is a good thing.
Carl Banks

Sep 11 '06 #7
Kamilche wrote:
Is there any reason NOT to do this that I may be unaware of?
[snip]
# ----------- Module 2.py ------------
# 'Self' module processing
import sys
var = 0
self = sys.modules[__name__]

def MyRoutine():
self.var = 1

MyRoutine()
print var
Looks basically fine to me, but I'd probably write it as::

_self = __import__(__name__)

Then you don't need to import sys. I'd also use a leading underscore
for "self" so that it's clearly marked as a module-internal attribute.

STeVe
Sep 11 '06 #8

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

Similar topics

9
by: Peter Dembinski | last post by:
I am trying to write Master Thesis on refactoring Python code. Where should I look for information? -- http://www.dembiński.prv.pl
4
by: | last post by:
Hi, Refactoring a winform causes problems if moving this form to a subdirectory in the same project. What is the workaround for this and will this be fixed in future? Thanks /BOB
0
by: Andre Baresel | last post by:
Hello together, just a year ago I was searching arround for a tool supporting refactoring for c++. I've seen implementations for java and was impressed how an IDE can help with such a feature....
2
by: Sachin Garg | last post by:
Hi, I was trying to find (like many others here) a tool for refactoring C++ code as I have lately been noticing that I spend most of my coding time doing refactoring and some refactoring which...
6
by: Dean Ware | last post by:
Hi, I am part way through developing a C++ application. I am developing it on my own and using VC++ 6.0. I am now at the stage where I wish to start tidying up my code. I have lots of...
8
by: Frank Rizzo | last post by:
I keep hearing this term thrown around. What does it mean in the context of code? Can someone provide a definition and example using concrete code? Thanks.
15
by: Simon Cooke | last post by:
Does anyone know of any tools for refactoring header files? We're using a third party codebase at work, and pretty much every file includes a 50Mb precompiled header file. I'm looking for a tool...
16
by: hzmonte | last post by:
Correct me if I am wrong, declaring formal parameters of functions as const, if they should not be/is not changed, has 2 benefits; 1. It tells the program that calls this function that the...
2
by: HendrikLeder | last post by:
Hello everybody :-) Next year I`ll write my diploma in computer science for business (It`s a degree in Germany) and I`ve some questions about the topic. The diploma will handle about refactoring...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you

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.