Yes, in Python 3.3 SimpleNamespace was added

Unlike object, with SimpleNamespace you can add and remove attributes. If a SimpleNamespace object is initialized with keyword arguments, those are directly added to the underlying namespace.

Example:

import types

x = types.SimpleNamespace()
x.happy = True

print(x.happy) # True

del x.happy
print(x.happy) # AttributeError. object has no attribute 'happy'
Answer from Vlad Bezden on Stack Overflow
๐ŸŒ
TutorialBrain
tutorialbrain.com โ€บ home โ€บ python create object
Python Create Object โ€” TutorialBrain
July 9, 2025 - It means that these attributes (or their copies) are unique to each object. Creating empty objects in Python is easy. Define an empty class and then create an object of that class.
Discussions

python - How can I create an object and add attributes to it? - Stack Overflow
I want to create a dynamic object in Python and then add attributes to it. This didn't work: obj = object() obj.somefield = "somevalue" AttributeError: 'object' object has no attribute ' More on stackoverflow.com
๐ŸŒ stackoverflow.com
python - Setting default/empty attributes for user classes in __init__ - Stack Overflow
With this in mind, let's change the attribute declarations in __init__. Before we settle for a well-behaved, well-defined declaration, we must take care of how we declare default arguments. ... Now, there are some 'gotchas' that we must be aware of while declaring default args. Consider the following declaration that initializes names and appends a random name on object creation. Recall that lists are mutable objects in Python... More on stackoverflow.com
๐ŸŒ stackoverflow.com
Can you create a class with an empty list attribute
what should I do to work around this? When you initialize the object, set the attribute to an empty list. More on reddit.com
๐ŸŒ r/learnpython
7
1
February 22, 2023
oop - Empty class object in Python - Stack Overflow
I'm teaching a Python class on object-oriented programming and as I'm brushing up on how to explain classes, I saw an empty class definition: class Employee: pass The example then goes on to d... More on stackoverflow.com
๐ŸŒ stackoverflow.com
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ how-to-create-an-empty-class-in-python
How to create an empty class in Python? - GeeksforGeeks
December 29, 2020 - # Python program to demonstrate # empty class class Geeks: pass # Driver's code obj = Geeks() print(obj) Output: <__main__.Geeks object at 0x02B4A340> Python also allows us to set the attributes of an object of an empty class. We can also set different attributes for different objects.
๐ŸŒ
TutorialsPoint
tutorialspoint.com โ€บ how-to-create-an-empty-class-in-python
How to create an empty class in Python?
September 15, 2022 - This statement in Python do nothing. Let us see an example ? ... In this example, we will create an empty class using the pass, but attributes will also be set for objects ? class Student: pass # Creating objects st1 = Student() st1.name = 'Henry' st1.age = 17 st1.marks = 90 st2 = Student() st2.name = 'Clark' st2.age = 16 st2.marks = 77 st2.phone = '120-6756-79' print('Student 1 = ', st1.name, st1.age, st1.marks) print('Student 2 = ', st2.name, st2.age, st2.marks, st2.phone)
๐ŸŒ
Readthedocs
jfine-python-classes.readthedocs.io โ€บ en โ€บ latest โ€บ construct.html
Constructing classes โ€” Objects and classes in Python tutorial
The method resolution order (mro) attribute __mro__ is computed from the bases of the class. It provides support for multiple inheritance. ... For now the important thing is that even the empty class has attributes.
๐ŸŒ
Packtpub
subscription.packtpub.com โ€บ book โ€บ application-development โ€บ 9781784398781 โ€บ 6 โ€บ ch06lvl1sec43 โ€บ empty-objects
6. Python Data Structures | Python 3 Object-Oriented Programming - Second Edition
Technically, we can instantiate ... has no attribute 'x' Unfortunately, as you can see, it's not possible to set any attributes on an object that was instantiated directly....
Find elsewhere
Top answer
1 of 4
35

I think you should avoid both solutions. Simply because you should avoid to create uninitialized or partially initialized objects, except in one case I will outline later.

Look at two slightly modified version of your class, with a setter and a getter:

class MyClass1:
    def __init__(self, df):
          self.df = df
          self.results = None

    def set_results(self, df_results):
         self.results = df_results

    def get_results(self):
         return self.results

And

class MyClass2:
    def __init__(self, df):
          self.df = df

    def set_results(self, df_results):
         self.results = df_results

    def get_results(self):
         return self.results

