function argument as an input for f-string to change variables - python

def cleaning(input):
name = str(input)
read_file = pd.read_csv('#f"{name}".csv')
print(read_file)
cleaning(InputKeyword)
My function must take an input keyword, and this will change the "name" to "#input" word.
I was trying with f-strigs, but it doesn't work. Any ideas or referrals where can I find the solution?
Thanks in advance:)

read_file = pd.read_csv('#f"{name}".csv')
That's not actually an f-string, it's a normal string that has an f, some quotes, and some braces inside it. An f-string must be prefixed with (surprisingly enough) an f :-)
I suggest you try something like:
read_file = pd.read_csv(f"#{name}.csv")
If the name string holds xyzzy, this will try to process the file #xyzzy.csv.
Additionally, it's a very bad idea to use built-in functions as variable names. The input function is one such example. The following (complete) snippet solves both those issues:
# Assumes file_base is a string, see below.
def cleaning(file_base):
read_file = pd.read_csv(f"#{file_base}.csv")
print(read_file)
cleaning("someString")
Note that you can put arbitrary expressions inside f-strings, not just variable names. Hence there's no need to create name as a separate (named) object, you could just insert str(file_base) inside the braces.
However, for your particular case, I don't think the use of str(file_base} is necessary since it appears from tour comments that file_base is already a string, and I believe the formatting for a string without a format_spec is just the string itself(a).
This is why I have f"#{file_base}.csv" in the code above without a str() around the file_base variable.
(a) For objects in general, an {object} snippet inside an f-string will call the object's __format__() method, passing in the format_spec used. Hence f"{something:314159} would use the object method call something.__format__("314159") to format the object into a string.

Related

How can I use user input to choose a parameter name and an attribute name?

I'm using a library called unit-convert. The interface looks like this:
# Bytes to terabytes
>>> UnitConvert(b=19849347813875).tb
Suppose I have strings taken from user input (omitting the input code) like so:
input_value_unit = 'b'
output_value_unit = 'tb'
How can I substitute these into the call?
I tried using UnitConvert(input_value_unit=user_input_value).output_value_unit, but this doesn't use the string values.
Code like function(x=1) doesn't care if there's a variable named x naming a string; the x literally means x, not the x variable. Similarly for attributes: x.y doesn't care if there is a y variable naming a string; it will just get the y attribute of x.
However, we can use strings to specify both of these things "dynamically".
To replace the b in the example, we need to use a string as a keyword argument name. We can do this by making a dictionary for the keyword arguments, and then using ** to pass them. With a literal string, that looks like: UnitConvert(**{'b': ...}).
To replace the tb, we need to use a string as an attribute name. We can do this by using the built-in getattr to look up an attribute name dynamically. With a literal string, that looks like: getattr(UnitConvert(...), 'tb').
These transformations let us use a literal string instead of an identifier name.
Putting it together:
# suppose we have read these from user input:
input_value_unit = 'b'
output_value_unit = 'tb'
input_amount = 19849347813875
# then we use them with the library:
getattr(UnitConvert(**{input_value_unit: input_amount}), output_value_unit)
Edit again - perhaps I still misunderstand. You're using an existing module that you downloaded?
Now that your code has been pared back to look nothing like the original, my first answer no longer applies. I'll leave it below the underline because you should still be aware.
Usually in your situation the second unit would be passed as a second parameter to the function. Then the function can do the appropriate conversion.
UnitConvert(user_input_value, output_value_unit)
There's an alternative that looks a little closer to what you had in mind. If your function returns a dictionary with all the possible conversions, you can select the one you need.
UnitConvert(user_input_value)[output_value_unit]
The old irrelevant answer. Your statement:
if user_input_convert == ["kilometres", "miles", "nanometres", "metres"]:
is comparing a single string to a list of strings. They will never be equal. What you probably want is:
if user_input_convert in ["kilometres", "miles", "nanometres", "metres"]:
That checks to see if your string is equal to one of the strings in the list.

Convert function arguments to str

