Let me just start off by saying that I'm very new to programming, I'm pretty sure this is like my fourth time sitting down and learning stuff, so well, I'm not even sure the question sounds right.
So I watch beginner tutorials for Python by CS Dojo on YouTube, I'm on the third video, it's about functions. Watching tutorials I pause the video a lot and try to experiment a little bit to truly understand what I'm working with. So it went all good when I would play around with numbers. Like here:
def function(x):
return x+5
a = function(10)
print(a)
(Not sure if I pasted the code well, sorry)
But then I tried to do something with words to see if it could work:
def function(name):
return ("Hi ")
b = function(Oskar)
print(b)
And it doesn't, I get an error like this:
NameError: name 'Oskar' is not defined
Do these kind of codes only work with numbers? Or did I do something wrong? I wanna understand this so I'd like someone to explain it to me, considering that I'm a beginner and don't understand a lot of the words programmists use here.
Oskar is a variable. 'Oskar' and "Oskar" are strings (note the quotes).
In other words, any of the following will work:
b = function('Oskar')
b = function("Oskar")
my_name = 'Oskar'
b = function(my_name)
my_name = input('What is your name? ')
b = function(my_name)
(Along with an infinite number of other examples, of course.)
name = "oskar"
def function(name):
return ("Hi " + name)
b = function(name)
print(b)
Oskar is not a string, but undefined variable.
Oskar without quote is treated as an identifier not a string. Use "Oskar" or 'Oskar'
String always have to be encapsulated in a double("") or a single('') quote
def function(name):
return ("Hi " + name)
b = function("Oskar")
print(b)
Or use this one, in future it will come in real handy
def function(name):
return (f"Hi {name}")
b = function("Oskar")
print(b)
When you type Osakar python interpreter expects a variable which is not defined in your case.
Please note that Oskar is different from 'Oscar'. The first is a variable (that must be defined first). While the latter is a string.
Even if you use sting 'Oscar' you cannot use it with your function. Because the + does not work between a string and an integer.
Related
This question is similar to others asked on here, but after reading the answers I'm not grasping it and would appreciate further guidance.
While sketching new code I find myself adding a lot of statements like:
print('var=')
pprint(var)
It became tedious always writing that, so I thought I could make it into a function. Since I want to print the variable name on the preceding line, I tried:
def dbp(var):
eval('print(\'{0}=\')'.format(var))
eval('pprint({0})'.format(var))
so then I do do things like:
foo = 'bar'
dbp('foo')
which prints
foo=
'bar'
This is all great, but when I go to use it in a function things get messed up. For example, doing
def f():
a = ['123']
dbp('a')
f()
raises a NameError (NameError: name 'a' is not defined).
My expectation was that dbp() would have read access to anything in f()'s scope, but clearly it doesn't. Can someone explain why?
Also, better ways of printing a variable's name followed by its formatted contents are also appreciated.
You really should look at other ways to doing this.
The logging module is a really good habit to get into, and you can turn off and on debug output.
Python 3.6 has f'' strings so you would simplify this to:
pprint(f'var=\n{var}`)`
However, here's an example (not recommended) using locals():
In []:
def dbp(var, l):
print('{}='.format(var))
pprint(l[var])
def f():
a = 1
dbp('a', locals())
f()
Out[]:
a=
1
first of all, id like to say that eval is a high security risk for whoever is going to be running that code.
However, if you absolutely must, you can do this.
def dbp(var):
env = {'var': var}
# Adding global variables to the enviroment
env.update(globals())
eval("print('{0}=')".format(var))
eval('pprint(var)', env)
def f():
a = ['123']
dbp('a')
you can then do
>>> f()
a=
'a'
I have a class which has around a dozen object variables. Along with each variable, I want to provide a default value, a help string (for argparse) and a comment string (to write to a data file). I want to be able to instantiate objects by:
providing explicit values to the init method
providing values to use on the command line
taking the defaults
some combination of the above.
When I only had two object variables, I provided the defaults in the declaration of the init function, I replicated these and the help string when I created the argument parser, etc. But for many variables, it gets very messy.
The trimmed down example code below is my current solution, which I am fairly happy with, does exactly what I want, and works pretty well. But, I have two questions:
Is it pythonic?
Surely this must be a solved problem already, and there is a "standard" way to do it?
I did look around here, and Googled a bit, but I didn't manage to find an existing solution.
# invoke with python demoArgs.py -a 15 -b 25 -c text
import argparse
class Foo:
defaults = {'a':10,'b':20, 'c':"outFile"}
helpDefs = {'a' : 'the first parameter',
'b' : 'the second paramter',
'c' : 'the third paramter'}
#staticmethod
def parse_args():
parser = argparse.ArgumentParser()
for key in Foo.defaults:
parser.add_argument('-'+ key, help = Foo.helpDefs[key],
default = Foo.defaults[key])
return vars(parser.parse_args())
def __init__(self, a = defaults['a'], b = defaults['b'], c = defaults['c']):
self.a = a
self.b = b
self.c = c
def report(self):
for key in sorted(vars(self)):
print key, "val = ", getattr(self,key), \
", help = ", self.helpDefs[key], \
", def = ", self.defaults[key]
def main():
print "\n an object using all of the defaults"
a = Foo()
a.report()
print "\n an object using the command line values"
args = Foo.parse_args()
b = Foo(**args)
b.report()
print "\n an object using values specified in the code"
c = Foo(30,40,"object")
c.report()
print "\n an object using a perverse combination"
args = Foo.parse_args()
d = Foo(50, c = args['c'])
d.report()
if __name__ == '__main__':
main()
As for is it "pythonic" -- I'd say no. Argparse is already pretty powerful. Someone who wanted to use your library would have to carefully understand how it worked and how it wrapped something else (which would also require understanding the thing it wrapped). It's arguable whether the effort would be worth it. In the short run your probably better off just using argparse, rather than trying to simplify something which already does the job (IMHO).
As for question #2 -- I seriously doubt anyone else has tried to do it. Most people will usually just stick with the stdlib. It's simpler and is available on all platforms where python can run.
Of course neither of these answers should stop you from doing what you like.
For my examine command, because I don't want to do this:
def examine(Decision):
if Decision == "examine sword":
print sword.text
elif Decision == "examine gold":
print gold.text
elif Decision == "examine cake":
print cake.text
...
for every item in my game.
So I wanted to convert the second word of the Decision string into a variable so that I could use something like secondwordvar.text.
I tried to use eval(), but I always get an errors when I make a spelling mistake in a single word command.
The error
IndexError: list index out of range
It's be working otherwise though.
Right now my code is this:
def exam(Decision):
try:
examlist = shlex.split(Decision)
useditem = eval(examlist[1])
print useditem.text
except NameError:
print "This doesn't exist"
Does anyone have an idea, for an other option, how I could write that function in a easy way?
I should probably also include the full game. You can find it here:
http://pastebin.com/VVDSxQ0g
Somewhere in your program, create a dictionary mapping the name of the object to a variable that it represents. For example:
objects = {'sword': sword, 'gold': gold, 'cake': cake}
Then you can change your examine() function to something like the following:
def examine(Decision):
tokens = shlex.split(Decision)
if len(tokens) != 2 or tokens[0] != 'examine' or tokens[1] not in objects:
print "This doesn't exist"
else:
print objects[tokens[1]].text
What you could do (because with my knowledge in programming, somewhat limited, this is the most advanced way I could see it) is to utilize dictionaries. I'll try to explain in english, because my knowledge of code in this field is suspect and I don't want to mislead you.
Dictionaries are very array-like, allowing you to associate a decision with a value.
You would be able to associate Examine sword with an action code 4
This would (in a hack-y way) allow you to convert your string to a variable, more by direct and consistent referencing of key/value pairs.
Good luck with this approach; Read up some on Dictionaries and you may very well find them easier to handle than it sounds!
Finally, as a form of good coding practice, never use eval() unless you are sure of what you are doing. eval() executes the code inside the (), so if, god forbid, some malicious process manages to run that code with a malicious line injected inside it:
eval(###DELETE EVERYTHING RAWR###)
You'll have a bad time. Sincerely.
Also, for the sake of evaluating code, I've heard that it is a very slow command, and that there are better alternatives, performance-wise.
Happy coding!
These two print the same text:
Using a dictionary:
texts = dict(sword = "wathever",
gold = "eachever",
cake = "whomever")
def examine_dict(decision):
decision = decision.split()[1]
print texts[decision]
examine_dict("examine sword")
Using object attributes (a class):
class Texts():
sword = "wathever"
gold = "eachever"
cake = "whomever"
def examine_attribute(decision):
decision = decision.split()[1]
text = getattr(Texts, decision)
print text
examine_attribute("examine sword")
Depending on what you want, one method can be more appropriate than the other. The dictionary-based method, however, is in general, the easier and the faster one.
Your variables are stored in a dictionary somewhere. If they are global variables, globals() returns this dictionary. You can use this to look up the variable by name:
globals()['sword'].text
If the variables are stored in a class as attributes, you can use getattr:
getattr(object, 'sword').text
You'll want to catch possible exceptions for bad names.
[EDIT 00]: I've edited several times the post and now even the title, please read below.
I just learned about the format string method, and its use with dictionaries, like the ones provided by vars(), locals() and globals(), example:
name = 'Ismael'
print 'My name is {name}.'.format(**vars())
But I want to do:
name = 'Ismael'
print 'My name is {name}.' # Similar to ruby
So I came up with this:
def mprint(string='', dictionary=globals()):
print string.format(**dictionary)
You can interact with the code here:
http://labs.codecademy.com/BA0B/3#:workspace
Finally, what I would love to do is to have the function in another file, named my_print.py, so I could do:
from my_print import mprint
name= 'Ismael'
mprint('Hello! My name is {name}.')
But as it is right now, there is a problem with the scopes, how could I get the the main module namespace as a dictionary from inside the imported mprint function. (not the one from my_print.py)
I hope I made myself uderstood, if not, try importing the function from another module. (the traceback is in the link)
It's accessing the globals() dict from my_print.py, but of course the variable name is not defined in that scope, any ideas of how to accomplish this?
The function works if it's defined in the same module, but notice how I must use globals() because if not I would only get a dictionary with the values within mprint() scope.
I have tried using nonlocal and dot notation to access the main module variables, but I still can't figure it out.
[EDIT 01]: I think I've figured out a solution:
In my_print.py:
def mprint(string='',dictionary=None):
if dictionary is None:
import sys
caller = sys._getframe(1)
dictionary = caller.f_locals
print string.format(**dictionary)
In test.py:
from my_print import mprint
name = 'Ismael'
country = 'Mexico'
languages = ['English', 'Spanish']
mprint("Hello! My name is {name}, I'm from {country}\n"
"and I can speak {languages[1]} and {languages[0]}.")
It prints:
Hello! My name is Ismael, I'm from Mexico
and I can speak Spanish and English.
What do you think guys? That was a difficult one for me!
I like it, much more readable for me.
[EDIT 02]: I've made a module with an interpolate function, an Interpolate class and an attempt for a interpolate class method analogous to the function.
It has a small test suite and its documented!
I'm stuck with the method implementation, I don't get it.
Here's the code: http://pastebin.com/N2WubRSB
What do you think guys?
[EDIT 03]: Ok I have settled with just the interpolate() function for now.
In string_interpolation.py:
import sys
def get_scope(scope):
scope = scope.lower()
caller = sys._getframe(2)
options = ['l', 'local', 'g', 'global']
if scope not in options[:2]:
if scope in options[2:]:
return caller.f_globals
else:
raise ValueError('invalid mode: {0}'.format(scope))
return caller.f_locals
def interpolate(format_string=str(),sequence=None,scope='local',returns=False):
if type(sequence) is str:
scope = sequence
sequence = get_scope(scope)
else:
if not sequence:
sequence = get_scope(scope)
format = 'format_string.format(**sequence)'
if returns is False:
print eval(format)
elif returns is True:
return eval(format)
Thanks again guys! Any opinions?
[EDIT 04]:
This is my last version, it has a test, docstrings and describes some limitations I've found:
http://pastebin.com/ssqbbs57
You can quickly test the code here:
http://labs.codecademy.com/BBMF#:workspace
And clone grom git repo here:
https://github.com/Ismael-VC/python_string_interpolation.git
Modules don't share namespaces in python, so globals() for my_print is always going to be the globals() of my_print.py file ; i.e the location where the function was actually defined.
def mprint(string='', dic = None):
dictionary = dic if dic is not None else globals()
print string.format(**dictionary)
You should pass the current module's globals() explicitly to make it work.
Ans don't use mutable objects as default values in python functions, it can result in unexpected results. Use None as default value instead.
A simple example for understanding scopes in modules:
file : my_print.py
x = 10
def func():
global x
x += 1
print x
file : main.py
from my_print import *
x = 50
func() #prints 11 because for func() global scope is still
#the global scope of my_print file
print x #prints 50
Part of your problem - well, the reason its not working - is highlighted in this question.
You can have your function work by passing in globals() as your second argument, mprint('Hello my name is {name}',globals()).
Although it may be convenient in Ruby, I would encourage you not to write Ruby in Python if you want to make the most out of the language.
Language Design Is Not Just Solving Puzzles: ;)
http://www.artima.com/forums/flat.jsp?forum=106&thread=147358
Edit: PEP-0498 solves this issue!
The Template class from the string module, also does what I need (but more similar to the string format method), in the end it also has the readability I seek, it also has the recommended explicitness, it's in the Standard Library and it can also be easily customized and extended.
http://docs.python.org/2/library/string.html?highlight=template#string.Template
from string import Template
name = 'Renata'
place = 'hospital'
job = 'Dr.'
how = 'glad'
header = '\nTo Ms. {name}:'
letter = Template("""
Hello Ms. $name.
I'm glad to inform, you've been
accepted in our $place, and $job Red
will ${how}ly recieve you tomorrow morning.
""")
print header.format(**vars())
print letter.substitute(vars())
The funny thing is that now I'm getting more fond of using {} instead of $ and I still like the string_interpolation module I came up with, because it's less typing than either one in the long run. LOL!
Run the code here:
http://labs.codecademy.com/BE3n/3#:workspace
I want a function that can return the variable/object name as str like this :
def get_variable_name (input_variable):
## some codes
>>get_variable_name(a)
'a'
>>get_variable_name(mylist)
'mylist'
it looks like silly but i need the function to construct expression regarding to the variable for later on 'exec()'. Can someone help on how to write the 'get_variable_name' ?
I've seen a few variants on this kind of question several times on SO now. The answer is don't. Learn to use a dict anytime you need association between names and objects. You will thank yourself for this later.
In answer to the question "How can my code discover the name of an object?", here's a quote from Fredrik Lundh (on comp.lang.python):
The same way as you get the name of that cat you found on your porch:
the cat (object) itself cannot tell you its name, and it doesn’t
really care — so the only way to find out what it’s called is to ask
all your neighbours (namespaces) if it’s their cat (object)…
….and don’t be surprised if you’ll find that it’s known by many names,
or no name at all!
Note: It is technically possible to get a list of the names which are bound to an object, at least in CPython implementation. If you're interested to see that demonstrated, see the usage of the inspect module shown in my answer here:
Can an object inspect the name of the variable it's been assigned to?
This technique should only be used in some crazy debugging session, don't use anything like this in your design.
In general it is not possible. When you pass something to a function, you are passing the object, not the name. The same object can have many names or no names. What is the function supposed to do if you call get_variable_name(37)? You should think about why you want to do this, and try to find another way to accomplish your real task.
Edit: If you want get_variable_name(37) to return 37, then if you do a=37 and then do get_variable_name(a), that will also return 37. Once inside the function, it has no way of knowing what the object's "name" was outside.
def getvariablename(vara):
for k in globals():
if globals()[k] == vara:
return k
return str(vara)
may work in some instance ...but very subject to breakage... and I would basically never use it in any kind of production code...
basically I cant think of any good reason to do this ... and about a million not to
Here's a good start, depending on the Python version and runtime you might have to tweak a little. Put a break point and spend sometime to understand the structure of inspect.currentframe()
import inspect
def vprint(v):
v_name = inspect.currentframe().f_back.f_code.co_names[3]
print(f"{v_name} ==> {v}")
if __name__ == '__main__':
x = 15
vprint(x)
will produce
x ==> 15
if you just want to return the name of a variable selected based on user input... so they can keep track of their input, add a variable name in the code as they make selections in addition to the values generated from their selections. for example:
temp = raw_input('Do you want a hot drink? Type yes or no. ')
size = raw_input('Do you want a large drink? Type yes or no. ')
if temp and size == 'yes':
drink = HL
name = 'Large cafe au lait'
if temp and size != 'yes':
drink = CS
name = 'Small ice coffee'
print 'You ordered a ', name, '.'
MJ
If your statement to be used in exec() is something like this
a = ["ddd","dfd","444"]
then do something like this
exec('b = a = ["ddd","dfd","444"]')
now you can use 'b' in your code to get a handle on 'a'.
Perhaps you can use traceback.extract_stack() to get the call stack, then extract the variable name(s) from the entry?
def getVarName(a):
stack = extract_stack()
print(stack.pop(-2)[3])
bob = 5
getVarName(bob);
Output:
getVarName(bob)