The only difference between MyClass1 and MyClass2 is that the first one initializes results in the constructor while the second does it in set_results. Here comes the user of your class (usually you, but not always). Everyone knows you can't trust the user (even if it's you):

MyClass1("df").get_results()
# returns None

Or

MyClass2("df").get_results()
# Traceback (most recent call last):
# ...
# AttributeError: 'MyClass2' object has no attribute 'results'

You might think that the first case is better because it does not fail, but I do not agree. I would like the program to fail fast in this case, rather than do a long debugging session to find what happened. Hence, the first part of first answer is: do not set the uninitialized fields to None, because you loose a fail-fast hint.

But that's not the whole answer. Whichever version you choose, you have an issue: the object was not used and it shouldn't have been, because it was not fully initialized. You can add a docstring to get_results: """Always use set_results **BEFORE** this method""". Unfortunately the user doesn't read docstrings either.

You have two main reasons for uninitialized fields in your object: 1. you don't know (for now) the value of the field; 2. you want to avoid an expansive operation (computation, file access, network, ...), aka "lazy initialization". Both situations are met in real world, and collide the need of using only fully initialized objects.

Happily, there is a well documented solution to this problem: Design Patterns, and more precisely Creational patterns. In your case, the Factory pattern or the Builder pattern might be the answer. E.g.:

class MyClassBuilder:
    def __init__(self, df):
          self._df = df # df is known immediately
          # GIVE A DEFAULT VALUE TO OTHER FIELDS to avoid the possibility of a partially uninitialized object.
          # The default value should be either:
          # * a value passed as a parameter of the constructor ;
          # * a sensible value (eg. an empty list, 0, etc.)

    def results(self, df_results):
         self._results = df_results
         return self # for fluent style
         
    ... other field initializers

    def build(self):
        return MyClass(self._df, self._results, ...)

class MyClass:
    def __init__(self, df, results, ...):
          self.df = df
          self.results = results
          ...
          
    def get_results(self):
         return self.results
    
    ... other getters
         

(You can use a Factory too, but I find the Builder more flexible). Let's give a second chance to the user:

>>> b = MyClassBuilder("df").build()
Traceback (most recent call last):
...
AttributeError: 'MyClassBuilder' object has no attribute '_results'
>>> b = MyClassBuilder("df")
>>> b.results("r")
... other fields iniialization
>>> x = b.build()
>>> x
<__main__.MyClass object at ...>
>>> x.get_results()
'r'

The advantages are clear:

  1. It's easier to detect and fix a creation failure than a late use failure;
  2. You do not release in the wild a uninitialized (and thus potentially damaging) version of your object.

The presence of uninitialized fields in the Builder is not a contradiction: those fields are uninitialized by design, because the Builder's role is to initialize them. (Actually, those fields are some kind of forein fields to the Builder.) This is the case I was talking about in my introduction. They should, in my mind, be set to a default value (if it exists) or left uninitialized to raise an exception if you try to create an uncomplete object.

Second part of my answer: use a Creational pattern to ensure the object is correctly initialized.

Side note: I'm very suspicious when I see a class with getters and setters. My rule of thumb is: always try to separate them because when they meet, objects become unstable.

2 of 4
21

Following considerable research and discussions with experienced programmers please see below what I believe is the most Pythonic solution to this question. I have included the updated code first and then a narrative:

class MyClass:
    def __init__(self,df):
          self.df = df
          self._results = None

    @property
    def results(self):
        if self._results is None:
            raise Exception('df_client is None')
        return self._results

    def generate_results(self, df_results):
         #Imagine some calculations here or something
         self._results = df_results

Description of what I learnt, changed and why:

  1. All class attributes should be included in the __init__ (initialiser) method. This is to ensure readability and aid debugging.

  2. The first issue is that you cannot create private attributes in Python. Everything is public, so any partially initialised attributes (such as results being set to None) can be accessed. Convention to indicate a private attribute is to place a lead underscore at the front, so in this case I changed it to self.results to self._results.

    Keep in mind this is only convention, and self._results can still be directly accessed. However, this is the Pythonic way to handle what are pseudo-private attributes.

  3. The second issue is having a partly initialised attribute which is set to None. As this is set to None, as @jferard below explains, we now have lost a fail-fast hint and have added a layer of obfuscation for debugging the code.

    To resolve this we add a getter method. This can be seen above as the function results() which has the @property decorator above.

    This is a function that when invoked checks if self._results is None. If so it will raise an exception (fail-safe hint), otherwise it will return the object. The @property decorator changes the invocation style from a function to an attribute, so all the user has to use on an instance of MyClass is .results just like any other attribute.

    (I changed the name of the method that sets the results to generate_results() to avoid confusion and free up .results for the getter method)

  4. If you then have other methods within the class that need to use self._results, but only when properly assigned, you can use self.results, and that way the fail-safe hint is baked in as above.

