Python equivalent for C module

D

Derek Martin

I'd like to know if it's possible to code something in Python which
would be equivalent to the following C:

[Assume bool is typedef'd to int, and TRUE and FALSE are #defined to 1
and 0, respectively]

---- debug.c ----
#include <stdio.h>

bool DEBUG;

void dprint(char *msg)
{
if (DEBUG){
printf("DEBUG: %s", msg);
}
}

---- end of debug.c ----

The idea being that all modules of the program would "import" this
code via the header file:

---- debug.h ----
extern bool DEBUG;
void dprint(char *msg);
---- end of debug.h ----

I'm specifically trying to avoid having to create a debug object and
pass it around... All modules should have visibility into the state of
whether DEBUG is turned on or off, and be able to use dprint(). Can
Python do this?

I tried creating debug.py as such:

---- debug.py ----
DEBUG = True
def dprint(msg):
if DEBUG:
print("DEBUG: %s" % msg)
---- end ----

Then in the modules that wanted to use it, I did:

from debug import DEBUG, dprint

But I got some weird behavior. The imported copy of DEBUG is
read-only; if you update it, the name DEBUG points to a different
object which the other modules can't see. After doing some reading of
the docs, this behavior is explained and understood (though obviously
not what I want). It just occured to me that I might be able to get
around that by using a setter function in the module itself... I'll
try this later.

The other weird behavior was, once I changed the value of DEBUG,
dprint() started to behave oddly. No matter what I passed as an
argument (and no matter what I set the value of DEBUG to be), it
started printing the exact literal string:

DEBUG: %s

whenever it was called. It was as if the function couldn't see the
parameter msg, which was passed via the call. Most unexpected, and
definitely undesirable.

--
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0x81CFE75D


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQFI/L2HdjdlQoHP510RAhK6AJ4sD23vaAlBxaCYFGlS9g6Uhhd1FACeJbkO
kIDJ86K7S2+B5m0uKKNoIlo=
=5Uek
-----END PGP SIGNATURE-----
 
B

Bruno Desthuilliers

Derek Martin a écrit :
I'd like to know if it's possible to code something in Python which
would be equivalent to the following C:

[Assume bool is typedef'd to int, and TRUE and FALSE are #defined to 1
and 0, respectively]

---- debug.c ----
#include <stdio.h>

bool DEBUG;

void dprint(char *msg)
{
if (DEBUG){
printf("DEBUG: %s", msg);
}
}


This should have been:

fprintf(STDERR, "DEBUG: %s", msg);

STDOUT is for *normal* program outputs. Debug informations, warnings,
and all verbosity should go to STDERR.

---- end of debug.c ----

The idea being that all modules of the program would "import" this
code via the header file:

---- debug.h ----
extern bool DEBUG;
void dprint(char *msg);
---- end of debug.h ----

I'm specifically trying to avoid having to create a debug object and
pass it around... All modules should have visibility into the state of
whether DEBUG is turned on or off, and be able to use dprint(). Can
Python do this?

Yes, indeed.
I tried creating debug.py as such:

---- debug.py ----
DEBUG = True
def dprint(msg):
if DEBUG:
print("DEBUG: %s" % msg)
---- end ----

Same remark : please use sys.stderr

Then in the modules that wanted to use it, I did:

from debug import DEBUG, dprint
But I got some weird behavior. The imported copy

It's not a copy.
of DEBUG is
read-only;

It's not read-only.
if you update it, the name DEBUG points to a different
object which the other modules can't see.

Indeed : the way you imported it explicitely made it a (module) local name.
After doing some reading of
the docs, this behavior is explained and understood (though obviously
not what I want). It just occured to me that I might be able to get
around that by using a setter function in the module itself...

Just use a fully qualified name, so you dont make DEBUG local:

import debug
print debug.DEBUG
debug.DEBUG = True
print debug.DEBUG

Now note that ALL_UPPER names are - by convention - considered
'constants'. If this is supposed to be altered, don't write it ALL_UPPER.
The other weird behavior was, once I changed the value of DEBUG,
dprint() started to behave oddly. No matter what I passed as an
argument (and no matter what I set the value of DEBUG to be), it
started printing the exact literal string:

DEBUG: %s
>
whenever it was called. It was as if the function couldn't see the
parameter msg, which was passed via the call. Most unexpected, and
definitely undesirable.

I just fail to see how the code you posted could expose such a
behaviour. Please post actual code.


Also and FWIW, Python has a logging module in it's stdlib. Please use it
instead of any half-backed squared-wheel homegrown solution.

My 2 cents
 
A

Aaron Brady

