This is what I have in mind because I find myself typing the name twice whenever I want to inspect the value of a variable:
a = 1
my_print(a) # "a: 1"
Is this possible in Python?
If you are in control of the calling function, you can hack this to work reasonably well like:
Code:
import inspect
def print_name_and_value(var):
lines = inspect.stack()[1][4]
var_name = ''.join(lines).strip().split('(')[-1].split(')')[0]
print("%s: %d" % (var_name, var))
a = 5
print_name_and_value(a)
Results:
a: 5
How does this work?
The inspect module can be used to inspect the caller, and get the line of code used by the caller. With a bit of string hacking the variable name (assuming it is a simple variable and not a more complex expression) can be gathered from the source code.
I would say "no", and any other magic doable is just... too much magic.
However there's something you can do, and that's looking at the stack trace using the inspect module.
import inspect
def my_print(thingy):
# print("id(thingy)=%s" % id(thingy))
previous_frame = inspect.currentframe().f_back
# print("locals: %s" % previous_frame.f_locals)
for variable_name, variable_value in previous_frame.f_locals.items():
if id(variable_value) == id(thingy):
return("%s: %s" % (variable_name, variable_value))
# print("globals: %s" % previous_frame.f_globals)
for variable_name, variable_value in previous_frame.f_globals.items():
if id(variable_value) == id(thingy):
return("%s: %s" % (variable_name, variable_value))
if __name__ == '__main__':
a = 1
print("Test %s" % my_print(a)) # "a: 1"
list_thingy = [1, 2, 3]
print("Test %s" % my_print(list_thingy))
def and_within_function():
d = {1: "a"}
print("Test %s" % my_print(d))
and_within_function()
But this is not reliable and I'd use it more as a curiosity, since there are plenty of "special cases". For instance: the first 255 integers (I think) in Python occupy a specific memory address so, if you have two variables that are =1 I don't think you're gonna really be guaranteed which one is it.
Related
I wanted to try writing functions of a language to a different one. I opt for C to Python, and here is what I've done so far.
Code:
def printf(text, *args):
print(text % args, end = '')
def scanf(text, *args):
args = input(text % args)
return args
name = None
scanf("What's your name? %s", name)
printf("Hello, %s.\n", name)
Result:
What's your name? NoneBoy
Hello, Boy.
I have 3 problems regarding this question:
scanf doesn't actually print out the variable to be inputted.
I have to implement a variable with no value, but unlike C, where you could just write int result;, you must write it as result = None and my function would print None as well.
It never returned any value.
Are there any solutions I can use to fix these?
You can use static variables for updating any value inside the function.
class Example:
name = "None"
def printf(text, args):
print(text % args, end = '')
def scanf(text, args):
Example.name = input(text)
scanf("What's your name? ", name)
printf("Hello, %s.\n", Example.name)
There are other pre-build functions to use.
This is the example of the user-defined functions.
If you want to use a pre-defined function. Please let me know.
Here's a fun one. Create a file foo.py with the following contents:
OPTIONS = {'x': 0}
def get_option(key):
from foo import OPTIONS
return OPTIONS[key]
if __name__ == '__main__':
OPTIONS['x'] = 1
print("OPTIONS['x'] is %d" % OPTIONS['x'])
print("get_option('x') is %d" % get_option('x'))
Running python foo.py gives the following output:
OPTIONS['x'] is 1
get_option('x') is 0
I would have expected the result to be 1 in both cases. Why is it 0 in the second case?
You are getting this because from foo import OPTIONS line in get_options() function loads a new local OPTIONS variable in a memory whose value is {'x':0}. But if you remove/comment that line, then you got your expected result, this is because as OPTIONS variable in get_options() is now a global variable, not a local.
OPTIONS = {'x': 0}
def get_option(key):
# from foo import OPTIONS
return OPTIONS[key]
if __name__ == '__main__':
OPTIONS['x'] = 1
print("OPTIONS['x'] is %d" % OPTIONS['x'])
print("get_option('x') is %d" % get_option('x'))
You can also debug that by using the id() function which returns the “identity” of an object during it's lifetime.
For that the debugging code is:
OPTIONS = {'x': 0}
def get_option(key):
from foo import OPTIONS
print("Id is %d in get_option" % id(OPTIONS))
return OPTIONS[key]
if __name__ == '__main__':
OPTIONS['x'] = 1
print("Id is %d in main" % id(OPTIONS))
print("OPTIONS['x'] is %d" % OPTIONS['x'])
print("get_option('x') is %d" % get_option('x'))
Output:
Id is 140051744576688 in main
OPTIONS['x'] is 1
Id is 140051744604240 in get_option
get_option('x') is 0
Note: values of id's can be changed on your system.
Now, you can see the id's is different in both place, this means that there are two OPTIONS inside get_options() function one is __main__.OPTIONS and other one is foo.OPTIONS. But, if comment/remove line from foo import OPTIONS in get_options(), you get same id's at both places.
Setting variables as returned lists from functions that contain variables as a returned list doesn't seem to give me any output:
def get_wordlist(num, s):
items_in_wordlist = database_get(num)
print "Trying to get wordlist..."
print items_in_wordlist
items = []
if s == 0:
for item in items_in_wordlist:
items.append((item[1]).decode("hex"))
return items
elif s == 1:
for item in items_in_wordlist:
items.append((item[2]).decode("hex"))
return items
def get_wordlist_set(self, speed):
global main_wordlist, main_wordlist_e
print "Getting wordlist set..."
#try:
main_wordlist = get_wordlist(speed, 1)
print "Check (1) - Passed"
main_wordlist_e = get_wordlist(speed, 0)
print "Check (2) - Passed"
return main_wordlist
"Check (*) - Passed" should be printed to the screen. However, All I am getting is "Getting wordlist set..." Any ideas as to what I'm doing wrong?
As sandinmyjoints says, if you are seeing
Getting wordlist set...
But not
Trying to get wordlist...
It looks like
database_get(num)
isn't returning. It could also be that the same function name is used for a different function elsewhere. It might be a good idea to put a print before the call to database_get
I want to process a string by matching it with a sequence of regular expression. As I'm trying to avoid nested if-then, I'm thinking of switch-case. How can I write the following structure in Python? Thank you
switch str:
case match(regex1):
# do something
case match(regex2):
# do sth else
I know Perl allows one to do that. Does Python?
First consider why there is no case statement in Python. So reset you brain and forget them.
You can use an object class, function decorators or use function dictionaries to achieve the same or better results.
Here is a quick trivial example:
#!/usr/bin/env python
import re
def hat(found):
if found: print "found a hat"
else: print "no hat"
def cat(found):
if found: print "found a cat"
else: print "no cat"
def dog(found):
if found: print "found a dog"
else: print "no dog"
st="""
Here is the target string
with a hat and a cat
no d o g
end
"""
patterns=['hat', 'cat', 'dog']
functions=[hat,cat,dog]
for pattern,case in zip(patterns,functions):
print "pattern=",pattern
case(re.search(pattern,st))
C style case / switch statements also "fall through, such as:
switch(c) {
case 'a':
case 'b':
case 'c': do_abc();
break;
... other cases...
}
Using tuples and lists of callables, you can get the similar behavior:
st="rat kitten snake puppy bug child"
def proc1(st): print "cuddle the %s" % st
def proc2(st): print "kill the %s" % st
def proc3(st): print "pick-up the %s" % st
def proc4(st): print "wear the %s" % st
def proc5(st): print "dispose of the %s" %st
def default(st): print "%s not found" % st
dproc={ ('puppy','kitten','child'):
[proc3, proc1],
('hat','gloves'):
[proc3, proc4],
('rat','snake','bug'):
[proc2, proc3, proc5]}
for patterns,cases in dproc.iteritems():
for pattern in patterns:
if re.search(pattern,st):
for case in cases: case(pattern)
else: default(pattern)
print
This gets the order for the found item correct: 1) pick up child, cuddle the child; 2) kill the rat, pick up the rat... It would be difficult to do the same with a C switch statement in an understandable syntax.
There are many other ways to imitate a C switch statement. Here is one (for integers) using function decorators:
case = {}
def switch_on(*values):
def case_func(f):
case.update((v, f) for v in values)
return f
return case_func
#switch_on(0, 3, 5)
def case_a(): print "case A"
#switch_on(1,2,4)
def case_b(): print "case B"
def default(): print "default"
for i in (0,2,3,5,22):
print "Case: %i" % i
try:
case[i]()
except KeyError:
default()
To paraphrase Larry Wall, Tom Christiansen, Jon Orwant in Programming Perl regarding understanding context in Perl:
You will be miserable programming Python until you use the idioms that are native to the language...
A quick search shows a similar question asked earlier with multiple work arounds. May favorite solution from that one is by Mizard
import re
class Re(object):
def __init__(self):
self.last_match = None
def match(self,pattern,text):
self.last_match = re.match(pattern,text)
return self.last_match
def search(self,pattern,text):
self.last_match = re.search(pattern,text)
return self.last_match
gre = Re()
if gre.match(r'foo',text):
# do something with gre.last_match
elif gre.match(r'bar',text):
# do something with gre.last_match
else:
# do something else
You are looking for pyswitch (disclaimer: I am the author). With it, you can do the following, which is pretty close to the example you gave in your question:
from pyswitch import Switch
mySwitch = Switch()
#myswitch.caseRegEx(regex1)
def doSomething(matchObj, *args, **kwargs):
# Do Something
return 1
#myswitch.caseRegEx(regex2)
def doSomethingElse(matchObj, *args, **kwargs):
# Do Something Else
return 2
rval = myswitch(stringYouWantToSwitchOn)
There's a much more comprehensive example given at the URL I linked. pyswitch is not restricted to just switching on regular expressions. Internally, pyswitch uses a dispatch system similar to the examples others have given above. I just got tired of having to re-write the same code framework over and over every time I needed that kind of dispatch system, so I wrote pyswitch.
Your question regarding Perl style switch statements is ambiguous. You reference Perl but you are using a C style switch statement in your example. (There is a deprecated module that provides C style switch statements in Perl, but this is not recommended...)
If you mean Perl given / when type switch statements, this would not be trivial to implement in Python. You would need to implement smart matching and other non-trivial Perl idioms. You might as well just write whatever in Perl?
If you mean C style switch statements, these are relatively trivial in comparison. Most recommend using a dictionary dispatch method, such as:
import re
def case_1():
print "case 1"
return 1
def case_2():
print "case 2"
return 2
def case_3():
print "case 3"
return 3
def default():
print "None"
return 0
dispatch= {
'a': case_1,
'g': case_2,
'some_other': case_3,
'default': default
}
str="abcdefg"
r=[dispatch[x]() if re.search(x,str) else dispatch['default']()
for x in ['a','g','z'] ]
print "r=",r
If you're avoiding if-then, you can build on something like this:
import re
# The patterns
r1 = "spam"
r2 = "eggs"
r3 = "fish"
def doSomething1():
return "Matched spam."
def doSomething2():
return "Matched eggs."
def doSomething3():
return "Matched fish."
def default():
return "No match."
def match(r, s):
mo = re.match(r, s)
try:
return mo.group()
except AttributeError:
return None
def delegate(s):
try:
action = {
match(r1, s): doSomething1,
match(r2, s): doSomething2,
match(r3, s): doSomething3,
}[s]()
return action
except KeyError:
return default()
Results
>>> delegate("CantBeFound")
0: 'No match.'
>>> delegate("spam")
1: 'Matched spam.'
>>> delegate("eggs")
2: 'Matched eggs.'
>>> delegate("fish")
3: 'Matched fish.'
I feel like I should know this, but I haven't been able to figure it out...
I want to get the name of a method--which happens to be an integration test--from inside it so it can print out some diagnostic text. I can, of course, just hard-code the method's name in the string, but I'd like to make the test a little more DRY if possible.
This seems to be the simplest way using module inspect:
import inspect
def somefunc(a,b,c):
print "My name is: %s" % inspect.stack()[0][3]
You could generalise this with:
def funcname():
return inspect.stack()[1][3]
def somefunc(a,b,c):
print "My name is: %s" % funcname()
Credit to Stefaan Lippens which was found via google.
The answers involving introspection via inspect and the like are reasonable. But there may be another option, depending on your situation:
If your integration test is written with the unittest module, then you could use self.id() within your TestCase.
This decorator makes the name of the method available inside the function by passing it as a keyword argument.
from functools import wraps
def pass_func_name(func):
"Name of decorated function will be passed as keyword arg _func_name"
#wraps(func)
def _pass_name(*args, **kwds):
kwds['_func_name'] = func.func_name
return func(*args, **kwds)
return _pass_name
You would use it this way:
#pass_func_name
def sum(a, b, _func_name):
print "running function %s" % _func_name
return a + b
print sum(2, 4)
But maybe you'd want to write what you want directly inside the decorator itself. Then the code is an example of a way to get the function name in a decorator. If you give more details about what you want to do in the function, that requires the name, maybe I can suggest something else.
# file "foo.py"
import sys
import os
def LINE( back = 0 ):
return sys._getframe( back + 1 ).f_lineno
def FILE( back = 0 ):
return sys._getframe( back + 1 ).f_code.co_filename
def FUNC( back = 0):
return sys._getframe( back + 1 ).f_code.co_name
def WHERE( back = 0 ):
frame = sys._getframe( back + 1 )
return "%s/%s %s()" % ( os.path.basename( frame.f_code.co_filename ),
frame.f_lineno, frame.f_code.co_name )
def testit():
print "Here in %s, file %s, line %s" % ( FUNC(), FILE(), LINE() )
print "WHERE says '%s'" % WHERE()
testit()
Output:
$ python foo.py
Here in testit, file foo.py, line 17
WHERE says 'foo.py/18 testit()'
Use "back = 1" to find info regarding two levels back down the stack, etc.
I think the traceback module might have what you're looking for. In particular, the extract_stack function looks like it will do the job.
To elaborate on #mhawke's answer:
Rather than
def funcname():
return inspect.stack()[1][3]
You can use
def funcname():
frame = inspect.currentframe().f_back
return inspect.getframeinfo(frame).function
Which, on my machine, is about 5x faster than the original version according to timeit.