python 系统学习笔记(十)---类
self类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,Python会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。虽然你可以给这个参数任何名称,但是 强烈建议 你使用self这个名称——其他名称都是不赞成你使用的。 Python中的self等价于C++中的self指针和Java、C#中的this参考。你一定很奇怪Python如何给self赋值以及为何你不需要给它赋值。举一个例子会使此变得清晰。假如你有一个类称为MyClass和这个类的一个实例MyObject 。当你调用这个对象的方法MyObject.method(arg1, arg2) 的时候,这会由Python自动转为MyClass.method(MyObject, arg1, arg2) ——这就是self的原理了。这也意味着如果你有一个不需要参数的方法,你还是得给这个方法定义一个self参数。
类对象支持两种操作:属性引用和实例化。
属性引用使用和Python中所有的属性引用一样的标准语法: obj.name
。类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样:
class MyClass: "A simple example class" i = 12345 def f(self): return 'hello world'
那么 MyClass.i
和 MyClass.f
是有效的属性引用,分别返回一个整数和一个方法对象。也可以对类属性赋值,你可以通过给 MyClass.i
赋值来修改它。 __doc__ 也是一个有效的属性,返回类的文档字符串:“A simple example class
”。
类的实例化使用函数符号。只要将类对象看作是一个返回新的类实例的无参数函数即可。例如(假设沿用前面的类):
x = MyClass()
以上创建了一个新的类实例并将该对象赋给局部变量x。
这个实例化操作(“调用”一个类对象)来创建一个空的对象。很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为__init__() 的特殊方法,像下面这样:
def __init__(self): self.data = []
类定义了 __init__() 方法的话,类的实例化操作会自动为新创建的类实例调用 __init__() 方法。所以在下例中,可以这样创建一个新的实例:
x = MyClass()
当然,出于弹性的需要, __init__() 方法可以有参数。事实上,参数通过 __init__()传递到类的实例化操作上。
__init__方法
在Python的类中有很多方法的名字有特殊的重要意义。现在我们将学习__init__ 方法的意义。
__init__ 方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望的 初始
化 。注意,这个名称的开始和结尾都是双下划线。
使用__init__方法
class SayHello: def __init__(self,hellostr): self.data = hellostr def sayHi(self,histr): print 'hi'x=SayHello("hello world")print '%s' %(x.data)x.sayHi('hi')
第一种称作数据属性。这相当于Smalltalk中的“实例变量”或C++中的“数据成员”。和局部变量一样,数据属性不需要声明,第一次使用时它们就会生成
self.data 就是数据属性通常方法是直接调用的:
x.sayHi('hi')
在我们的例子中,这会返回字符串‘hi’
。
继承
当然,如果一种语言不支持继承就,“类”就没有什么意义。派生类的定义如下所示:
class DerivedClassName(BaseClassName): . . .
命名 BaseClassName (示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
class DerivedClassName(modname.BaseClassName):
派生类定义的执行过程和基类是一样的。构造派生类对象时,就记住了基类。这在解析属性引用的时候尤其有用:如果在类中找不到请求调用的属性,就搜索基类。如果基类是由别的类派生而来,这个规则会递归的应用上去。
派生类的实例化没有什么特殊之处:DerivedClassName()
(示列中的派生类)创建一个新的类实例。方法引用按如下规则解析:搜索对应的类属性,必要时沿基类链逐级搜索,如果找到了函数对象这个方法引用就是合法的。
派生类可能会覆盖其基类的方法。因为方法调用同一个对象中的其它方法时没有特权,基类的方法调用同一个基类的方法时,可能实际上最终调用了派生类中的覆盖方法。(对于C++程序员来说,Python中的所有方法本质上都是虚方法。)
派生类中的覆盖方法可能是想要扩充而不是简单的替代基类中的重名方法。有一个简单的方法可以直接调用基类方法,只要调用:“BaseClassName.methodname(self, arguments)”。有时这对于客户也很有用。(要注意的中只有基类在同一全局作用域定义或导入时才能这样用。)
#!/usr/bin/python# Filename: inherit.pyclass SchoolMember: '''Represents any school member.''' def __init__ (self, name, age): self.name = name self.age = age print '(Initialized SchoolMember: %s)' %self.name def tell(self): '''Tell my details.''' print 'Name:"%s" Age:"%s"' % (self.name,self.age),class Teacher(SchoolMember): '''Represents a teacher.''' def __init__ (self, name, age, salary): SchoolMember.__init__(self, name, age) self.salary = salary print '(Initialized Teacher: %s)' % self.name def tell(self): SchoolMember.tell(self) print 'Salary: "%d"' % self.salaryclass Student(SchoolMember): '''Represents a student.''' def __init__ (self, name, age, marks): SchoolMember.__init__(self, name, age) self.marks = marks print '(Initialized Student: %s)' % self.name def tell(self): SchoolMember.tell(self) print 'Marks: "%d"' % self.markst = Teacher('Mrs. Shrividya' , 40, 30000)s = Student('Swaroop', 22, 75)print # prints a blank linemembers = [t, s]for member in members: member.tell() # works for both Teachers and Students
四、运算符重载
重载的关键概念
*运算符重载让类拦截常规的Python运算。
*类可重载所有Python表达式运算。
*类可重载打印,函数调用,属性点号运算等运算。
*重载使类实例的行为像内置类型。
*重载是通过提供特殊名称的类方法来实现的。
如果类中提供了某些特殊名称的方法,当类实例出现在运算有关的表达式的时候,Python就会自动调用这些方法。
1、 常见的运算符重载方法
方法 重载 调用
__init__ 构造器方法 对象建立:X=Class()
__del__ 析构方法 对象收回
__add__ 运算符+ X+Y,X+=Y
__sub__ 运算符- X-Y,X-=Y
__or__ 运算符|(位OR) X|Y X|=Y
__repr__,__str__ 打印,转换 print X【__str__】、repr(X)、str(X)
__call__ 函数调用 X()
__getattr__ 点号运算 X.undefined
__setattr__ 属性赋值语句 X.any=Value
__getitem__ 索引运算 X[key],没有__iter__时的for循环和其他迭代器
__setitem__ 索引赋值语句 X[key]=value
__len__ 长度 len(X),真值测试
__cmp__ 比较 X==Y,X
__lt__ 特定的比较 X<Y(or else __cmp__)
__eq__ 特定的比较 X==Y(or else __cmp__)
__radd__ 左侧加法 + Noninstance + X
__iadd__ 实地(增强的)的加法 X+=Y(or else __add__)
__iter__ 迭代环境 用于循环,测试,列表,映射及其他
所有重载方法的名称前后都有两个下划线字符,以便把同类中定义的变量名区别开来。特殊方法名称和表达式或运算的映射关系,是由Python语言预先定义好的。
所有运算符重载的方法都是选用的:如果没有写某个方法,那么定义的类就不支持该运算。多数重载方法只用在需要对象行为表现得就像内置函数一样的高级程序中。然而,__init__构造方法常出现在绝大多数类中。
__getitem__拦截索引运算
__getitem__方法拦截实例的索引运算。当实例X出现X[i]这样的索引运算中时,Python会调用这个实例继承的__getitem__方法。
(如果有),把X作为第一个参数传递,并且放括号内的索引值传递给第二个参数
python实现 单例模式
#!/usr/bin/env python # -*- coding:utf-8 -*- import os class IOLoop(object): @classmethod def instance(self): if not hasattr(self, "_instance"): self._instance = self() return self._instance @classmethod def initialized(self): """Returns true if the singleton instance has been created.""" return hasattr(self, "_instance") def service(self): print 'Hello,World' print IOLoop.initialized() ioloop = IOLoop.instance() ioloop.service() #if os.fork() == 0:print IOLoop.initialized() ioloop = IOLoop.instance() ioloop.service()
练习题
写一个类继承一个基类
# Creating a class hierarchy with an abstract base class. class Employee: """Abstract base class Employee""" def __init__(self, first, last): """Employee constructor, takes first name and last name. NOTE: Cannot create object of class Employee.""" if self.__class__ == Employee: raise NotImplementedError,"Cannot create object of class Employee" self.firstName = first self.lastName = last def __str__(self): """String representation of Employee""" return "%s %s" % (self.firstName, self.lastName) def _checkPositive(self, value): """Utility method to ensure a value is positive""" if value < 0: raise ValueError,"Attribute value (%s) must be positive" % value else: return value def earnings(self): """Abstract method; derived classes must override""" raise NotImplementedError, "Cannot call abstract method" class Boss(Employee): """Boss class, inherits from Employee""" def __init__(self, first, last, salary): """Boss constructor, takes first and last names and salary""" Employee.__init__(self, first, last) self.weeklySalary = self._checkPositive(float(salary)) def earnings(self): """Compute the Boss's pay""" return self.weeklySalary def __str__(self): """String representation of Boss""" return "%17s: %s" % ("Boss", Employee.__str__(self)) class CommissionWorker(Employee): """CommissionWorker class, inherits from Employee""" def __init__(self, first, last, salary, commission, quantity): """CommissionWorker constructor, takes first and last names, salary, commission and quantity""" Employee.__init__(self, first, last) self.salary = self._checkPositive(float(salary)) self.commission = self._checkPositive(float(commission)) self.quantity = self._checkPositive(quantity) def earnings(self): """Compute the CommissionWorker's pay""" return self.salary + self.commission * self.quantity def __str__(self): """String representation of CommissionWorker""" return "%17s: %s" % ("Commission Worker", Employee.__str__(self)) class PieceWorker(Employee): """PieceWorker class, inherits from Employee""" def __init__(self, first, last, wage, quantity): """PieceWorker constructor, takes first and last names, wage per piece and quantity""" Employee.__init__(self, first, last) self.wagePerPiece = self._checkPositive(float(wage)) self.quantity = self._checkPositive(quantity) def earnings(self): """Compute PieceWorker's pay""" return self.quantity * self.wagePerPiece def __str__(self): """String representation of PieceWorker""" return "%17s: %s" % ("Piece Worker", Employee.__str__(self)) class HourlyWorker(Employee): """HourlyWorker class, inherits from Employee""" def __init__(self, first, last, wage, hours): """HourlyWorker constructor, takes first and last names, wage per hour and hours worked""" Employee.__init__(self, first, last) self.wage = self._checkPositive(float(wage)) self.hours = self._checkPositive(float(hours)) def earnings(self): """Compute HourlyWorker's pay""" if self.hours <= 40: return self.wage * self.hours else: return 40 * self.wage + (self.hours - 40) * self.wage * 1.5 def __str__(self): """String representation of HourlyWorker""" return "%17s: %s" % ("Hourly Worker", Employee.__str__(self)) # main program # create list of Employees employees = [ Boss("John", "Smith", 800.00), CommissionWorker("Sue", "Jones", 200.0, 3.0, 150), PieceWorker("Bob", "Lewis", 2.5, 200), HourlyWorker("Karen", "Price", 13.75, 40) ] # print Employee and compute earnings for employee in employees: print "%s earned $%.2f" % (employee, employee.earnings())