I'm specifically trying to avoid having to create a debug object and
pass it around... All modules should have visibility into the state of
whether DEBUG is turned on or off, and be able to use dprint().  Can
Python do this?

I tried creating debug.py as such:

---- debug.py ----
DEBUG = True
def dprint(msg):
    if DEBUG:
        print("DEBUG: %s" % msg)
---- end ----

Then in the modules that wanted to use it, I did:

from debug import DEBUG, dprint

But I got some weird behavior.  The imported copy of DEBUG is
read-only; if you update it, the name DEBUG points to a different
object which the other modules can't see.  After doing some reading of
the docs, this behavior is explained and understood (though obviously
not what I want).  It just occured to me that I might be able to get
around that by using a setter function in the module itself... I'll
try this later.

The other weird behavior was, once I changed the value of DEBUG,
dprint() started to behave oddly.  No matter what I passed as an
argument (and no matter what I set the value of DEBUG to be), it
started printing the exact literal string:

DEBUG: %s

whenever it was called.  It was as if the function couldn't see the
parameter msg, which was passed via the call.  Most unexpected, and
definitely undesirable.

It should work if you set the attribute of the module directly.

(untested)
import debug
debug.DEBUG= True
debug.DEBUG= False

Your idea of a module getter/setter should work too.

def set_debug( val ):
global DEBUG
DEBUG= val

Can't help with the other problem. Simplify a little with just
print( msg ).
 
B

Bruno Desthuilliers

Ville M. Vainio a écrit :
Actually, stderr is for errors, by convention. It's rather impolite to
dump trivial debug info to stderr, which often "alerts" the user more
than stdout.

If you "dump trivial debug infos" to stdout, you just break anything
relying on stdout being for *normal* program outputs - IOW, you just can
chain-pipe programs no more. As far as I'm concerned, it's *way* more
impolite than "alerting" the user. Also and FWIW, most programs have
--quiet and --verbose options that let the user specify verbosity.
Unfortunately these square-wheeled homegrown solutions are easier to
grok than the standard logging module. It seems to target more
"serious" applications at the cost of feeling a bit too clunky for
quick hack jobs.

If it's for a "quick hack job", you don't even need anything like what
the OP describe. For anything more serious - anything that requires more
than one .py script file with a couple functions and a main section -,
the couple minutes spent setting up a default logger will very quickly
pay off.

But YMMV, of course...
 
V

Ville M. Vainio

Bruno Desthuilliers said:
STDOUT is for *normal* program outputs. Debug informations,
warnings, and all verbosity should go to STDERR.

Actually, stderr is for errors, by convention. It's rather impolite to
dump trivial debug info to stderr, which often "alerts" the user more
than stdout.
Also and FWIW, Python has a logging module in it's stdlib. Please
use it instead of any half-backed squared-wheel homegrown solution.

Unfortunately these square-wheeled homegrown solutions are easier to
grok than the standard logging module. It seems to target more
"serious" applications at the cost of feeling a bit too clunky for
quick hack jobs.
 
S

Steven D'Aprano

No, it shouldn't have. If I turn on debugging, I want the debug
messages to go to stdout, so that they can be captured along with the
output (of which there is almost none anyway) to clearly indicate when
they happened.

I agree with this: debugging messages aren't errors, and shouldn't go to
stderr.


[...]
Actually, I'm pretty sure it is; i.e. there are two copies of the name:
one in the namespace of the module, and one in the namespace of the file
into which I imported it.

Names are not first class Python objects. You can't pass a name to a
function and say "do something to this *name*, not the object".

