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 易做图 example class"
i = 12345
def f(self):
return 'hello world'
那么 MyClass.i 和 MyClass.f 是有效的属性引用,分别返回一个整数和一个方法对象。也可以对类属性赋值,你可以通过给 MyClass.i 赋值来修改它。 __doc__ 也是一个有效的属性,返回类的文档字符串:“A 易做图 example class”。
类的实例化使用函数符号。只要将类对象看作是一个返回新的类实例的无参数函数即可。例如(假设沿用前面的类):
x = MyClass()
以上创建了一个新的类实例并将该对象赋给局部变量x。
这个实例化操作(“调用”一个类对象)来创建一个空的对象。很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为__init__() 的特殊方法,像下面这样:
def __init__(self):
self.data = []
类定义了 __init__() 方法的话,类的实例化操作会自动为新创建的类实例调用 __init__() 方法。所以在下例中,可以这样创建一个新的实例:
x = MyClass()
当然,出于弹性的需要, __init__() 方法可以有参数。事实上,参数通过 __init__()传递到类的实例化操作上。
__init__方法
在Python的类中有很多方法的名字有特殊的重要意义。现在我们将学习__init__ 方法的意义。
__init__ 方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望的 初始
化 。注意,这个名称的开始和结尾都是双下划线。
使用__init__方法
[python]
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)”。有时这对于客户也很有用。(要注意的中只有基类在同一全局作用域定义或导入时才能这样用。)
[python]
#!/usr/bin/python
# Filename: inherit.py
class 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.salary
class 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)