1. class statement
A class is defined using the class statement.The body of a class contains a series of statements that execute during class definition. Here's an example:
class Account(object):
num_accounts = 0
def __init__(self,name,balance):
self.name = name
self.balance = balance
Account.num_accounts += 1
def __del__(self):
Account.num_accounts -= 1
def deposit(self,amt):
self.balance = self.balance + amt
def withdraw(self,amt):
self.balance = self.balance - amt
def inquiry(self):
return self.balance
It's important to note that a class statement by itself doesn’t create any instances of the class.
The functions defined inside a class are known as instance methods. An instance method is a function that operates on an instance of the class, which is passed as the first argument: self.
Class variables such as num_accounts are values that are shared among all instances of a class.
2. Scoping Rules:
For example, in methods you always reference attributes of the instance through self. Thus, in the example you use
self.balance, not balance. This also applies if you want to call a method from another method, as shown in the following example:
class Foo(object):
def bar(self):
print("bar!")
def spam(self):
bar(self) #
Incorrect! 'bar' generates a NameError
self.bar() # This works
Foo.bar(self) # This also works
The lack of scoping in classes is one area where Python differs from C++ or Java.
If you have used those languages, the self parameter in Python is the same as the this pointer.
The explicit use of self is required because Python does not provide a means to explicitly declare variables (that is, a declaration such as int x or float y in Class).
The explicit use of self fixes this—all values stored on self are part of the instance and all other assignments are just local variables.
3. static method and Class method : @staticmethod and @classmethod
(1)
A static method is an ordinary function that just happens to live in the namespace defined by a class. It does not operate on any kind of instance. To define a static method, use the @staticmethod decorator as shown here:
class Foo(object):
@staticmethod
def add(x,y):
return x + y
To call a static method, you just prefix it by the class name.You do not pass it any additional information. For example:
x = Foo.add(3,4) # x = 7
A common use of static methods is in writing classes where you might have many different ways to create new instances. Because there can only be one __init__() function, alternative creation functions are often defined as shown here:
class Date(object):
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
@staticmethod
def now():
t = time.localtime()
return Date(t.tm_year, t.tm_mon, t.tm_day)
@staticmethod
def tomorrow():
t = time.localtime(time.time()+86400)
return Date(t.tm_year, t.tm_mon, t.tm_day)
# Example of creating some dates
a = Date(1967, 4, 9)
b = Date.now() # Calls static method now()
c = Date.tomorrow() # Calls static method tomorrow()
(2) Class methods
Class methods are methods that operate on the class itself as an object. Defined using the
@classmethod decorator, a class method is different than an instance method in that the class is passed as the first argument which is named cls by convention. For example:
class Times(object):
factor = 1
@classmethod
def mul(cls,x):
return cls.factor*x
class TwoTimes(Times):
factor = 2
x = TwoTimes.mul(4) # Calls Times.mul(TwoTimes, 4) -> 8
In this example, notice how the class TwoTimes is passed to mul() as an object.
As an example, suppose that you defined a class that inherited from the Date class shown previously and customized it slightly:
class EuroDate(Date):
# Modify string conversion to use European dates
def __str__(self):
return "%02d/%02d/%4d" % (self.day, self.month, self.year)
Because the class inherits from Date, it has all of the same features. However, the now() and tomorrow() methods are slightly broken.
For example, if someone calls EuroDate.now(), a Date object is returned instead of a EuroDate object.
A class method can fix this:
class Date(object):
#... (omit)
@classmethod
def now(cls):
t = time.localtime()
# Create an object of the appropriate type
return cls(t.tm_year, t.tm_month, t.tm_day)
class EuroDate(Date):
#... (omit)
a = Date.now() # Calls Date.now(Date) and returns a Date
b = EuroDate.now() # Calls Date.now(EuroDate) and returns a EuroDate
(3)
One caution about static and class methods is that Python does not manage these methods in a separate namespace than the instance methods. As a result, they can be invoked on an instance. For example:
d = Date(1967,4,9)
b = d.now() # Calls Date.now(Date)
This is potentially quite confusing because a call to d.now() doesn't really have anything to do with the instance d.
This behavior is one area where the Python object system differs from that found in other OO languages such as Smalltalk and Ruby. In those languages, class methods are strictly separate from instance methods.
(4)
When you define static and class methods using @staticmethod and @classmethod, you are actually specifying the use of a different property function that will handle the access to those methods in a different way.
For example, @staticmethod simply returns the method function back “as is” without any special wrapping or processing.
4. property
(1)
A property is a special kind of attribute that computes its value when accessed. Here is a simple example:
class Circle(object):
def __init__(self,radius):
self.radius = radius
# Some additional properties of Circles
@property
def area(self):
return math.pi*self.radius**2
@property
def perimeter(self):
return 2*math.pi*self.radius
The resulting Circle object behaves as follows:
>>> c = Circle(4.0)
>>> c.radius
4.0
>>> c.area
50.26548245743669
>>> c.perimeter
25.132741228718345
>>> c.area = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>>
In this example, Circle instances have an instance variable c.radius that is stored. c.area and c.perimeter are simply computed from that value.
The @property decorator makes it possible for the method that follows to be accessed as a simple attribute, without the extra () that you would normally have to add to call the method.
(2)
Properties can also intercept operations to set and delete an attribute.This is done by attaching additional setter and deleter methods to a property. Here is an example:
class Foo(object):
def __init__(self,name):
self._ _name = name
@property
def name(self):
return self.__name
@name
.setter
def name(self,value):
if not isinstance(value,str):
raise TypeError("Must be a string!")
self.__name = value
@name
.deleter
def name(self):
raise TypeError("Can't delete name")
f = Foo("Guido")
n = f.name # calls f.name() - get function
f.name = "Monty" # calls setter name(f,"Monty")
f.name = 45 # calls setter name(f,45) -> TypeError
del f.name # Calls deleter name(f) -> TypeError
In this example, the attribute name is first defined as a read-only property using the @property decorator and associated method.
The @name.setter and @name.deleter decorators that follow are associating additional methods with the set and deletion
operations on the name attribute. The names of these methods must exactly match the name of the original property.
In these methods, notice that the actual value of the name is stored in an attribute
__name
.
(3)
In older code, you will often see properties defined using the
property(getf=None, setf=None, delf=None, doc=None) function with a set of uniquely named methods for carrying out each operation. For example:
class Foo(object):
def getname(self):
return self.__name
def setname(self,value):
if not isinstance(value,str):
raise TypeError("Must be a string!")
self.__name = value
def delname(self):
raise TypeError("Can't delete name")
name =
property(getname,setname,delname)
This older approach is still supported, but the decorator version tends to lead to classes that are a little more polished.
For example, if you use decorators, the get, set, and delete functions aren't also visible as methods.