I recommend also reading @jferard's answer to this question. He goes into depth about the problems and some of the solutions. The reason I added my answer is that I think for a lot of cases the above is all you need (and the Pythonic way of doing it).

๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ can you create a class with an empty list attribute
r/learnpython on Reddit: Can you create a class with an empty list attribute
February 22, 2023 -

I'm trying to create texas holdem with players being class instances with hand as an attribute of type list. When I instantiate a class with no value for hand it says I need instantiate it with a list, and when I try to use self.hand = None it doesn't allow me to append new generated cards to it since it's value type none, what should I do to work around this?

Edit: Now that I'm home I can add my code for people to see

Main Code

from pokerMethods import *
from playerClass import *

def main():
    deckNumber = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
    deckSuit = ["Spades", "Diamonds", "Clubs", "Hearts"]
    cardList = []
    playerList = []
    p1 = Player("Herp", "Derp")
    p2 = Player("Herpy", "Derpy")

    createCard(p1, deckNumber, deckSuit, cardList)
    createCard(p2, deckNumber, deckSuit, cardList)
    
    print(p1.hand)
    print(p2.hand)
main()

Class Code:

class Player:
    def __init__(self, fname: str, lname: str, hand = [], money = 0):
        self.fname = fname
        self.lname = lname
        self.hand = hand
        self.money = money

    def addCard(self, newCard):
        self.hand.insert(0,newCard)

    def removeMoney(self, bet):
        self.money -= bet

    def addMoney(self, bet):
        self.money += bet

Method Code

import random
def createCard(player, deckNumber, deckSuit, cardList,):
    cardPlayer = deckNumber[random.randint(0, len(deckNumber)-1)] + " " + 
    deckSuit[random.randint(0, len(deckSuit)-1)]
    if cardPlayer not in cardList:
        cardList.append(cardPlayer)
        player.addCard(cardPlayer)

added hand = [] and then did self.hand = hand because when I did just self.hand = [] it gave me the error

Traceback (most recent call last):

File "Pythons Test Shit\Test'.py", line 17, in <module>

main()

File "Pythons Test Shit\Test'.py", line 9, in main

p1 = Player("Herp", "Derp")

TypeError: __init__() missing 1 required positional argument: 'hand'

and with hand = [] in the initializer

Player 1: ['2 Hearts', '1 Clubs']

Player 2: ['2 Hearts', '1 Clubs']

both instances are having their lists edited

edit 2:

re-read the comments and saw u/Binary101010 's comment, sorry for not trying that before doing all my edits and stuff but thank you so much, it worked

๐ŸŒ
Real Python
realpython.com โ€บ python-class-constructor
Python Class Constructors: Control Your Object Instantiation โ€“ Real Python
January 19, 2025 - To run the first step, Python classes have a special method called .__new__(), which is responsible for creating and returning a new empty object. Then another special method, .__init__(), takes the resulting object, along with the class ...
๐ŸŒ
Python documentation
docs.python.org โ€บ 3 โ€บ tutorial โ€บ classes.html
9. Classes โ€” Python 3.14.4 documentation
Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state.
๐ŸŒ
W3Schools
w3schools.com โ€บ python โ€บ ref_func_object.asp
Python object() Function
The object() function returns an empty object. You cannot add new properties or methods to this object. This object is the base for all classes, it holds the built-in properties and methods which are default for all classes.
๐ŸŒ
sqlpey
sqlpey.com โ€บ python โ€บ top-2-ways-to-create-an-empty-object-in-python
Top 2 Ways to Create an Empty Object in Python - sqlpey
November 23, 2024 - In this case, you are creating a blank slate that behaves like any other Python object, allowing you to add attributes dynamically and use duck typing effectively. If you are looking for further variations, consider using Pythonโ€™s collections.namedtuple for creating lightweight objects with immutable fields or creating an empty dictionary and using it as a dynamic container.
๐ŸŒ
CodingNomads
codingnomads.com โ€บ creating-python-objects-from-classes
Python Classes, Objects and Instance Variables
Learn how to define a simple Python class, create an object of that class, and modify instance variables within the Python object.