(Of course you can pass a string that happens to match the name to exec,
but that's not the same thing.)

If you dig around in globals() or locals(), you will find strings 'DEBUG'
and 'dprint', but they aren't "names". They're just the strings that
represents the names, and it turns out that CPython caches many (all?)
such strings which look like identifiers, so there probably is literally
one and only one string 'DEBUG' no matter how many times you import the
module.

All of this is just splitting hairs, because you don't really mean Python
is making a copy of the name 'DEBUG', but of the *data* that DEBUG refers
to, namely the object True. And it turns out that True is a singleton:
there is only ever one object True.

But even if DEBUG was set to some other value, say [1, 2, 3, 'x'], you'd
still be wrong, because Python promises never to copy objects unless you
explicitly tell it to. There are a number of ways to prove this, but
perhaps this is the simplest:

DEBUG = [True] # a mutable list

Now from your calling code, do this:

from module import DEBUG
DEBUG[0] = False # mutate the object, don't rebind the name

At the time they are created, they both point
to the same object. Is that not the very definition of a copy?

No. It would be a copy if they pointed to different objects, where one
object was a copy of the other.

The
object itself may exist only in one place,

which is exactly why there is no copy. It's the same object.

but it has two names; one in each namespace.


The *object* very much is: it is immutable.

So what? The *name* DEBUG is not read-only.

The name of that object is
DEBUG, and thus DEBUG is read-only.

But it clearly isn't read-only, because as you yourself point out:
You can make DEBUG point to a
different object by binding a different value to it

[...]
Right, several people have already pointed this out. Which leads me to
believe that the point of your reply was to berate me into following
your conventions, which I have no interest in doing, in part because
they are counterproductive to my goals, and in part because they are
counter to the way I've been programming for 25 years. Fortunately, it's
not your call how I write my code.

No, and it's not your call what advice people give you. If you refuse to
follow good Pythonic advice because you prefer the way you learned
programming a quarter century ago (before Python even existed), please go
right ahead, but don't be surprised if people consider you a lousy Python
programmer.

YOUR convention, not mine.

Actually it is a very common convention in Python circles. I often use it
myself. However it's not the only one, and from time to time I use
others. I would consider using DEBUG unusual, but not excessively so.

Note that the correct possessive form of "it" is "its" with no
apostrophe. This was the only thing of value which you contributed,
though really, using that is way overkill for my needs. If I've written
bad code, by all means, please correct it. If I've written code in a
style that you happen not to like, please feel free to keep that to
yourself.

Deary deary me... you come along here, asking noob Python questions, and
then get shirty when people give you friendly and perfectly good answers.
Are you trying to ensure that the next question you ask remains
unanswered?
 
A

Aaron Brady

Actually, stderr is for errors, by convention. It's rather impolite to
dump trivial debug info to stderr, which often "alerts" the user more
than stdout.
snip

Indeed. Just dump to STDTRIVIAL.
 
D

Derek Martin

All of this is just splitting hairs,

Indeed... :)
because you don't really mean Python is making a copy of the name
'DEBUG', but of the *data* that DEBUG refers to, namely the object
True.

Well, as long as we're having semantic discussions... If you reread
my post, it should be clear that what you wrote above can not possibly
be the case. If you recall, my intent was to make a copy of a means
of accessing the value known by the name "DEBUG" contained in the
debug module, which could be accessed from any module in the program.
Clearly the data itself *must not* be a copy, or else what I was
trying to do would never have worked. What I was refering to as a
copy was in fact essentially the name, or more accurately (as regards
my conception of purpose) a reference to the data.
So what? The *name* DEBUG is not read-only.

You may have missed where I explained that the name refers to two
different things, and that I, speaking in loose terms, was refering to
both things simultaneously but in different contexts. I was speaking
loosely -- I was using "read-only" as a figure of speech of sorts, and
elaborated *correctly* what actually happens. Again, if you reread
my original post with that explanation in mind, I think you'll find
that this is the only sensible interpretation for what I wrote.
Actually it is a very common convention in Python circles. I often use it
myself. However it's not the only one, and from time to time I use
others. I would consider using DEBUG unusual, but not excessively so.

