【学习记录】Python3版本(6:面向对象的编程)
对象?哪有对象?
编程方法分为面向对象和面向过程两种。我也不知这两种具体有啥子区分。可能就是面向对象的时候,你面对的是“一类”的概念。
据百度百科,个人理解这两种区分,可能是:面向过程就是描述你的细胞与细胞之间的关系,他们很难独立存在;面向对象就是描述你和你的亲人朋友的关系。
看了知乎之后更蒙逼了。那我还是按照我的方式去理解吧......
Class-Instance即类-实例。差不多就是,你们班-你的关系。
数据封装、继承和多态是面向对象的三大特点。
类和实例
class Student(object):
- Student是类的名字,类名通常用大写开头
- (object)讲的是它从何处继承而来。如果没有合适的类别,就当他是object类继承的就没错了。
def __init__(self,name,score):
self.name=name
self.score=score
- 类可以起到模板的作用,可以把一些必要的属性其强制填写。通过定义一个特殊的__init__方法
- __init__第一个参数永远是"self",因为self指向创建的实例它本身
=====
>>>bart=Student('Bart',59)
- 类中定义的函数,除了不用传入实例变量本身之外,其他与普通函数一致
>>> bart=Student()
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module> bart=Student()
TypeError: __init__() missing 2 required positional arguments: 'name' and 'score
- 你必须传入name和score才能创建这个对象实例
数据封装
#普通函数打印Student内部的数据
def print_score(std):
print('%s:%s' %(std.name , std.score))
>>>print_score(bart)
# ====
#将上面的函数移到类定义中
>>>bart.print_score()
#正常打印
>>> print_score(bart)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>print_score(bart)
NameError: name 'print_score' is not defined
#不能用调用函数的方式直接调用print_score相当于节省了一个函数名(?)
数据封装的方法,能节省一个函数名,但是更多的只能说是,额,可能和模块化差不多吧,感觉并没有什么太大的差别。
也许差别只在于模块封装的是功能以及少量的必须数据,而类封装了数据、操作。
此外,即使我们定义了类里面必须要有name和score,但并不妨碍人们向类里的变量传入新的参数,比如age等。同时,它也允许同一个类中的不同实例拥有不同的其他参数。
访问限制
将变量前面加双下划线,就可以一定程度上限制外部对变量的访问。
def __init__(self,name,score):
self.__name=name
self.__score=score
#并在后面加上访问和修改的函数
这样,一定程度上保证了如果我们不提供入口以供调用,那么各个学生的分数就是难以被外部调用直接更改的,保证了数据的私密性。
但是个人认为一般的数据并不要求过高的独立性。
继承和多态
定义class时,相当于定义了一种数据类型,是与'list'同等级的存在,同样可以使用例如isinsitance(a,animal)
来盘它。
同时,在定义一个类的时候,可以指明它继承自哪个类。
class Pupil(Student):
此时,Pupil这个类别已经完美继承了我们的Student的属性,比如说一样需要两个属性,姓名及成绩,一样的有set_grade()
函数。
子类别的数据可以看成父类别的数据,但是父类别的数据不能看做子类别的数据。
但如果子类别的set_grade()
想拥有特殊的操作,python会执行子类别(Subclass)中的函数,而非父类别(Base class/Super class)的函数。
也因此,在Student这个类别中我们实现了多态性。只要他是Student一员,不论它是Pupil(小学生)还是中学生、大学生,他们都能调用Student的函数,同时,还可以有自己的修改。而在外部命令时,我们只需要一个函数:get_score()
。
image
有被笑到hhhhhhh,这位大哥很强。
获取类别数据
type(a)
isinstance(bart,Student)
dir('ABC')
- dir是将对象的所有属性和方法列出来。
-
注意到idel返回的list中有'__len__'和'lower'
-
'__len__'可以直接调用比如
'ABC'.__len__
等价于len('ABC')
。而len('ABC')
本身也是通过调用类中的__len__方法来实现操作的。因此,我们的类中也可以通过'len'来自定一个函数,在外部直接通过len()函数来直接调用。 -
dir是真的很好用,建议像我这样的菜鸟多用!
获取属性数据
>>> setattr(bart,'number',2017112987)
#直接插入学号变量
>>> hasattr(bart,'__name')
False
#由于之前定义的是私密变量,因此此时'name'无法访问
>>> hasattr(bart,'number')
True
>>> getattr(bart,'number',404)
2017112987
#判断该数据中是否有学号,然后将之返回,如果不存在,则返回404
实例属性和类属性
[图片上传失败...(image-30ee44-1583058980225)]
在类定义的变量居然是个公共变量,类似C的static局部变量实际可以等同全局变量的味道,只有在构造函数中的变量才是C++意义上的类变量。更混乱的是实例居然可以随时自己添加删除变量,造成每个实例的成员数量都不一样多,而且是很随意的隐士添加!!! PY类知识系统严格说有三种变量,C++只有一种变量。PY简直是太随意太没有约束了,灵活是很灵活,但是感觉太混乱太容易被人弄出问题还不好查了,如果故意卖弄这些特点,在函数结构上也随意,不做注释粗看简直是混沌,可以绕晕别人。
我不能同意更多。
class里面可以定义一个属于它的变量,比如说在Student中加一个count计算学生人数。
访问时应当使用Student.count
。
同时,Student中的一个实例如bart自己也可以有count属性。当bart有count属性时,bart.count返回的是它自己的count。如果bart没有count属性,那么返回的就是Student的实例属性了。