Below, see the batch file and the configuration script for
my Python interactive prompt.
The widths of the secondary prompts increase when the self.count of
SysPrompt1 exceeds 99.
I am using a global variable "zxc" to share self.count, which is not
Pythonic.
How can I pass in self.count without a global?
I did RTFM, aka Google, but to no avail.
echo py.bat
set PYTHONSTARTUP=c:\scripts\startup.py
python
^Z
# startup.py
# inspired by:
# http://www.doughellmann.com/PyMOTW/sys/interpreter.html
import sys
class SysPrompt1(object):
def __init__(self):
self.count = 0
def __str__(self):
self.count += 1
global zxc
zxc = self.count
return '[%2d]> ' % self.count
class SysPrompt2(object):
def __str__(self):
global zxc
if zxc > 99: return '...... '
else: return '..... '
class DisplayHook(object):
def __call__(self, value):
if value is None: return
global zxc
if zxc > 99: print '[ out]', value, '\n'
else: print '[out]', value, '\n'
class ExceptHook(object):
def __call__(self, type, value, trace):
global zxc
if zxc > 99: print '[ err]', value, '\n'
else: print '[err]', value, '\n'
sys.ps1 = SysPrompt1()
sys.ps2 = SysPrompt2()
sys.displayhook = DisplayHook()
sys.excepthook = ExceptHook()
First of all, you shouldn't do OOP if you don't feel it. Python,
unlike Java and like C++, supports also procedural programming, so you
can write your scripts without writing classes (but still using
objects, since all in python is an object).
If you have classes with no data and a single __call_ method, then
they are no classes, they are functions (or methods) in disguise.
So, one solution could be to use plain functions and use global as you
already do. 'global' is pythonic if you are not doing OOP, although I
don't like it.
If you want to stick to OOP, then I suggest to have a make
display_hook and except_hook methods of your class SysPrompt1; This
way all your code can access to self.count without needing globals.
As for your class SysPrompt2, I don't understand enough your code to
know what you are trying to do. maybe make it a sunclass of
SysPrompt1 ?
HTH
Ciao
----
FB
It's not "unpythonic" - but it's not good OO style neither !-)
> How can I pass in self.count without a global?
(snip)
> sys.ps1 = SysPrompt1()
> sys.ps2 = SysPrompt2()
> sys.displayhook = DisplayHook()
> sys.excepthook = ExceptHook()
>
hint #1: a bound method is also a callable.
hint #2: an object can be an attribute of another object.
Possible OO solution:
class Counter(object):
def __init__(self):
self._count = 0
def inc(self):
self._count += 1
value = property(fget=lambda s: s._count)
class Prompt1(object):
def __init__(self, counter):
self._counter = counter
def _str_(self):
self._counter.inc()
return '[%2d]> ' % self._counter.value
class Prompt2(object):
def __init__(self, counter):
self._counter = counter
def _str_(self):
if self._counter.value > 99: # XXX magic number
return '...... '
else:
return '..... '
class MySysHookHandler(object):
def __init__(self):
self._counter = Counter()
self.ps1 = Prompt1(self._counter)
self.ps2 = Prompt2(self._counter)
def displayhook(self, value):
if value is None:
return
if self._counter.value > 99: # XXX magic number
print '[ out]', value, '\n'
else:
print '[out]', value, '\n'
def excepthook(self, type, value, trace):
if self._counter.value > 99: # XXX magic number
print '[ err]', value, '\n'
else:
print '[err]', value, '\n'
handler = MySysHook()
sys.ps1 = handler.ps1
sys.ps2 = handler.ps2
sys.displayhook = handler.displayhook
sys.excepthook = handler.excepthook
HTH
However, if you used a single class instead of multiples then you could
use an instance variable for zxc, and have each of the functions be
bound methods (i.e. methods of the instance, not the class).
This is untested code (some days I don't seem to write any other kind
...) but it should give you the flavor:
class kbInterface(object):
def __init__(self):
self.zxc = 0
def prompt1(self):
self.count += 1
return "[%d]> "
def prompt2(self):
l = len(str(self.count))+1
return "%s " % "."*l
def dhook(self, value):
print "[%d out]" % self.count
def ehook(self, type, value, trace):
print "[%d err]\n" % value
kbi = kbInterface()
sys.ps1 = kbi.prompt1
sys.ps2 = kbi.prompt2
sys.displayhook = kbi.dhook
sys.excepthook = kbi.ehook
Do you get the idea? Now the count is shared between all the methods,
and it's available in the instance's namespace.
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/
indeed !-)
> class kbInterface(object):
> def __init__(self):
> self.zxc = 0
> def prompt1(self):
> self.count += 1
Ahem...
(snip)
> This is untested code (some days I don't seem to write any other kind
> ...) but it should give you the flavor:
>
> class kbInterface(object):
> def __init__(self):
> self.zxc = 0
> def prompt1(self):
> self.count += 1
> return "[%d]> "
> def prompt2(self):
> l = len(str(self.count))+1
> return "%s " % "."*l
> def dhook(self, value):
> print "[%d out]" % self.count
> def ehook(self, type, value, trace):
> print "[%d err]\n" % value
>
> kbi = kbInterface()
> sys.ps1 = kbi.prompt1
> sys.ps2 = kbi.prompt2
> sys.displayhook = kbi.dhook
> sys.excepthook = kbi.ehook
Unfortunately this won't do what you expect, because sys.ps1 and ps2
should be either strings, or objects with a __str__ method. They aren't
called to generate the prompt.
(After fixing the typo with self.count vs self.zxc)
>>> kbi = kbInterface()
>>> sys.ps1 = kbi.prompt1
<bound method kbInterface.prompt1 of <__main__.kbInterface object at
0xb7cbd52c>>print "Hello"
Hello
<bound method kbInterface.prompt1 of <__main__.kbInterface object at
0xb7cbd52c>>
--
Steven
> Steven D'Aprano wrote:
> [... points out my misapprehension ...]
>>
>>>>> kbi = kbInterface()
>>>>> sys.ps1 = kbi.prompt1
>> <bound method kbInterface.prompt1 of <__main__.kbInterface object at
>> 0xb7cbd52c>>print "Hello"
>> Hello
>> <bound method kbInterface.prompt1 of <__main__.kbInterface object at
>> 0xb7cbd52c>>
>>
> Right, this is expert mode ...
Here's a way to turn expert mode into something less advanced:
>>> import sys
>>> def expert_mode():
... return "for newbies ;) "
...
>>> sys.ps1 = expert_mode
<function expert_mode at 0x7f498b9735f0>class Str:
... def __init__(self, f): self.f = f
... def __str__(self): return self.f()
...
<function expert_mode at 0x7f498b9735f0>sys.ps1 = Str(expert_mode)
for newbies ;)
Peter
but their __str__ does get called to generate the prompt.
import sys
class kbInterfaceHelper(object):
def __init__(self, str_func):
self.str_func = str_func
def __str__(self):
return self.str_func()
class kbInterface(object):
def __init__(self):
self.count = 0
def prompt1(self):
self.count += 1
return "[%d]> " % self.count
def prompt2(self):
l = len(str(self.count))+1
return "%s " % "."*l
def dhook(self, value):
print "[%d out]" % self.count
def ehook(self, type, value, trace):
print "[%d err]\n" % value
kbi = kbInterface()
sys.ps1 = kbInterfaceHelper(kbi.prompt1)
sys.ps2 = kbInterfaceHelper(kbi.prompt2)