第十三次课:Python类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十三次课:Python类相关的知识,希望对你有一定的参考价值。

  在Python中,可以通过class关键字定义自己的类,然后通过自定义的类对象类创建实例对象。如下,创建一个people类,并定义了一个初始化__init__函数。

class people(object):
   ‘‘‘This is a people class‘‘‘
   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 class
(<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 class‘, ‘__init__‘: <function __init__ at 0x0000000005A27B38>}
__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 class‘, ‘__init__‘: <function __init__ at 0x0000000005A27B38>}
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 class‘‘‘
   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 class‘‘‘
   address=[]
   code=‘0590‘
   def __init__(self,name,age):
         self.name=name
         self.age=age
   @classmethod
   def classinfo(cls):
       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 class‘‘‘
   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 SubClassName(ParentClass1 [, ParentClass2, ...]):

     class_suite

  实现继承之后,子类将继承父类的属性,也可以使用内建函数insubclass()来判断一个类是不是另一个类的子孙类。如下例子:

class parent():
   ‘‘‘This is a parent class‘‘‘
   num=[]
   def plus(self,a,b):
       return a+b
class child(parent):
   ‘‘‘This is a child class‘‘‘
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__

运行结果:
[0, 1, 2, 3, 4]
10 + 20 =  30
True
False
(<class __main__.parent at 0x0000000004E59828>,)
This is a parent class
This is a child class

  注:注意例子中的文档字符串。文档字符串对于类,函数/方法,以及模块来说是唯一的,也就是说__doc__属性是不能从父类中继承来的。

  当在Python中出现继承的情况时,一定要注意初始化函数__init__的行为。有以下几点需要注意:

(1)如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。如下例子:

class Parent(object):
   def __init__(self, name):
       self.name = name
       print self.name

class Child(Parent):
   ‘‘‘This is a child class‘‘‘

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 class‘‘‘
   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 class‘‘‘
   def __init__(self):
       print ‘This is a self test‘
       super(Child,self).__init__(‘Data from Child class‘)

c = Child()

运行结果:
This is a self test
Data from Child class

  从上面的例子中我们通过super()函数调用了父类__init__方法,下面就介绍下super():

  在子类中,一般会定义与父类相同的属性(数据属性,方法),从而来实现子类特有的行为。也就是说,子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的属性和方法。

class Parent(object):
   name = "This is a parent class"
   def data(self):
       print "This is data from Parent"

class Child(Parent):
   name = "This is a child class"
   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 class

  在上述例子中子类的属性”name”和”data”覆盖了父类的属性,所以子类有了自己的行为。但是,有时候可能需要在子类中访问父类的一些属性,这时候,可以通过父类名直接访问父类的属性,当调用父类的方法是,需要将”self”显示的传递进去的方式。

class Parent(object):
   name = "This is a parent class"
   def data(self):
       print "This is data from Parent"

class Child(Parent):
   name = "This is a child class"
   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 class
This is data from Parent

这种方式有一个不好的地方就是,需要经父类名硬编码到子类中,为了解决这个问题,可以使用Python中的super关键字:

class Parent(object):
   name = "This is a parent class"
   def data(self):
       print "This is data from Parent"

class Child(Parent):
   name = "This is a child class"
   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 class
This is data from Parent

  对于”super(Child, self).data()”可以理解为,首先找到Child的父类Parent,然后调用父类的data方法,同时将Child的实例self传递给data方法。

本文出自 “DreamScape” 博客,请务必保留此出处http://dyqd2011.blog.51cto.com/3201444/1979215

以上是关于第十三次课:Python类的主要内容,如果未能解决你的问题,请参考以下文章

2018-06-11 第十三次课

第十三次会议

第十三次作业

201621123042《java程序设计》第十三次作业

2021年春季学期-信号与系统-第十三次作业参考答案

第十三次立会暨第六次集体开发