In Python, and many other languages, there is a value that means "no value". In Python, that value is None. So you could do something like this:
class User:
username = None
password = None
Those sure sound like instance variables though, and not class variables, so maybe do this:
class User(object):
def __init__(self):
self.username = None
self.password = None
Note how Python assigns the None value implicitly from time to time:
def f():
pass
g = f() # g now has the value of None
Answer from Kenan Banks on Stack OverflowIn Python, and many other languages, there is a value that means "no value". In Python, that value is None. So you could do something like this:
class User:
username = None
password = None
Those sure sound like instance variables though, and not class variables, so maybe do this:
class User(object):
def __init__(self):
self.username = None
self.password = None
Note how Python assigns the None value implicitly from time to time:
def f():
pass
g = f() # g now has the value of None
First of all, you should rewrite like this:
class User(object):
def __init__(self, username, password):
self.username = username
self.password = password
This way, username and password are instance variables instead of class variables (in your example, they are class variables -- all instance variables need to be defined in __init__ as properties of self). Then, you can initialize a User with whatever username and password you want, including None if you truly want them to have no value.
Can you create a class with an empty list attribute
python - Setting default/empty attributes for user classes in __init__ - Stack Overflow
Given an object in python, can I somehow leave one attribute empty? - Stack Overflow
python 3.x - Class attribute returning Empty - Stack Overflow
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 (: )
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
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).
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'
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'
>>>
This is easy to accomplish by overriding __dir__ and __getattribute__:
class Empty(object):
def __dir__(self):
return []
def __getattribute__(self, name):
raise AttributeError("'{0}' object has no attribute '{1}'".format(type(self).__name__, name))
e = Empty()
dir(e)
[]
e.__name__
AttributeError: 'Empty' object has no attribute '__name__'
(In python2, Empty needs to be a new-style class, so the class Empty(object): is required; in python3 old-style classes are extinct so class Empty: is sufficient.)
Havn't came across any such object, which doesn;t have any attribute.. see below
In [74]: class dummy():
....: pass
....:
In [75]: d1 = dummy()
In [76]: dir(d1)
Out[76]: ['__doc__', '__module__']
In [77]: len(dir(d1))
Out[77]: 2
even None has attributes...
In [78]: dir(None)
Out[78]:
['__class__',
'__delattr__',
'__doc__',
'__format__',
'__getattribute__',
'__hash__',
'__init__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__']
You can define a dict as a class variable as you already did, but add the UID as a key to the dict in the __init__ method instead of a separate add_user method so that you can always validate the UID when an object is instantiated, no matter how:
class Account():
users = {}
def __init__(self, name, balance=0.0, uid=None):
if uid in self.users:
raise ValueError("UID '%s' already belongs to %s." % (uid, self.users[uid].name))
if len(uid) != 5 or not uid.isdigit():
raise ValueError("UID must be a 5-digit number.")
self.name = name
self.balance = balance
self.uid = uid
self.users[uid] = self
First noticed that you cant to a "return print(...", remove print.
You can do something like this
class Account():
'''
A class to perform some basic banking functions
'''
UserList = {} #Empty dictionary to store (UID: name) for each new instance
def __init__(self, name, balance=0.0, uid=None):
self.name = name #The name of the account holder
self.balance = balance #The initial balance
self.uid = uid #User ID number chosen by account holder
self.add_user(uid, name)
@classmethod
def new_account(cls):
'''
New user can specify details of account through this class method via input()
'''
return cls(
input('Name: '),
int(input('Balance: ')),
int(input('UID: ')),
)
def withdraw(self, amount):
if amount > self.balance:
raise RuntimeError('Amount greater than available balance.')
else:
self.balance -= amount
return "After a withdrawl of {}, {}'s current balance is {}".format(amount, self.name, self.balance) #printing balance after withdrawl
def deposit(self, amount):
self.balance += amount
return "After a deposit of {}, {}'s curent balance is {}".format(amount, self.name, self.balance) # printing balance after deposit
def add_user(self, uid, name):
self.UserList[int(uid)] = name
a = Account("new user", 100, 1)
a.add_user(2, "new user") a.add_user(3, "new user")
print(a.UserList)
this will output {1: 'new user', 2: 'new user', 3: 'new user'}