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 OverflowYes, 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'
You can use type to create a new class on the fly and then instantiate it. Like so:
>>> t = type('test', (object,), {})()
>>> t
<__main__.test at 0xb615930c>
The arguments to type are: Class name, a tuple of base classes, and the object's dictionary. Which can contain functions (the object's methods) or attributes.
You can actually shorten the first line to
>>> t = type('test', (), {})()
>>> t.__class__.__bases__
(object,)
Because by default type creates new style classes that inherit from object.
type is used in Python for metaprogramming.
But if you just want to create an instance of object. Then, just create an instance of it. Like lejlot suggests.
Creating an instance of a new class like this has an important difference that may be useful.
>>> a = object()
>>> a.whoops = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'whoops'
Where as:
>>> b = type('', (), {})()
>>> b.this_works = 'cool'
>>>
python - How can I create an object and add attributes to it? - Stack Overflow
python - Setting default/empty attributes for user classes in __init__ - Stack Overflow
Can you create a class with an empty list attribute
oop - Empty class object in Python - Stack Overflow
Videos
The built-in object can be instantiated but can't have any attributes set on it. (I wish it could, for this exact purpose.) This is because it doesn't have a __dict__ to hold the attributes.
I generally just do this:
class Object(object):
pass
obj = Object()
obj.somefield = "somevalue"
But consider giving the Object class a more meaningful name, depending on what data it holds.
Another possibility is to use a sub-class of dict that allows attribute access to get at the keys:
class AttrDict(dict):
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
obj = AttrDict()
obj.somefield = "somevalue"
To instantiate the object attributes using a dictionary:
d = {"a": 1, "b": 2, "c": 3}
for k, v in d.items():
setattr(obj, k, v)
You could use my ancient Bunch recipe, but if you don't want to make a "bunch class", a very simple one already exists in Python -- all functions can have arbitrary attributes (including lambda functions). So, the following works:
obj = lambda: None
obj.somefield = 'somevalue'
Whether the loss of clarity compared to the venerable Bunch recipe is OK, is a style decision I will of course leave up to you.
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:
- It's easier to detect and fix a creation failure than a late use failure;
- 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.
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:
All class attributes should be included in the
__init__(initialiser) method. This is to ensure readability and aid debugging.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.resultstoself._results.Keep in mind this is only convention, and
self._resultscan still be directly accessed. However, this is the Pythonic way to handle what are pseudo-private attributes.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@propertydecorator above.This is a function that when invoked checks if
self._resultsisNone. If so it will raise an exception (fail-safe hint), otherwise it will return the object. The@propertydecorator changes the invocation style from a function to an attribute, so all the user has to use on an instance of MyClass is.resultsjust like any other attribute.(I changed the name of the method that sets the results to
generate_results()to avoid confusion and free up.resultsfor the getter method)If you then have other methods within the class that need to use
self._results, but only when properly assigned, you can useself.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).
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 += betMethod 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
A class is more or less a fancy wrapper for a dict of attributes to objects. When you instantiate a class you can assign to its attributes, and those will be stored in foo.__dict__; likewise, you can look in foo.__dict__ for any attributes you have already written.
This means you can do some neat dynamic things like:
class Employee: pass
def foo(self): pass
Employee.foo = foo
as well as assigning to a particular instance. (EDIT: added self parameter)
Try with lambda:
john.greet = lambda : print( 'hello world!' )
The you'll be able to do:
john.greet()
EDIT: Thanks Thomas K for the note - this works on Python 3.2 and not for Python2, where print appeared to be statement. But this will work for lambdas, without statements (right? Sorry, I know only python3.2 (: )
As per the type function , the third argument should be in the form of dictionary. So, for nested attributes, you can create the object before itself and then use it in the dictionary. Something like this might work -
da = type('',(),{'data':1})
a = type('',(),{'foo':da})
I dont get your point but you may use namedtuple :
>>>from collections import namedtuple
>>>foo = namedtuple('foo', "data tuple dict")
>>>foo.data = ""
''
>>> foo.tuple = ()
>>> foo.tuple
()
Suppose you want to store some collection of named data. You could use a dict but you like the look of dotted attributes in a class object. Just create the most boring class possible and use python's native attribute assignment to do the trick. It is usually a question of aesthetics.
If you know the attributes ahead of time you can use namedtuples for this kind of functionality.
From the python docs:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
Namedtuples are on way, if they don't have to be mutable:
from collections import namedtuple
MyTupleType = namedtuple('MyTupleType', ['field'])
yourobject = MyTupleType(field=3)
print(yourobject.field) # prints 3
If it's for testing, then using the Mock library is also handy (see http://www.voidspace.org.uk/python/mock/ ; unittest.mock is part of the standard library since Python 3.3 as well).
yourobject = MagicMock()
yourobject.field = 3
Note that yourobject now has any field or method you try to access on it, and their values are all yet another MagicMock instance. It's a very powerful unit testing tool.
Lastly you can just create a boring dummy class:
class Dummy(object):
pass
yourobject = Dummy()
yourobject.field = 3
Why not use a Default dict here.e.g.
var = defaultdict(int)
var.update({
'blas': {
'bla': 0.250,
'bla1': 0.300,
'bla2': 6,
...
},
'somth1': self.smth1,
'something': [
{ 'h1': 66.00 },
{ 'h2': 47.00 },
{ 'h3': 85.00 },
{ 'h4': 32.00 },
{ 'h5': 34.00 }
],
'this_has_to_be_object'.field: 1
}
)
Now var['anything'] would always return with 0.
I guess that is the functionality you require for testing, Right ?