I wrote a function and call it as below:
from lib import base_frequency
base_frequency("AB610939-AB610950.gb", "genbank")
#This calls the function that uses a BioPython code.
How could I pass the function arguments as below?
base_frequency(AB610939-AB610950.gb, genbank)
Note that quotes are missing. Should I do this? Is there a recommended nomenclature in Python when function argument is sting?
I thought this required me to convert filename and record format to a string inside the function. That is:
AB610939-AB610950.gb to "AB610939-AB610950.gb"
genbank to "genbank"
I have tried str(AB610939-AB610950.gb) inside the function but it did not do the job.
There is no way to do this without quotes, or else Python will interpret it as an expression. Take the first argument for example,
AB610939-AB610950.gb
Python will read this as a subtraction operation between two variables, AB610939 and the gb property of AB610950, not a sequence of characters. The only way to stop this is to surround it in quotation marks to make it string literal.
Is there a recommended nomenclature in Python when function argument is string?
Yes.
Enclose a string literal "within quotes".
Here is a pair of valid examples of doing that:
base_frequency("AB610939-AB610950.gb", "genbank")
That produces a pair of str values,
pushes them onto the stack,
and calls the base_frequency function.
If e.g. the 2nd arg was an unquoted genbank,
that would mean something entirely different.
It would mean "please look up the value of
the variable named genbank and pass its
value to the function."
If you ask for a variable that does not exist,
the result will be a NameError.

Is it possible to use format() function with a string in format's place?

I'm using a format() in python and I want to use a variable pokablelio so that the person could choose how many numbers to output after the dot. When I try to put the variable alone after the comma it outputs: ValueError: Invalid format specifier. I tried replacing some characters or making the whole string in a parentheses but that didn't work.
Right now I'm wondering: Can I even use a variable as a string to put it in format's place?
(note: The machine should have a "'.10f'" string in the variable)
Error and the code
It is possible to use variables as part of the format specifier, just include them inside additional curly braces:
>>> n_places = 10
>>> f'{1.23:.{n_places}f}'
'1.2300000000'

Passing a variable as a column name through pyspark Expr [duplicate]

