Python Variable Declaration

Python Variable Declaration

Okay, first things first.

There is no such thing as "variable declaration" or "variable initialization" in Python.

There is simply what we call "assignment", but should probably just call "naming".

Assignment means "this name on the left-hand side now refers to the result of evaluating the right-hand side, regardless of what it referred to before (if anything)".

foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication

As such, Python's names (a better term than "variables", arguably) don't have associated types; the values do. You can re-apply the same name to anything regardless of its type, but the thing still has behaviour that's dependent upon its type. The name is simply a way to refer to the value (object). This answers your second question: You don't create variables to hold a custom type. You don't create variables to hold any particular type. You don't "create" variables at all. You give names to objects.

Second point: Python follows a very simple rule when it comes to classes, that is actually much more consistent than what languages like Java, C++ and C# do: everything declared inside the class block is part of the class. So, functions (def) written here are methods, i.e. part of the class object (not stored on a per-instance basis), just like in Java, C++ and C#; but other names here are also part of the class. Again, the names are just names, and they don't have associated types, and functions are objects too in Python. Thus:

class Example:
data = 42
def method(self): pass

Classes are objects too, in Python.

So now we have created an object named Example, which represents the class of all things that are Examples. This object has two user-supplied attributes (In C++, "members"; in C#, "fields or properties or methods"; in Java, "fields or methods"). One of them is named data, and it stores the integer value 42. The other is named method, and it stores a function object. (There are several more attributes that Python adds automatically.)

These attributes still aren't really part of the object, though. Fundamentally, an object is just a bundle of more names (the attribute names), until you get down to things that can't be divided up any more. Thus, values can be shared between different instances of a class, or even between objects of different classes, if you deliberately set that up.

Let's create an instance:

x = Example()

Now we have a separate object named x, which is an instance of Example. The data and method are not actually part of the object, but we can still look them up via x because of some magic that Python does behind the scenes. When we look up method, in particular, we will instead get a "bound method" (when we call it, x gets passed automatically as the self parameter, which cannot happen if we look up Example.method directly).

What happens when we try to use x.data?

When we examine it, it's looked up in the object first. If it's not found in the object, Python looks in the class.

However, when we assign to x.data, Python will create an attribute on the object. It will not replace the class' attribute.

This allows us to do object initialization. Python will automatically call the class' __init__ method on new instances when they are created, if present. In this method, we can simply assign to attributes to set initial values for that attribute on each object:

class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before

Now we must specify a name when we create an Example, and each instance has its own name. Python will ignore the class attribute Example.name whenever we look up the .name of an instance, because the instance's attribute will be found first.

One last caveat: modification (mutation) and assignment are different things!

In Python, strings are immutable. They cannot be modified. When you do:

a = 'hi '
b = a
a += 'mom'

You do not change the original 'hi ' string. That is impossible in Python. Instead, you create a new string 'hi mom', and cause a to stop being a name for 'hi ', and start being a name for 'hi mom' instead. We made b a name for 'hi ' as well, and after re-applying the a name, b is still a name for 'hi ', because 'hi ' still exists and has not been changed.

But lists can be changed:

a = [1, 2, 3]
b = a
a += [4]

Now b is [1, 2, 3, 4] as well, because we made b a name for the same thing that a named, and then we changed that thing. We did not create a new list for a to name, because Python simply treats += differently for lists.

This matters for objects because if you had a list as a class attribute, and used an instance to modify the list, then the change would be "seen" in all other instances. This is because (a) the data is actually part of the class object, and not any instance object; (b) because you were modifying the list and not doing a simple assignment, you did not create a new instance attribute hiding the class attribute.

Is it possible to hard declare a variable in Python?

You said: " I want to loop and take the numbers one by one."

Did you mean this:

for match in INV_match_id:
match_db = sb.events(match_id=match)

I don't know what you want to do with match_db

Update:

"that single number is also declared as a list. like this- ['125364']"

Well if match == ['125364'] then it depends on whether you want: "125364" or 125364. I assume the latter since you talk a lot about integers:

for match in INV_match_id:
match = int(match[0])
match_db = sb.events(match_id=match)

Next Update:

So you have: INV_match_id = ['3749052','3749522']

This means that the list is a list of strings, so the code changes to this:

for match in INV_match_id:
match_db = sb.events(match_id=int(match))

Your original code was making match into a list of the digits of each number. (eg match = [1,2,5,3,6,4])

Reversionary Update:

This time we have: INV_match_id = [['3749052'],['3749522']]

that just means going back to the second version of my code above:

for match in INV_match_id:
match = int(match[0])
match_db = sb.events(match_id=match)

Is it possible only to declare a variable without assigning any value in Python?

Why not just do this:

var = None

Python is dynamic, so you don't need to declare things; they exist automatically in the first scope where they're assigned. So, all you need is a regular old assignment statement as above.

This is nice, because you'll never end up with an uninitialized variable. But be careful -- this doesn't mean that you won't end up with incorrectly initialized variables. If you init something to None, make sure that's what you really want, and assign something more meaningful if you can.

Streamlit python variable declaration

The question has nothing to do with Streamlit, the variables are just not defined. Let me rewrite your code without the Streamlit part and with added comments to see if that clarifies things:

option = 'C'

if option == 'A':
foo = 1 # this line is not executed, since option is not A
elif option == 'B':
bar = 2 # this line is not executed, since option is not B
elif option == 'C':
# the code below is executed, but foo and bar are undefined, so there is an error
baz = foo + bar
print(baz)

Does the error make more sense? If you want to add foo and bar, they must be defined first, which is not the case here.

If you are sure that the code will be called with options A and B before option C, then it should work. But then you'd be better off setting some default values beforehand, like foo = None and bar = None. You'd still get an error if they are still None at the C step, but that would be clearer.

Or maybe you what you are looking for are session states?

Explicitly declaring a variable type in Python

in case you want methods callable on a type ...you can always use dir(var) in python console...

Difficulty in understanding the python variable declaration

  1. dataValue is a dictionary variable name, which has in it key:value pair of '0xffff':None https://docs.python.org/3/tutorial/datastructures.html.
  2. vars(cls).items() Return the __dict__ attribute for a module, class, instance, or any other object with a __dict__ attribute https://docs.python.org/3/library/functions.html#vars.
  3. A function returning another function, usually applied as a function transformation using the @wrapper syntax. Common examples for decorators are classmethod() and staticmethod() https://docs.python.org/3/glossary.html#term-decorator https://docs.python.org/3/library/functions.html#classmethod https://docs.python.org/3/library/functions.html#staticmethod.

declare variable type inside function

Type hints are ignored at runtime.

At the top of the page, the documentation that you've linked contains a note that states (emphasis mine):

The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc.

The purpose of type hints is for static typechecking tools (e.g. mypy), which use static analysis to verify that your code respects the written type hints. These tools must be run as a separate process. Their primary use is to ensure that new changes in large codebases do not introduce potential typing issues (which can eventually become latent bugs that are difficult to resolve).

If you want explicit runtime type checks (e.g. to raise an Exception if a value of a wrong type is passed into a function), use isinstance().

How to declare a class variable without a value in a way that suppresses Pylance warning

update: This is so obvious I assume it won't work in your case, but it is the "natural thing to do"

If you arte annotating instance attributes, and don't want them to be able to read "None" or other sentinel value, simply do not fill in a sentinel value, just declare the attribute and its annotation. That is, do not try to fill in a value in __init__, declare the annotation in the class body instead:

class Person:

name: str

# No need for this:
# def __init__(self) -> None:
# self.name:str = None

def setName(self, name:str) -> None:
self.name = name


Assuming you need to initialize it with an invalid value for whatever reason, the original answer applies:

Well, if this was certainly a case were the programmer knows better than the type-checker, I think it would be the case for using typing.cast: this is a no-operation in runtime, but which tells the static checkers that the value being cast is actually of that type, regardless of previous declarations:

(to be clear: don't do this:)

import typing as t

class Person:

def __init__(self) -> None:
self._name: t.Optional[str, None] = None

@property
def name(self) -> str:
return t.cast(str, self._name)

...

However, upon writing this, I came to the realisation that "self._name" might actually be "None" at this time. The typechecker can do some state-checking by following the program steps, but not in such a generic way - trying to read instance.name before it was set should cause in Python a runtime error instead.

So, if the method is called to express exactly that, it works as the tools can follow parts of the code guarded by isinstance (and if one needs a more complicated check than isinstance, take a look on the docs for typing.TypeGuard) - and we thank the tools for ensuring the program will run without a hard to debug error afterwards:

(this is the correct way)


import typing as t

class Person:

def __init__(self) -> None:
self._name: t.Optional[str, None] = None

@property
def name(self) -> str:
if isinstance(name:=self._name, str):
return name
raise AttributeError()

@name.setter
def name(self, name:str) -> None:
self._name = name

Python variable declaration and function error

Regarding:

if __name__ == "__main__":

That's only true if you actually run the test.py file, not when you just import it, as you do from file2.py. In the latter case, there is no code running to bind the BP variable to an object, so calling test will complain about it.



Related Topics



Leave a reply



Submit