# Differentiate between a string and an expression

**URL:** <https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065>\
**Category:** Python Help\
**Created:** [September 15, 2026, 10:24am UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065 "2026-09-15T10:24:36Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![NickC](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nickc/32/37293_2.png) [@NickC](https://discuss.python.org/u/NickC)\
**Post date:** [September 15, 2026, 10:24am UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/1 "2026-09-15T10:24:36Z")

</div>

Is there a way to differentiate between a variable containing a plain string and one containing an expression, like an isexpression() function? For example how can I establish between these two:

```python
test1 = 'print("hello")' # <- expression

test2 = '"print(\"hello\")"' # <- string

```

A clearer demonstration of one reason why I need to establish between a string and a function:

```python
in_str = '"a {myVar} string"'
stored_code1 = 'f' + in_str
print(stored_code1)

in_str = 'aFunc("param1", "param2")'
stored_code2 = in_str
print(stored_code2)

def aFunc(par1, par2):
    return None

myVar = "test"
print(eval(stored_code1))
print(eval(stored_code2))

```

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [September 15, 2026, 10:47am UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/2 "2026-09-15T10:47:33Z")

</div>

The variable doesn’t contain the expression. It contains a value. In your `test1` example, the value it contains is a pretty boring one - `None` - because the `print()` function doesn’t return anything useful.

I’m not sure what you’re trying to achieve, but if you’re trying to figure out whether something’s safe to evaluate, I would recommend looking at [`ast.literal_eval`](https://docs.python.org/3/library/ast.html#ast.literal_eval); it’s able to parse a lot of things that would be considered safe, but rejects anything with a function call in it. But do be aware that an f-string isn’t safe; in fact, there’s nothing stopping you from doing something like `f'{aFunc("param1", "param2")}'` and calling the function from inside the string.

But you may need to provide us with more context to figure out what it is you’re trying to do. Maybe a different form of string interpolation will work for you.

---

<div class="post-metadata">

**Author:** ![NickC](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nickc/32/37293_2.png) [@NickC](https://discuss.python.org/u/NickC)\
**Post date:** [September 15, 2026, 11:26am UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/3 "2026-09-15T11:26:48Z")

</div>

@Rosuav you are quite right, question now edited to show test1 & test2 correctly. I will look into`ast.literal_eval` as you suggest.

The second example more clearly demonstrates why I need to establish the difference.

---

<div class="post-metadata">

**Author:** ![NickC](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nickc/32/37293_2.png) [@NickC](https://discuss.python.org/u/NickC)\
**Post date:** [September 15, 2026, 12:26pm UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/4 "2026-09-15T12:26:30Z")

</div>

Thanks, @Rosuav that works with a try.. except block:

```python
try:
    x = ast.literal_eval(in_str)
    print(in_str, "is string")
except:
    print(in_str, "is function")

```

However, not sure I like the idea of using try…except to determine a condition, that just feels like it should be used more for, well, exceptions.

---

<div class="post-metadata">

**Author:** ![NickC](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nickc/32/37293_2.png) [@NickC](https://discuss.python.org/u/NickC)\
**Post date:** [September 15, 2026, 1:50pm UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/5 "2026-09-15T13:50:41Z")

</div>

Further to your suggestion of `ast.literal_eval()` I have now found a solution using `ast.parse()`:

```python
import ast

def get_type(in_str):
    ast_tree = ast.parse(in_str)
    if str(ast_tree.body[0].value)[:8] == "Constant":
        return "constant"
    if str(ast_tree.body[0].value)[:4] == "Call":
        return "function"

in_str = '"a {myVar} string"'
print(in_str, "is a",get_type(in_str))

in_str = 'aFunc("param1", "param2")'
print(in_str, "is a",get_type(in_str))

```

---

<div class="post-metadata">

**Author:** ![peterc](https://avatars.discourse-cdn.com/v4/letter/p/f9ae1b/32.png) [@peterc](https://discuss.python.org/u/peterc)\
**Post date:** [September 15, 2026, 1:57pm UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/6 "2026-09-15T13:57:35Z")

</div>

With hindsight using ast.parse is the obviously correct solution. Note that ast.parse is capable of fairly sophisticated operations, there shouldn’t be any need for string slicing. And your current code will tell you that `'4'` is a string, when I think you’ll want to interpret that as an int instead. (Then again, maybe you have a guarantee that it won’t ever be a string.)

---

<div class="post-metadata">

**Author:** ![NickC](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nickc/32/37293_2.png) [@NickC](https://discuss.python.org/u/NickC)\
**Post date:** [September 15, 2026, 2:03pm UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/7 "2026-09-15T14:03:16Z")

</div>

> [@peterc](#):
>
> there shouldn’t be any need for string slicing

I couldn’t find any way to refer to the correct piece of the ast tree without using string slicing.

---

<div class="post-metadata">

**Author:** ![NickC](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nickc/32/37293_2.png) [@NickC](https://discuss.python.org/u/NickC)\
**Post date:** [September 15, 2026, 2:08pm UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/8 "2026-09-15T14:08:13Z")

</div>

> [@peterc](#):
>
> And your current code will tell you that `'4'` is a string

Would have been better if I had called the return values “constant” / “function”. Now edited, also moved in to a function.

---

<div class="post-metadata">

**Author:** ![BenjyWiener](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/benjywiener/32/33309_2.png) [@BenjyWiener](https://discuss.python.org/u/BenjyWiener)\
**Post date:** [September 17, 2026, 5:21am UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/9 "2026-09-17T05:21:35Z")

</div>

> [@NickC](#):
>
> I couldn’t find any way to refer to the correct piece of the ast tree without using string slicing.

This is a great use case for [`match`](https://docs.python.org/3/tutorial/controlflow.html#match-statements):

```python
def get_type(in_str):
    match ast.parse(in_str).body:
        case [ast.Expr(value=ast.Constant())]:
            return "constant"
        case [ast.Expr(value=ast.Call())]:
            return "function"
    
    raise RuntimeError("Expected function call or constant")

```

---

<div class="post-metadata">

**Author:** ![NickC](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nickc/32/37293_2.png) [@NickC](https://discuss.python.org/u/NickC)\
**Post date:** [September 17, 2026, 4:26pm UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/10 "2026-09-17T16:26:16Z")

</div>

Very interesting @BenjyWiener. However I’m not sure I understand why that works, for example any idea why

```python
if ast.parse(in_str).body.Expr(value=ast.Constant()) == True

```

doesn’t work?

---

<div class="post-metadata">

**Author:** ![peterc](https://avatars.discourse-cdn.com/v4/letter/p/f9ae1b/32.png) [@peterc](https://discuss.python.org/u/peterc)\
**Post date:** [September 18, 2026, 7:39am UTC](https://discuss.python.org/t/differentiate-between-a-string-and-an-expression/109065/11 "2026-09-18T07:39:28Z")

</div>

match does a lot of magic. In this case the equivalent if statement is

```python
if ast.parse("'hi'").body[0].value. __class__ == ast.Constant: ...

```