I would like to put an int into a string. This is what I am doing at the moment:
num = 40
plot.savefig('hanning40.pdf') #problem line
I have to run the program for several different numbers, so I'd like to do a loop. But inserting the variable like this doesn't work:
plot.savefig('hanning', num, '.pdf')
How do I insert a variable into a Python string?
See also
If you tried using + to concatenate a number with a string (or between strings, etc.) and got an error message, see How can I concatenate str and int objects?.
If you are trying to assemble a URL with variable data, do not use ordinary string formatting, because it is error-prone and more difficult than necessary. Specialized tools are available. See Add params to given URL in Python.
If you are trying to assemble a SQL query, do not use ordinary string formatting, because it is a major security risk. This is the cause of "SQL injection" which costs real companies huge amounts of money every year. See for example Python: best practice and securest way to connect to MySQL and execute queries for proper techniques.
If you just want to print (output) the string, you can prepare it this way first, or if you don't need the string for anything else, print each piece of the output individually using a single call to print. See How can I print multiple things (fixed text and/or variable values) on the same line, all at once? for details on both approaches.
Using f-strings:
plot.savefig(f'hanning{num}.pdf')
This was added in 3.6 and is the new preferred way.
Using str.format():
plot.savefig('hanning{0}.pdf'.format(num))
String concatenation:
plot.savefig('hanning' + str(num) + '.pdf')
Conversion Specifier:
plot.savefig('hanning%s.pdf' % num)
Using local variable names (neat trick):
plot.savefig('hanning%(num)s.pdf' % locals())
Using string.Template:
plot.savefig(string.Template('hanning${num}.pdf').substitute(locals()))
See also:
Fancier Output Formatting - The Python Tutorial
Python 3's f-Strings: An Improved String Formatting Syntax (Guide) - RealPython
With the introduction of formatted string literals ("f-strings" for short) in Python 3.6, it is now possible to write this with a briefer syntax:
>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
With the example given in the question, it would look like this
plot.savefig(f'hanning{num}.pdf')
plot.savefig('hanning(%d).pdf' % num)
The % operator, when following a string, allows you to insert values into that string via format codes (the %d in this case). For more details, see the Python documentation:
printf-style String Formatting
You can use + as the normal string concatenation function as well as str().
"hello " + str(10) + " world" == "hello 10 world"
In general, you can create strings using:
stringExample = "someString " + str(someNumber)
print(stringExample)
plot.savefig(stringExample)
If you would want to put multiple values into the string you could make use of format
nums = [1,2,3]
plot.savefig('hanning{0}{1}{2}.pdf'.format(*nums))
Would result in the string hanning123.pdf. This can be done with any array.
Special cases
Depending on why variable data is being used with strings, the general-purpose approaches may not be appropriate.
If you need to prepare an SQL query
Do not use any of the usual techniques for assembling a string. Instead, use your SQL library's functionality for parameterized queries.
A query is code, so it should not be thought about like normal text. Using the library will make sure that any inserted text is properly escaped. If any part of the query could possibly come from outside the program in any way, that is an opportunity for a malevolent user to perform SQL injection. This is widely considered one of the important computer security problems, costing real companies huge amounts of money every year and causing problems for countless customers. Even if you think you know the data is "safe", there is no real upside to using any other approach.
The syntax will depend on the library you are using and is outside the scope of this answer.
If you need to prepare a URL query string
See Add params to given URL in Python. Do not do it yourself; there is no practical reason to make your life harder.
Writing to a file
While it's possible to prepare a string ahead of time, it may be simpler and more memory efficient to just write each piece of data with a separate .write call. Of course, non-strings will still need to be converted to string before writing, which may complicate the code. There is not a one-size-fits-all answer here, but choosing badly will generally not matter very much.
If you are simply calling print
The built-in print function accepts a variable number of arguments, and can take in any object and stringify it using str. Before trying string formatting, consider whether simply passing multiple arguments will do what you want. (You can also use the sep keyword argument to control spacing between the arguments.)
# display a filename, as an example
print('hanning', num, '.pdf', sep='')
Of course, there may be other reasons why it is useful for the program to assemble a string; so by all means do so where appropriate.
It's important to note that print is a special case. The only functions that work this way are ones that are explicitly written to work this way. For ordinary functions and methods, like input, or the savefig method of Matplotlib plots, we need to prepare a string ourselves.
Concatenation
Python supports using + between two strings, but not between strings and other types. To work around this, we need to convert other values to string explicitly: 'hanning' + str(num) + '.pdf'.
Template-based approaches
Most ways to solve the problem involve having some kind of "template" string that includes "placeholders" that show where information should be added, and then using some function or method to add the missing information.
f-strings
This is the recommended approach when possible. It looks like f'hanning{num}.pdf'. The names of variables to insert appear directly in the string. It is important to note that there is not actually such a thing as an "f-string"; it's not a separate type. Instead, Python will translate the code ahead of time:
>>> def example(num):
... return f'hanning{num}.pdf'
...
>>> import dis
>>> dis.dis(example)
2 0 LOAD_CONST 1 ('hanning')
2 LOAD_FAST 0 (num)
4 FORMAT_VALUE 0
6 LOAD_CONST 2 ('.pdf')
8 BUILD_STRING 3
10 RETURN_VALUE
Because it's a special syntax, it can access opcodes that aren't used in other approaches.
str.format
This is the recommended approach when f-strings aren't possible - mainly, because the template string needs to be prepared ahead of time and filled in later. It looks like 'hanning{}.pdf'.format(num), or 'hanning{num}.pdf'.format(num=num)'. Here, format is a method built in to strings, which can accept arguments either by position or keyword.
Particularly for str.format, it's useful to know that the built-in locals, globals and vars functions return dictionaries that map variable names to the contents of those variables. Thus, rather than something like '{a}{b}{c}'.format(a=a, b=b, c=c), we can use something like '{a}{b}{c}'.format(**locals()), unpacking the locals() dict.
str.format_map
This is a rare variation on .format. It looks like 'hanning{num}.pdf'.format_map({'num': num}). Rather than accepting keyword arguments, it accepts a single argument which is a mapping.
That probably doesn't sound very useful - after all, rather than 'hanning{num}.pdf'.format_map(my_dict), we could just as easily write 'hanning{num}.pdf'.format(**my_dict). However, this is useful for mappings that determine values on the fly, rather than ordinary dicts. In these cases, unpacking with ** might not work, because the set of keys might not be determined ahead of time; and trying to unpack keys based on the template is unwieldy (imagine: 'hanning{num}.pdf'.format(num=my_mapping[num]), with a separate argument for each placeholder).
string.Formatter
The string standard library module contains a rarely used Formatter class. Using it looks like string.Formatter().format('hanning{num}.pdf', num=num). The template string uses the same syntax again. This is obviously clunkier than just calling .format on the string; the motivation is to allow users to subclass Formatter to define a different syntax for the template string.
All of the above approaches use a common "formatting language" (although string.Formatter allows changing it); there are many other things that can be put inside the {}. Explaining how it works is beyond the scope of this answer; please consult the documentation. Do keep in mind that literal { and } characters need to be escaped by doubling them up. The syntax is presumably inspired by C#.
The % operator
This is a legacy way to solve the problem, inspired by C and C++. It has been discouraged for a long time, but is still supported. It looks like 'hanning%s.pdf' % num, for simple cases. As you'd expect, literal '%' symbols in the template need to be doubled up to escape them.
It has some issues:
It seems like the conversion specifier (the letter after the %) should match the type of whatever is being interpolated, but that's not actually the case. Instead, the value is converted to the specified type, and then to string from there. This isn't normally necessary; converting directly to string works most of the time, and converting to other types first doesn't help most of the rest of the time. So 's' is almost always used (unless you want the repr of the value, using 'r'). Despite that, the conversion specifier is a mandatory part of the syntax.
Tuples are handled specially: passing a tuple on the right-hand side is the way to provide multiple arguments. This is an ugly special case that's necessary because we aren't using function-call syntax. As a result, if you actually want to format a tuple into a single placeholder, it must be wrapped in a 1-tuple.
Other sequence types are not handled specially, and the different behaviour can be a gotcha.
string.Template
The string standard library module contains a rarely used Template class. Instances provide substitute and safe_substitute methods that work similarly to the built-in .format (safe_substitute will leave placeholders intact rather than raising an exception when the arguments don't match). This should also be considered a legacy approach to the problem.
It looks like string.Template('hanning$num.pdf').substitute(num=num), and is inspired by traditional Perl syntax. It's obviously clunkier than the .format approach, since a separate class has to be used before the method is available. Braces ({}) can be used optionally around the name of the variable, to avoid ambiguity. Similarly to the other methods, literal '$' in the template needs to be doubled up for escaping.
I had a need for an extended version of this: instead of embedding a single number in a string, I needed to generate a series of file names of the form 'file1.pdf', 'file2.pdf' etc. This is how it worked:
['file' + str(i) + '.pdf' for i in range(1,4)]
You can make dict and substitute variables in your string.
var = {"name": "Abdul Jalil", "age": 22}
temp_string = "My name is %(name)s. I am %(age)s years old." % var

Why no ' is needed in string.format() dictionary reference?

my_dic={"Vajk":"vékony","Bibi":'magas'}
my_dic['Bibi']
'magas'
We can see, that we need the ' to refer to the value for key 'Bibi'. But if want to use the same format in .format(), it gives this error:
print("úgy érzem, hogy Bibi nagyon {0['Bibi']}".format(my_dic))
Traceback (most recent call last):
File "<ipython-input-109-52760dad9136>", line 1, in <module>
print("úgy érzem, hogy Bibi nagyon {0['Bibi']}".format(my_dic))
KeyError: "'Bibi'"
I have to use the reference without ', then it works.
print("úgy érzem, hogy Bibi nagyon {0[Bibi]}".format(my_dic))
úgy érzem, hogy Bibi nagyon magas
Why doesn't the first work, and why does the second? It should be the opposite, first should work, and second shouldn't.
First, some terminology:
'Bibi' is a string literal, syntax to create a string value. Your keys are strings, and using a string literal you can specify one of those keys.
You could use a variable instead; assign as string value to a variable and use the variable to get an item from your dictionary:
foo = 'Bibi' # or read this from a file, or from a network connection
print(my_dic[foo]) # -> magas
In string formatting, the {...} are replacement fields. The str.format() method provides values for the replacement fields.
The 0[Bidi] part in the {...} replacement field syntax is the field name. When you use [...] in a field name, it is a compound field name (there are multiple parts). The [...] syntax is usually referred to as indexing.
The format used in field names is deliberately kept simple, and is only Python-like. The syntax is simplified to limit what it can be used for, to constrain the functionality to something that is usually safe to use.
As such, if you use a compound name with getitem [...] indexing syntax, names are treated as strings, but you don't use quotes to create the string. You could not pass in a variable name anyway, there is no need to contrast between 'name' (a string) and name (a variable).
In other words, in a Python expression, my_dic[foo] works by looking up the value of the variable foo, and that is a different concept from using a string literal like my_dic['Bidi']. But you can't use variables in a field name, in a str.format() operation, using {0[foo]} should never find the variable foo.
The original proposal to add the feature explains this as:
Unlike some other programming languages, you cannot embed arbitrary expressions in format strings. This is by design - the types of expressions that you can use is deliberately limited. Only two operators are supported: the '.' (getattr) operator, and the '[]' (getitem) operator. The reason for allowing these operators is that they don't normally have side effects in non-pathological code.
and
It should be noted that the use of 'getitem' within a format string is much more limited than its conventional usage. In the above example, the string 'name' really is the literal string 'name', not a variable named 'name'. The rules for parsing an item key are very simple. If it starts with a digit, then it is treated as a number, otherwise it is used as a string.
Keeping the syntax simple makes templates more secure. From the Security Considerations section:
Barring that, the next best approach is to ensure that string formatting has no side effects. Because of the open nature of Python, it is impossible to guarantee that any non-trivial operation has this property. What this PEP does is limit the types of expressions in format strings to those in which visible side effects are both rare and strongly discouraged by the culture of Python developers.
Permitting {0[foo]} to look up variables in the current scope could easily produce side effects, while treating foo as a string instead means you can know, with certainty, that it'll always be the string 'foo' and not something else.
If you are only using string literals and not dynamic values (so 'some {} template'.format(...) and not some_variable.format(...), and you are using Python 3.6 or newer, you can use formatted string literals instead, as you can then use full Python expressions:
print(f"úgy érzem, hogy Bibi nagyon {my_dic['Bibi']}")
In an f string, you use actual Python expressions instead of field names, so you use quotes again to pass in a string literal. Because they are string literals, they are evaluated right where they are defined, and you as a developer can see what local variables are available, so presumably you know how to keep that secure.
It should be the opposite, first should work, and second shouldn't.
No, it shouldn't because 'Bibi' inside a double quoted string is a quoted string not just Bibi. You can check this simply as following:
In [51]: "'Bibi'" == "Bibi"
Out[51]: False
If in first case the key was "'Bibi'" Then it'd worked perfectly:
In [49]: my_dic={"Vajk":"vékony","'Bibi'":'magas'}
In [50]: print("úgy érzem, hogy Bibi nagyon {0['Bibi']}".format(my_dic))
úgy érzem, hogy Bibi nagyon magas
The reason that why it doesn't accept "Bibi" in first case and doesn't give you a the expected result is that Python looks for everything between brackets in dictionary and in this case you have "'Bibi'" inside the brackets not 'Bibi'.

Categories

Resources