We can create new types of objects with the class
statement. Within the class we can define member functions that operate on objects of this class.
# create a new type of object with nothing in it:
class mytype():
pass
v=mytype()
print(dir(v))
Usually we define an __init__
function to initialize the object (a constructor). We can define other "dunder" functions that perform well-known operations, including those performed by operators (+, ==, <, etc). And we can define our own functions.
# constructor:
class mytype():
'''
This is displayed by help().
'''
def __init__(self,a=0):
self.x=a
def __eq__(self,a):
return self.x == a
def __repr__(self):
return str(self.x)
def negated(self):
return -self.x
v=mytype(3)
# help(mytype)
print(v.x, v == 3, v == 5, v, v.negated())
help(mytype)
Unlike some other OO languages, members are not private. You can also modify and inspect objects dynamically.
class myclass():
x=1
# members (attributes) are not private:
v=myclass()
print(v.x)
v.y=3
print(v.y)
print(dir(v))
But objects are not variables. There is a difference between creating an object and binding it to a variable using the assignment operator. Only objects of built-in types (e.g. ints, lists, dictionaries) can be created using syntax instead of constructor functions.
# and variables are not objects:
print(v,type(v))
# if we assign to v, it now points to an int:
v = 5
print(v,type(v))
# but this type is incomplete, so not very useful :
v=mytype(3)
print(v+1)
In many cases it's worth building on the features provided by an existing type ("subclassing"). Here's an example that subclasses the int
type. Here we access the existing __sub__
and __add__
functions in the int
type to avoid recursion.
# so let's subclass an existing type
# and redefine some operators
class myint(int):
def __add__(self,x):
return int.__sub__(self,x)
def __sub__(self,x):
return int.__add__(self,x)
# new type is just like int but +/- are reversed:
x=myint(1)
print(x, x+1, x-1, x+x)
We can also define the function call and indexing (__setitem__
) operators. In this example we define a new type of dictionary that converts stored values to upper-case. As before, we re-use dict
's__setitem__
method:
# another example of subclassing an existing type
# changing the behaviour of the [] operator for a dict:
class updict(dict):
def __setitem__(self,k,v):
dict.__setitem__(self,k,str.upper(v))
v=updict()
v[0]='x'
print(v)