Some tips about Class in Python

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.





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值