- Definition
- Inheritance
- Self Reference
- Instantiation
- Metaclass
- Deconstruction
- Encapsulation
- Special Attributes
- Operator Overloading
- Polymorphism
A class statement indicates a class definition.
It consists of the following:
- The
classkeyword - The class name
- The base classes in a pair of round brackets, indicates the inheritance
- A colon
- An indented block of code specifying its variable and method attributes
Built-in types can be used as base classes for extension by the user.
Multiple inheritance is supported in Python.
super() returns a proxy object that allows the access to the methods of all base classes.
Functions defined in class are called methods.
The first parameter of a method must be the object itself, oftenly called self reference with an identifier name self.
It refers to the current instance of the class, and is used to access attributes that belongs to the class or the instance.
Property
A property is like a variable that can be retrieved, set, or deleted.
@propertydeclares a method as a property. The method will be the getter method that returns the value of the property.@p.setterdeclares a method as the setter method for the property p.@p.deleterdeclares a method as the deleter method for the property p.
Class method
@classmethod declares a method as a class method that can be called through the class name without instantiation.
Instead of self, the reference argument of a class method is cls, which is used to access the class attributes but not the instance attributes.
Static method
@staticmethod defines a static method that does not receive any reference argument and cannot access any attributes.
Call the class as a function to create a class instance, an object.
Use an assignment statement to assign a variable with an object value.
Each class in Pyhton is actually an instance of the type metaclass.
Thus a class definition can be rewritten as: type(name, bases, attributes), an instantiation where bases is in the form of a tuple and attributes a dictionary.
A del statement deletes objects or properties on objects.
Private attributes, denoted by a single or double underscores as the prefix, prevent data from direct modifications.
There exist a few special private attributes that most objects have in common:
__init__()is automatically invoked during class instantiation if defined, initializing a new class instance as its constructor.__call__()is invoked when an object is called like a function, to resolve the behaviors of this callable object.__str__()is invoked whenprint()orstr()function are called on the object and returns its content as a string.__int__()is invoked whenintfunction is called on the object and returns its content as an integer.__len__()is invoked whenlen()function is called on the object and returns the length of the container in the form of an integer.__getitem__()is invoked when the item access operator[]is applied on the object and returns the corresponding element.__bool__()returns the boolean value of the object. By default, it evaluates toTrue.__class__refers to the class from which the object was created.__doc__refers to the documentation string (docstring) of that class.__dict__refers to a dictionary used to store the public attributes of an object.
Most built-in operators which are interpreted as functions can be redefined for class instances.
| Operator | Interpretation |
|---|---|
a + b |
a.__add__(b) |
a - b |
a.__sub__(b) |
a * b |
a.__mul__(b) |
a ** b |
a.__pow__(b) |
a / b |
a.__truediv__(b) |
a // b |
a.__floordiv__(b) |
a % b |
a.__mod__(b) |
a << b |
a.__lshift__(b) |
a << b |
a.__rshift__(b) |
a & b |
a.__and__(b) |
a | b |
a.__or__(b) |
a ^ b |
a.__xor__(b) |
~a |
a.__invert__(b) |
a < b |
a.__lt__(b) |
a <= b |
a.__le__(b) |
a == b |
a.__eq__(b) |
a != b |
a.__ne__(b) |
a > b |
a.__gt__(b) |
a >= b |
a.__ge__(b) |
If multiple types of objects share a same attribute, a common interface can be created by a def statement and used.
class A:
def method(self):
pass
class B:
def method(self):
pass
def interface(object):
object.method()Roman Numeral
class RomanNum():
'''
Roman numeral type, with common numeric operations supported.
'''
reference = [
('M', 1000), ('CM', 900), ('D', 500), ('CD', 400),
('C', 100), ('XC', 90), ('L', 50), ('XL', 40),
('X', 10), ('IX', 9), ('V', 5), ('IV', 4),
('I', 1)
]
def __a_r(self, anum) -> str:
if not 0 < anum < 4000:
raise ValueError("integer value requested to be between 1 and 3999 for RomanNum()")
rnum = ''
for (rchars, achars) in self.reference:
while anum >= achars:
rnum += rchars
anum -= achars
return rnum
def __r_a(self, rnum) -> int:
anum = 0
for (rchars, achars) in self.reference:
while rnum.startswith(rchars):
anum += achars
rnum = rnum[len(rchars):len(rnum)]
if rnum:
raise ValueError("invalid roman numeral string literal for RomanNum()")
return anum
def __init__(self, value):
'''
Initializes or updates the instance.
'''
if type(value) == RomanNum:
self.__roman = value.roman()
self.__arabic = value.arabic()
elif type(value) == int:
self.__roman = self.__a_r(value)
self.__arabic = value
elif type(value) == str:
self.__arabic = self.__r_a(value)
self.__roman = value
else:
raise TypeError("RomanNum() only takes a decimal integer or a roman numeral string")
__call__ = __init__
def __str__(self) -> str:
'''
Returns the roman numeral as string.
'''
return self.__roman
__repr__ = __str__
roman = __str__
def __int__(self) -> int:
'''
Returns the corresponding arabic numeral as integer.
'''
return self.__arabic
__index__ = __int__
arabic = __int__
def __float__(self) -> float:
'''
Returns the corresponding arabic numeral as floating-point.
'''
return float(self.__arabic)
def __len__(self) -> int:
'''
Returns the length of the roman numeral string.
'''
return len(self.__roman)
def __eq__(self, other):
if type(other) == RomanNum:
other = other.__arabic
return self.__arabic == other or self.__roman == other
def __ne__(self, other):
return not self.__eq__(other)
def __lt__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return self.__arabic < other
def __le__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return self.__arabic <= other
def __gt__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return self.__arabic > other
def __ge__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return self.__arabic >= other
def __add__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return RomanNum(int(self.__arabic + other))
def __sub__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return RomanNum(int(self.__arabic - other))
def __mul__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return RomanNum(int(self.__arabic * other))
def __pow__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return RomanNum(int(self.__arabic ** other))
def __floordiv__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return RomanNum(int(self.__arabic // other))
def __mod__(self, other):
if type(other) != float and type(other) != int:
other = RomanNum(other).__arabic
return RomanNum(int(self.__arabic % other))