zwd 发表于 2018-8-12 14:23:26

第十三次课:Python类

  在Python中,可以通过class关键字定义自己的类,然后通过自定义的类对象类创建实例对象。如下,创建一个people类,并定义了一个初始化__init__函数。
class people(object):
  '''This is a people>  address=[]
  code='0590'
  def __init__(self,name,age):
  self.name=name
  self.age=age
  属性
  借助这个例子我们来看看Python中类的相关内容。
  在上面的people类中,”address””code””name”和”age”都被称为类的数据属性,但是它们又分为类数据属性和实例数据属性。我们通过一个例子来演示,如下:
people.address.extend(['China','Fujian','Fuzhou'])  print 'Address is %s' %people.address
  people.food=['foutiaoqiao','yuwan','rouyan']
  print 'Food is %s' %people.food
  print dir(people)
  John=people('John',29)
  print '%s is %s year old' %(John.name,John.age)
  John.gender='Man'
  print '%s is %s' %(John.name,John.gender)
  print dir(John)
  John.address.append('hudonglu')
  print John.address
  Wiki=people('Wiki',22)
  print dir(Wiki)
  print Wiki.address
  运行结果:
  Address is ['China', 'Fujian', 'Fuzhou']
  Food is ['foutiaoqiao', 'yuwan', 'rouyan']
  ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'address', 'code', 'food']
  John is 29 year old
  John is Man
  ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'address', 'age', 'code', 'food', 'gender', 'name']
  ['China', 'Fujian', 'Fuzhou', 'hudonglu']
  ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'address', 'age', 'code', 'food', 'name']
  ['China', 'Fujian', 'Fuzhou', 'hudonglu']
  注:通过内建函数dir(),或者访问类的字典属性__dict__可以查看类有哪些属性。如上例子dir(people)
  通过如上例子我们可以归纳几点有关类的特性:
  (1)类数据属性属于类本身,可以通过类名进行访问或修改;如people.address
  (2)类数据属性也可以被类的所有实例访问或修改;如Wiki.address='hudonglu'
  (3)在类定义之后,可以通过类名动态添加类数据属性,新增的类属性也被类和所有实例共有;如
  people.address.extend(['China','Fujian','Fuzhou'])
  (4)实例数据属性只能通过实例访问;如John.gender
  (5)在实例生成后,还可以动态添加实例数据属性,但是这些实例数据属性只属于该实例;如John.gender
  对于所有的类,都有一组特殊的属性:
__name__类的名字(字符串)__doc__类的文档字符串__bases__类的所有父类组成的元组__dict__类的属性组成的字典__module__类所属的模块__class__类对象的类型  通过这些属性,可以得到 people类的一些信息
print people.__name__  print people.__doc__
  print people.__bases__
  print people.__dict__
  print people.__module__
  运行结果:
people
  This is a people>  (<type 'object'>,)

  {'__module__': '__main__', 'code': '0590', 'food': ['foutiaoqiao', 'yuwan', 'rouyan'], 'address': ['China', 'Fujian', 'Fuzhou', 'hudonglu'], '__dict__': <attribute '__dict__' of 'people' objects>, '__weakref__': <attribute '__weakref__' of 'people' objects>, '__doc__': 'This is a people>  __main__
  <type 'type'>
  从上面的介绍了解到,类数据属性属于类本身,被所有该类的实例共享;并且,通过实例可以去访问或修改类属性。但是,在通过实例中访问类属性的时候一定要谨慎,因为可能出现属性”隐藏”的情况。那什么情况下有隐藏呢,下面举例说明:
print people.code  print people.__dict__
  John.code='0722'
  print John.code
  print John.__dict__
  del John.code
  运行结果:
0590
  {'__module__': '__main__', 'code': '0590', 'food': ['foutiaoqiao', 'yuwan', 'rouyan'], 'address': ['China', 'Fujian', 'Fuzhou', 'hudonglu'], '__dict__': <attribute '__dict__' of 'people' objects>, '__weakref__': <attribute '__weakref__' of 'people' objects>, '__doc__': 'This is a people>  0722
  {'gender': 'Man', 'age': 29, 'code': '0722', 'name': 'John'}
  0590
  从上述例子中分析得出如下结论:
  (1)对于类属性people.code,可以通过实例John进行访问,切John.code等同于people.code;
  (2)当通过实例赋值code属性的时候,都将为实例John新建一个code实例属性,这时John.code不等同于people.code;
  (3)当通过”del John.code”语句删除实例的code属性后,John.code又等同于people.code;
  (4)当通过实例修改code属性的时候,将修改John.code指向的内存地址(即people.code),此时John.code又等同于people.code;
  注意,虽然通过实例可以访问类属性,但是,不建议这么做,最好还是通过类名来访问类属性,从而避免属性隐藏带来的不必要麻烦。
  方法
  在一个类中,可能出现三种方法,实例方法、静态方法和类方法,下面来看看三种方法的不同。
  实例方法的第一个参数必须是“self”,实例方法只能通过类实例进行调用,这时候“self”就代表这个类实例本身。通过“self”可以直接访问实例的属性。如下例子:
class people(object):
  '''This is a people>  address=[]
  code='0590'
  def __init__(self,name,age):
  self.name=name
  self.age=age
  def info(self):
  print '%s is %s' %(self.name,self.age)
  John=people('John',29)
  John.info()
  运行结果:
  John is 29
  类方法以cls作为第一个参数,cls表示类本身,定义时使用@classmethod装饰器。通过cls可以访问类的相关属性。