To be honest, same here. My post contained throw-away C code that I
typed up on the fly, and the same goes for the Python -- I simply
translated the C code literally, so to speak. As has been pointed out
in a different thread (by Bruno himself, if I'm not mistaken), the
code hastily posted here need not represent the code that one would
write in "real" programs. But I find it offensive that certain people
here can't resist lambasting some posters who have simple questions,
because the code they posted isn't up to their particular favorite
coding "standards" (i.e. conventions), and I will speak out about it,
especially when it's done to me. I didn't ask about coding
conventions, but Bruno's response was roughly 75% about how my code
sucks, and maybe 25% about answering my question. And what part did
answer my question was completely redundant. It was roughly 95% a
waste of time and energy for both him and me, though I did learn about
the logging module...
Deary deary me... you come along here, asking noob Python questions, and
then get shirty when people give you friendly and perfectly good answers.

Well, we disagree that the answer Bruno provided was either friendly
or perfectly good. I did receive perfectly good answers, and if you
read the whole thread, you saw me accept such answers graciously.
Bruno's answer smacked of a superiority and arrogance that is not
uncommon among certain frequent posters. He has no idea what my
program does, or what my real code looks like, but apparently deigns
himself the Code Police, and finds it necessary to punnish people for
posting code which does not conform to his idea of Programming Law.

I can't deny that I should have been able to answer my own question
with only a few more moments thought... Though I don't think it's
quite right to characterize questions about scope as "noob" questions.
I suspect actual noobs don't yet know enough to ask such questions.
Are you trying to ensure that the next question you ask remains
unanswered?

Not at all, just trying to preempt the pound of attitude that often
goes with the ounce of answers. But if the choice is between no
answer, and an answer that barely manages to avoid calling me an idiot
(especially over coding style), I'd rather have no answer.

--
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0x81CFE75D


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQFI/VrodjdlQoHP510RAlP0AKCVY28QZExTJ3+epEepD9k0UP13PwCcD0Jl
4HsvU97JMRcBpKuAOSoCCwQ=
=lHMm
-----END PGP SIGNATURE-----
 
V

Vinay Sajip

Unfortunately these square-wheeled homegrown solutions are easier to
grok than the standardloggingmodule. It seems to target more
"serious" applications at the cost of feeling a bit too clunky for
quick hack jobs.

I'm surprised to hear you say that. All you need is

import logging

logging.warning("Message with %s data", "variable") # or debug, info,
error

and I'd like to know what simpler interface you think would be better/
easier to grok for quick hack jobs.

Regards,

Vinay Sajip
 
B

Bruno Desthuilliers

Derek Martin a écrit :
No, it shouldn't have. If I turn on debugging, I want the debug
messages to go to stdout, so that they can be captured along with the
output (of which there is almost none anyway) to clearly indicate when
they happened.

Then redirect stderr to stdout.
That's your opinion,

Nope, that's what stderr and stdout were designed for.
and I disagree. Besides which, if you're running
a program in debug mode, you're DEBUGGING... "normal" does not apply.

so you'd find it ok for, say, a compression program, to intermix
compressed data (it's normal output) with debugging infos ? Well, it's
your program so you're of course free to write it as you want...
You're being rather presumptuous... you don't even know how my program
is being used.

Nope. But I do know the difference between sterr and stdout. Call me
names for it if you want, but I'm not sure I understand how it will help.
Actually, I'm pretty sure it is; i.e. there are two copies of the
name:

of the name, yes. Not of the object. We obviously weren't talking about
the same thing.
one in the namespace of the module, and one in the namespace of
the file into which I imported it.
>
At the time they are created, they
both point to the same object. Is that not the very definition of a
copy? The object itself may exist only in one place, but it has two
names; one in each namespace.
Indeed.


The *object* very much is: it is immutable. The name of that object
is DEBUG, and thus DEBUG is read-only. You can make DEBUG point to a
different object by binding a different value to it, but if that value
is of an immutable type, it will still be a read-only object.

Here again, not talking about the same thing. And I do know what's an
immutable object, and how name binding works in Python, thanks.
In the sentence I wrote, as well as in general, "DEBUG" actually
refers to two different things: the object bound to the name, and the
name itself. It's up to the reader to infer which sense is correct
given the thing being said about it. It just so happens that the
English sentence I wrote refers to both simultaneously.

And that I was refering to the name when you were talking about the
object and vice-versa.
Right, several people have already pointed this out.

Indeed. That's the pythonic solution to your problem. Since I can infer
from what you wrote above that you have a correct understanding of name
bindings and scopes in Python, I can only wonder why you don't just use
thos solution.
Which leads me
to believe that the point of your reply was to berate me into
following your conventions,

???

This is just insane. This is how name binding works in Python. It's not
"my convention", nor anyone else convention, it's just how the language
works.
which I have no interest in doing, in part
because they are counterproductive to my goals, and in part because
they are counter to the way I've been programming for 25 years.

Bad news : Python is not C.
Fortunately, it's not your call how I write my code.

Write you code the way you like, I just don't give a damn.
YOUR convention, not mine.

Nope, Python's coding standard. Not mine.
Note that the correct possessive form of "it" is "its" with no
apostrophe.

Note that this is an international newsgroup, that I'm not a native
english speaker, and that this remark, in the context, is - by usenet
standards, not mine - to be considered as a deliberate insult.
This was the only thing of value which you contributed,

Glad to be helpful somehow.
though really, using that is way overkill for my needs. If I've
written bad code, by all means, please correct it. If I've written
code in a style that you happen not to like, please feel free to keep
that to yourself.

If all you have to contribute here is flaming and insulting people that
at least try to answer your questions, please feel free to post your
contribution somewhere else.
Must be Zimbabwe currency...

Godwin point ahead. Good luck Mr. Martin.
 
V

Ville M. Vainio

Vinay Sajip said:
import logging

logging.warning("Message with %s data", "variable") # or debug, info,
error

and I'd like to know what simpler interface you think would be better/
easier to grok for quick hack jobs.

It's not the logging itself that is a problem, it's setting up the
loggers that was nontrivial (back in the day I last tried it).

Some googling revealed what was my problem back in 2004:

http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/3714.html

I do realize the technical problems of coming up with
one-size-fits-all solution for a problem domain like this.
 

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,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top