Hi everyone and thanks to help me.
I have a function called factorial like this:
def fact(n):
if n == 0:
return 1
else:
return n * fact(n-1)
How i transform this function in a character like '!'?
for example:
>> fact(3)
6
>> 3!
6
use fact function when i put a number before '!', thanks for all!
Python allows you to define new meanings for two kinds of things:
names: sequences of characters starting with a letter or _ followed by any number of characters belonging to the 3 categories (digits, letters, digits).
existing operators, including but not limited to +, -, *, [], ==, in etc.
In order to define factorial as a trailing exclamation mark, as you desire, ! would have to be an existing postfix operator in Python. This is not the case.
The summary of all of that is: what you want cannot be done in Python.
considering "3!" is a string, you can always manipulate it. I'd recommend using a more sophisticated system, to check if the input is legit etc.
def fact(n):
return fact_number(int(n[:-1]))
def fact_number(n):
if n == 0:
return 1
else:
return n * fact_number(n-1)
print(fact("3!"))
output:
6
You can't do that in python, as suggested by #sheldonzy, you could parse a string somehow to give mathematical meaning to the ! operator.
When it comes to python operator overriding, these are the ones python provides you and you can override. So for instance, you could have your own int class and using the unary invert operator ~, like this:
class DontUseMe(int):
def __new__(cls, a, *args, **kwargs):
return super().__new__(cls, a)
def __invert__(self):
x = 1
for v in list(range(2, self + 1)):
x = x * v
return x
for i in range(10):
print(~DontUseMe(i))
In any case, I don't suggest overriding the builtin types for something like this, better continue using the method fact or parsing strings as mathematical expressions.
I recommend you to take a look at sympy, it's really handy to make mathematical operations on python.
Related
I am trying to find occurrence of letter 'b' and 'B'. the code that I have written works perfectly. Is there a better way that i can do this.
My code:
def count_letter_b(string):
#TODO: Your code goes here
a = int(string.count('B'))
b = int(string.count('b'))
return a + b
print count_letter_b("Bubble Bungle")
You can turn the string to uppercase (or lowercase), then count the occurrences:
string.upper().count('B')
So, overall, your code will look like this:
def count_letter_b(string):
return string.upper().count('B')
Note: no need to cast to int(..) as the result of str.count is already an int
Well if you only want to apply the same computation to a varying amount of letters you may want them to be arguments (count_letter(s, letters)), but anyway, here is a more functional example:
def count_letter_b(string):
return sum(map(string.count, 'Bb'))
This uses the str.count version that is bound to your input string instance.
Note that you're shadowing the name string if you use it as a parameter name.
You could do
# count in upper string, upper character
def countInvariantChars(c,s):
return s.upper().count(c.upper())
# list comprehensions + length
def countInvariantChars2(c,s):
return len([x for x in s if c.upper() == x.upper()])
# sum ones of list comprehension
def countInvariantChars3(c,s):
return sum([1 for x in s if c.upper() == x.upper()])
print(countInvariantChars("b","Bubble Bungle"))
print(countInvariantChars2("b","Bubble Bungle"))
print(countInvariantChars3("b","Bubble Bungle"))
Output (pyfiddle.io):
read-only#bash: 4
4
4
Use this:
def count_letter_b(string):
return string.lower().count('b')
print(count_letter_b(string))
Currently I'm experimenting a little bit with recursive functions in Python. I've read some things on the internet about them and I also built some simple functioning recursive functions myself. Although, I'm still not sure how to use the base case.
I know that a well-designed recursive function satisfies the following rules:
There is a base case.
The recursive steps work towards the base case.
The solutions of the subproblems provide a solution for the original problem.
Now I want to come down to the question that I have: Is it allowed to make up a base case from multiple statements?
In other words is the base case of the following self written script, valid?
def checkstring(n, string):
if len(string) == 1:
if string == n:
return 1
else:
return 0
if string[-1:] == n:
return 1 + checkstring(n, string[0:len(string) - 1])
else:
return checkstring(n, string[0:len(string) - 1])
print(checkstring('l', 'hello'))
Yes, of course it is: the only requirement on the base case is that it does not call the function recursively. Apart from that it can do anything it wants.
That is absolutely fine and valid function. Just remember that for any scenario that you can call a recursion function from, there should be a base case reachable by recursion flow.
For example, take a look at the following (stupid) recursive function:
def f(n):
if n == 0:
return True
return f(n - 2)
This function will never reach its base case (n == 0) if it was called for odd number, like 5. You want to avoid scenarios like that and think about all possible base cases the function can get to (in the example above, that would be 0 and 1). So you would do something like
def f(n):
if n == 0:
return True
if n == 1:
return False
if n < 0:
return f(-n)
return f(n - 2)
Now, that is correct function (with several ifs that checks if number is even).
Also note that your function will be quite slow. The reason for it is that Python string slices are slow and work for O(n) where n is length of sliced string. Thus, it is recommended to try non-recursive solution so that you can not re-slice string each time.
Also note that sometimes the function do not have strictly base case. For example, consider following brute-force function that prints all existing combinations of 4 digits:
def brute_force(a, current_digit):
if current_digit == 4:
# This means that we already chosen all 4 digits and
# we can just print the result
print a
else:
# Try to put each digit on the current_digit place and launch
# recursively
for i in range(10):
a[current_digit] = i
brute_force(a, current_digit + 1)
a = [0] * 4
brute_force(a, 0)
Here, because function does not return anything but just considers different options, we do not have a base case.
In simple terms Yes, as long as it does not require the need to call the function recursively to arrive at the base case. Everything else is allowed.
Coming from the C/C++ world and being a Python newb, I wrote this simple string function that takes an input string (guaranteed to be ASCII) and returns the last four characters. If there’s less than four characters, I want to fill the leading positions with the letter ‘A'. (this was not an exercise, but a valuable part of another complex function)
There are dozens of methods of doing this, from brute force, to simple, to elegant. My approach below, while functional, didn’t seem "Pythonic".
NOTE: I’m presently using Python 2.6 — and performance is NOT an issue. The input strings are short (2-8 characters), and I call this function only a few thousand times.
def copyFourTrailingChars(src_str):
four_char_array = bytearray("AAAA")
xfrPos = 4
for x in src_str[::-1]:
xfrPos -= 1
four_char_array[xfrPos] = x
if xfrPos == 0:
break
return str(four_char_array)
input_str = "7654321"
print("The output of {0} is {1}".format(input_str, copyFourTrailingChars(input_str)))
input_str = "21"
print("The output of {0} is {1}".format(input_str, copyFourTrailingChars(input_str)))
The output is:
The output of 7654321 is 4321
The output of 21 is AA21
Suggestions from Pythoneers?
I would use simple slicing and then str.rjust() to right justify the result using A as fillchar . Example -
def copy_four(s):
return s[-4:].rjust(4,'A')
Demo -
>>> copy_four('21')
'AA21'
>>> copy_four('1233423')
'3423'
You can simple adding four sentinel 'A' character before the original string, then take the ending four characters:
def copy_four(s):
return ('AAAA'+s)[-4:]
That's simple enough!
How about something with string formatting?
def copy_four(s):
return '{}{}{}{}'.format(*('A'*(4-len(s[-4:])) + s[-4:]))
Result:
>>> copy_four('abcde')
'bcde'
>>> copy_four('abc')
'Aabc'
Here's a nicer, more canonical option:
def copy_four(s):
return '{:A>4}'.format(s[-4:])
Result:
>>> copy_four('abcde')
'bcde'
>>> copy_four('abc')
'Aabc'
You could use slicing to get the last 4 characters, then string repetition (* operator) and concatenation (+ operator) as below:
def trailing_four(s):
s = s[-4:]
s = 'A' * (4 - len(s)) + s
return s
You can try this
def copy_four_trailing_chars(input_string)
list_a = ['A','A','A','A']
str1 = input_string[:-4]
if len(str1) < 4:
str1 = "%s%s" % (''.join(list_a[:4-len(str1)]), str1)
return str1
I have a task where I need to convert equations in one language (MATLAB) to another (C++) using Python. Everything is straightforward except the power operation. The equations are represented by Python strings.
For example, I want to convert
Eq = ((a+b)^2 + (c+d)^(1/2)) * e
to,
Eq = (pow((a+b),2) + pow(c+d, 1/2)) * e
I tried regular expression, but it does not seem to work because of nested parenthesis. Is there any good way to do this?
The best way to solve this would be to use Abstract Syntax Tree of Python. We can get that using ast module.
import ast, _ast
ops = {_ast.Mult: "*", _ast.Add: "+", _ast.BitXor: "pow", _ast.Div: "/"}
def rec(n):
if isinstance(n, _ast.Expr):
return rec(n.value)
elif isinstance(n, _ast.BinOp):
if isinstance(n.op, _ast.BitXor):
return "{}({}, {})".format(ops[type(n.op)], rec(n.left),rec(n.right))
else:
return "({} {} {})".format(rec(n.left), ops[type(n.op)],rec(n.right))
elif isinstance(n, _ast.Name):
return n.id
elif isinstance(n, _ast.Num):
return n.n
print rec(ast.parse("(((a+b)^2) + ((c+d)^(1/2))) * e").body[0])
# ((pow((a + b), 2) + pow((c + d), (1 / 2))) * e)
Note: Since ^ means Binary XOR operation in Python, you need to enclose that expression with an extra parenthesis, like I have shown in the example.
First, we check if it is an expression, then we process its value. If it is a binary operation, we check of it is Bitwise XOR, in that case we return the result in a different format, otherwise we return the result like left op right. If the current item looks like a name, then we return its id or if it is a number we return the attribute n.
You can do it as follows. Note: This is still a very primitive approach and I'd be careful about relying on it 100%:
import re
s = "Eq = ((a+b)^2 + (c+d)^(1/2)) * e"
>>> print re.sub(r'\(([^()\s]*)\)\^\(?([^()\s]*)\)?', 'pow(\\1,\\2)', s)
Eq = (pow(a+b,2) + pow(c+d,1/2)) * e
I think I'd do this with a simple tokeniser and parser rather than regular expressions. It's not that hard to write and will be more robust and readable than a regular expression based parser.
This question already has answers here:
Evaluating a mathematical expression in a string
(14 answers)
Closed 8 years ago.
I've got a python formula that randomly places operands in between numbers. The list could, for example, look like this:
['9-8+7', '7-8-6']
What I want to do is get the value of each string, so that looping through the strings, an array would see 9-8+7 and would append 8 and 7-8-6 would append -7. I can't convert a string with operands to int, so is this possible at all? Or should I change the algorithm so that instead of creating a string with each random output it calculates the value of it immediately?
Thank you in advance.
You can do eval on the list items, but that's a potential security hole and should only be used if you fully trust the source.
>>> map(eval, ['9-8+7', '7-8-6'])
[8, -7]
If you control the code producing the string, computing the values directly sounds like a better approach (safer and probably faster).
As Fredrik pointed out, you can do eval in Python. I thought I'd add a more general approach that would work in any language, and might shed some light on simple parsers for those that haven't seen them in action.
You're describing a language whose formal definition looks something like this:
expr := sum
sum := prod [("+" | "-") prod]...
prod := digit [("*" | "/") digit]...
digit := '0'..'9'
This grammar (which I'm not bothering to make correct EBNF) accepts these strings: "3", "4*5/2", and "8*3+9", and so on.
This gives us a clue how to parse it, and evaluation is no more work than accumulating results as we go. The following is working Python 2 code. Notice how closely the code follows the grammar.
class ParseFail(Exception):
pass
def eval_expr(str):
value, pos = eval_sum(str, 0)
return value
def eval_sum(str, pos):
value, pos = eval_product(str, pos)
accum = value
while pos != len(str):
op = str[pos]
if not str[pos] in ['+', '-']:
raise ParseFail("Unexpected symbol at position "
"{pos} of {str}".format(str=str, pos=pos))
value, pos = eval_product(str, pos + 1)
if op == '+':
accum += value
else:
accum -= value
return accum, pos
def eval_product(str, pos):
value, pos = eval_digit(str, pos)
accum = value
while pos != len(str):
op = str[pos]
if not str[pos] in ['*', '/']:
return accum, pos
value, pos = eval_digit(str, pos + 1)
if op == '*':
accum *= value
else:
accum /= value
return accum, pos
def eval_digit(str, pos):
if not str[pos].isdigit():
raise ParseFail("Unexpected symbol at position "
"{pos} of {str}".format(str=str, pos=pos))
return int(str[pos]), pos + 1
try:
print "3 ->", eval_expr("3")
print "3*4 ->", eval_expr("3*4")
print "2+3*4-5 ->", eval_expr("2+3*4-5")
# Should raise ParseFail
print "2+3*4^2-5 ->", eval_expr("2+3*4^2-5")
except ParseFail as err:
print
print err.args[0]
Here's a sample run:
$ python simple_expr.py
3 -> 3
3*4 -> 12
2+3*4-5 -> 9
2+3*4^2-5 ->
Unexpected symbol at position 5 of 2+3*4^2-5
It would be pretty easy to extend this to a full string calculator with more operators, such as the exponent operator '^' and multi-digit integers. Parentheses, floats and functions might be a bit of work, but not that hard either. Every programmer should try it once in their lives, in my opinion.
This of course depends on how well-behaved and restricted your expressions are.
Since subtraction is addition with a negative number, you can write the subtractions as additions with a negative number. Spit on + to find the terms. Then parse the terms of the sum to integers, and sum them. Do so for each expression.
[sum(map(int,l.replace('-', '+-').split('+'))) for l in ['9-8+7','7-8-6']]