class people(object):
  '''This is a people>  address=[]
  code='0590'
  def __init__(self,name,age):
  self.name=name
  self.age=age
  @classmethod

  def>  print cls.__name__
  print dir(cls)
  people.classinfo()
  John=people('John',29)
  John.classinfo()
  运行结果:
  people
  ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'address', 'classinfo', 'code', 'food', 'info']
  静态方法没有参数限制,既不需要实例参数,也不需要类参数,定义的时候使用@staticmethod装饰器。
class people(object):
  '''This is a people>  address=[]
  code='0590'
  def __init__(self,name,age):
  self.name=name
  self.age=age
  @staticmethod
  def static():
  print people.code
  print people.address
  people.satic()
  John=people('John',29)
  John.static()
  运行结果:
  0590
  ['China', 'Fujian', 'Fuzhou', 'hudonglu']
  三种方法的主要区别在于参数,实例方法被绑定到一个实例,只能通过实例进行调用;但是对于静态方法和类方法,可以通过类名和实例两种方式进行调用。
继承
  在Python中,同时支持单继承与多继承,基础语法如下:

  >  class_suite
  实现继承之后,子类将继承父类的属性,也可以使用内建函数insubclass()来判断一个类是不是另一个类的子孙类。如下例子:
class parent():
  '''This is a parent>  num=[]
  def plus(self,a,b):
  return a+b
  class child(parent):

  '''This is a child>  child.num.extend(xrange(5))
  print child.num
  print '10 + 20 = ',child().plus(10,20)
  print issubclass(child,parent)
  print issubclass(child,object)
  print child.__bases__
  print parent.__doc__
  print child.__doc__
  运行结果:
  10 + 20 =30
  True
  False
  (<class __main__.parent at 0x0000000004E59828>,)

  This is a parent>
  This is a child>  注:注意例子中的文档字符串。文档字符串对于类,函数/方法,以及模块来说是唯一的,也就是说__doc__属性是不能从父类中继承来的。
  当在Python中出现继承的情况时,一定要注意初始化函数__init__的行为。有以下几点需要注意:
  (1)如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。如下例子:
class Parent(object):  def __init__(self, name):
  self.name = name
  print self.name
  class Child(Parent):

  '''This is a child>  c = Child('John Test')
  print c
  Child()
  运行结果:
  Traceback (most recent call last):
  John Test
  File "C:/Users/YangQing/PycharmProjects/Test/class.py", line 81, in <module>
  Child()
  TypeError: __init__() takes exactly 2 arguments (1 given)
  (2)如果子类定义了自己的初始化函数,而没有显示调用父类的初始化函数,则父类的属性不会被初始化
class Parent(object):  def __init__(self, name):
  self.name = name
  print self.name
  class Child(Parent):

  '''This is a child>  def __init__(self):
  print 'This is a self test'
  c = Child()
  print c.name
  运行结果:
This is a self test  Traceback (most recent call last):
  File "C:/Users/YangQing/PycharmProjects/Test/class.py", line 83, in <module>
  print c.name
  AttributeError: 'Child' object has no attribute 'name'
  (3)如果子类定义了自己的初始化函数,显示调用父类,子类和父类的属性都会被初始化
class Parent(object):  def __init__(self, name):
  self.name = name
  print self.name
  class Child(Parent):

  '''This is a child>  def __init__(self):
  print 'This is a self test'

  super(Child,self).__init__('Data from Child>  c = Child()
  运行结果:
  This is a self test

  Data from Child>  从上面的例子中我们通过super()函数调用了父类__init__方法,下面就介绍下super():
  在子类中,一般会定义与父类相同的属性(数据属性,方法),从而来实现子类特有的行为。也就是说,子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的属性和方法。
class Parent(object):
  name = "This is a parent>  def data(self):
  print "This is data from Parent"
  class Child(Parent):

  name = "This is a child>  def data(self):
  print "This is data from child"
  c = Child()
  c.data()
  print Child.name
  运行结果:
This is data from child
  This is a child>  在上述例子中子类的属性”name”和”data”覆盖了父类的属性,所以子类有了自己的行为。但是,有时候可能需要在子类中访问父类的一些属性,这时候,可以通过父类名直接访问父类的属性,当调用父类的方法是,需要将”self”显示的传递进去的方式。
class Parent(object):
  name = "This is a parent>  def data(self):
  print "This is data from Parent"
  class Child(Parent):

  name = "This is a child>  def data(self):
  print "This is data from child"
  print Parent.name
  Parent.data(self)
  c = Child()
  c.data()
  运行结果:
This is data from child
  This is a parent>  This is data from Parent
  这种方式有一个不好的地方就是,需要经父类名硬编码到子类中,为了解决这个问题,可以使用Python中的super关键字:
class Parent(object):
  name = "This is a parent>  def data(self):
  print "This is data from Parent"
  class Child(Parent):

  name = "This is a child>  def data(self):
  print "This is data from child"
  print super(Child, self).name
  super(Child, self).data()
  c = Child()
  c.data()
  运行结果:
  This is data from child

  This is a parent>  This is data from Parent
  对于”super(Child, self).data()”可以理解为,首先找到Child的父类Parent,然后调用父类的data方法,同时将Child的实例self传递给data方法。
页: [1]
查看完整版本: 第十三次课:Python类