学习python类需要注意的知识点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/magic_wz/article/details/78811485

前言

面向对象的编程离不开类,通过对类进行实例化,创建出了对象,关于PYTHON类也存在一些知识点或难点需要重点学习和讨论,本文主要从以下几个方面进行讨论:
1. 基本特性
2. 属性的种类和作用域
3. 方法的种类和区别
4. 关于对多态的理解
5. 继承和重写的问题
6. 多继承

基本特性

使用class,类中定义类的属性和方法,基本形态如下:

class Person:
    count = 0
    def __init__(self,name):
        self.name = name
    def work(self):
        print "work work"

有了类之后,就可以通过类创建对象了,类的基本特性:封装、继承、和多态。
封装比较好理解,把属性和方法封装在类中,通过类来描述具体事物。
继承,通过类创建的对象,就拥有了类的属性和方法,也可以通过类派生出子类,子类可以继承父类的属性和方法。
多态的概念不太容易说清楚,这个放在下面再讨论。

属性的种类和作用域问题

属性分为:
- 实例属性
- 类属性

类属性

有些书中叫实例变量或者类变量。例如上一节代码中的count就是类属性,类属性存在于类作用域,类作用域中的属性特点:
1. 可被类访问
2. 可被所有实例访问
3. 可被屏蔽
例如:

class Person:
    count = 0
    def __init__(self,name):
        self.name = name
    def increase(self):
        Person.count += 1
    def work(self):
        print "work work"

操作如下:

 p1 = Persion("zhangsan")
 p1.increase()
 p2 = Persion("lisi")
 p2.increase()
 print Persion.count
 print p1.count

可见,可以被类和实例访问,如果执行

p1.count = 10
print p1.count
print Person.count

可见类的count被p1的count屏蔽了

实例属性

实例属性比较简单了,就是在实例中使用,Person类的name就是实例属性,通常在构造函数中用self.XXX来声明

私有

方法的种类和区别

这里说的方法指的是在类中定义的方法,包括:
1. 实例方法
2. 静态方法
3. 类方法
4. 构造函数

实例方法

类中定的参数中有(self)的方法,区分于函数
例如Person中的increase(self)方法
假如increase()方法参数中什么都不写,虽然代码不报错,但是似乎这样的方法也用不了,

>>> class Person:
...     def aaa():
...         print "a"
...
>>> Person.aaa()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method aaa() must be called with Person instance as first argument (got nothing instead)
>>> p = Person()
>>> p.aaa()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: aaa() takes no arguments (1 given)

类方法

用@classmethod装饰的方法是类方法,例如
class Person:
count = 0
@classmethod
def cmeth(cls):
print cls.count
等同于:
class Person:
count = 0
def cmeth(cls):
print cls.count
cmeth = classmethod(cmeth)

静态方法

用@staticmethod装饰的方法是静态方法,参数里为空,不用写东西,例如:

class Person:
… @staticmethod
… def smeth():
… print “static method”
这有啥用?我觉得似乎就是定义在类中的函数,似乎用函数也可以替代它的功能。

这三种方法对比

主要区别在于参数。实例方法隐含的参数为类实例self,而类方法隐含的参数为类本身cls。
静态方法无隐含参数

构造函数

init() 来做
就不多说了

继承和重写的问题

继承,看下面例子:

class Person:
    def __init__(self,name):
        self.name = name
class Student(Person):
    pass

class Teacher(Person):
    def __init__(self,age):
        self.age = age

s = Student("zhangsan")
print s.name 

t = Teacher(30)
print t.name

输出s.name,可见学生类继承了父类的name属性,但是Teacher由于重新写构造函数,导致丢失了name属性,这就引发了错误
继承父类构造函数的写法
所以如果需要重写构造函数,则需要继承父类构造函数,否则父类中的实例属性不被继承可能会出错,写法如下:
第一种方法:

class Teacher(Person):
    def __init__(self,name,age):
        Person.__init__(self,name)
        self.age = age


t = Teacher("lisi",30)
print t.name

显式调用父类构造函数,可以解决问题,或者使用第二种方法,用super

class Person:
    def __init__(self,name):
        self.name = name

class Teacher(Person):
    def __init__(self,name,age):
        super(Teacher,self).__init__(name)
        self.age = age

t = Teacher("lisi",30)
print t.name

用super后发现报错,

Traceback (most recent call last):
  File "/Users/wz/class_python.py", line 10, in <module>
    t = Teacher("lisi",30)
  File "/Users/wz/class_python.py", line 7, in __init__
    super(Teacher,self).__init__(name)
TypeError: super() argument 1 must be type, not classobj

这里需要注意,使用super,父类必须有继承的类,如果没有就用object
修改为:

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

这样就ok了,两种方法的区别?
建议使用super,在处理多继承时候会更加智能一点。

再谈多态

继承和封装都比较容易理解,那么多态应该怎么理解?
多态从字面意思看,就是多种形态,我觉得多态可能体现在多个方面,
例如,person类继承出student和teacher,这是不是也算person的多种形态,属于多态的范畴吧
比如方法重新后,又是多种形态
又如list dict都有len函数,算不算多态?
使用+可以运算多种类型,是不是属于运算符都多态?
所以,我觉得多态可能体现在方方面面,有了类和继承,自然就出现类多态

多继承

指的是一个子类继承多个父类,这个在java种我记得似乎是不允许的,不过java种可以实现多个接口
这里要注意,先继承的父类的方法优先生效
关于类中需要注意的知识点先写这么多,感觉有可能没有总结全,等想到了再补充吧

参考:

关于Python类属性与实例属性的讨论 http://python.jobbole.com/85100/
python super用法:
https://www.cnblogs.com/wjx1/p/5084980.html

猜你喜欢

转载自blog.csdn.net/magic_wz/article/details/78811485