首页
学习
活动
专区
圈层
工具
发布
30 篇文章
1
【愚公系列】2021年12月 Python教学课程 01-全方位解读Python
2
【愚公系列】2021年12月 Python教学课程 02-变量
3
【愚公系列】2021年12月 Python教学课程 03-数据类型
4
【愚公系列】2021年12月 Python教学课程 04-字符串
5
【愚公系列】2021年12月 Python教学课程 05-列表List
6
【愚公系列】2021年12月 Python教学课程 06-元组Tuple
7
【愚公系列】2021年12月 Python教学课程 07-字典Dict
8
【愚公系列】2021年12月 Python教学课程 08-基本语法
9
【愚公系列】2021年12月 Python教学课程 09-流程控制-顺序执行
10
【愚公系列】2021年12月 Python教学课程 10-流程控制-条件判断
11
【愚公系列】2021年12月 Python教学课程 11-流程控制-循环控制
12
【愚公系列】2021年12月 Python教学课程 12-Python函数
13
【愚公系列】2021年12月 Python教学课程 13-变量作用域
14
【愚公系列】2021年12月 Python教学课程 14-递归函数
15
【愚公系列】2021年12月 Python教学课程 15-匿名函数
16
【愚公系列】2021年12月 Python教学课程 16-推导式
17
【愚公系列】2021年12月 Python教学课程 17-模块与包
18
【愚公系列】2021年12月 Python教学课程 18-异常处理
19
【愚公系列】2021年12月 Python教学课程 19-面向对象编程-面向对象定义
20
【愚公系列】2021年12月 Python教学课程 20-面向对象编程-类和对象
21
【愚公系列】2021年12月 Python教学课程 21-面向对象编程-特殊成员和魔法方法
22
【愚公系列】2021年12月 Python教学课程 22-面向对象编程-封装、继承、多态
23
【愚公系列】2021年12月 Python教学课程 23-面向对象编程-运算符重载
24
【愚公系列】2021年12月 Python教学课程 24-Python数据库编程
25
【愚公系列】2021年12月 Python教学课程 25-Python文件读写
26
【愚公系列】2021年12月 Python教学课程 26-系统编程
27
【愚公系列】2021年12月 Python教学课程 27-算法
28
【愚公系列】2021年12月 Python教学课程 28-Web开发基础
29
【愚公系列】2021年12月 Python教学课程 29-MVC设计模式
30
【愚公系列】2021年12月 Python教学课程 30-Django简介

【愚公系列】2021年12月 Python教学课程 20-面向对象编程-类和对象

文章目录

一、类和对象

类,英文名字 Class,有“类别”,“分类”,“聚类”的意思。必须牢记类是抽象 的模板,用来描述具有相同属性和方法的对象的集合,比如 Animal 类。而实例是根据 类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 能不同。

1. 类的构成

类(class)由 3 个部分构成

  • 类的名称:类名
  • 类的属性:一组数据
  • 类的方法:允许对类进行操作的方法

例如:

“人”这个类: 名称:人(Person) 属性:名字(name),年龄(age),性别(gender) 方法:走(walk),讲话(speak)

“猫”这个类: 名称:猫(cat) 属性:品种(category),毛色(color),名字(name) 方法:叫(meow),跑(run),抓老鼠(catch_rat)

2. 类的抽象

拥有相同(或类似)属性和行为的对象都可以抽象出一个类

3. 定义类

Python 使用 class 关键字来定义类,其基本结构如下:

代码语言:javascript
复制
class 类名(父类列表):
    属性列表 
    方法列表

类名通常采用驼峰式命名方式,尽量让字面意思体现出类的作用。Python 采用多继承机制,一个类可以同时继承多个父类(也叫基类、超类),继承的基类有先后顺序,写在类名后的圆括号里。继承的父类列表可以为空,此时的圆括号可以省略。但在Python3 中,即使没有显式继承任何父类的定义了一个类,它也默认继承 object 类。因为,object 是 Python3 中所有类的基类。

下面是一个学生类:

代码语言:javascript
复制
class Student:
    classroom = '101'
    address = 'beijing' 
    def __init__(self):
        print('a student crreated')
    def intro(self):
        print('hello')

4. 创建对象

python 中可以根据已经定义的类去创建出一个个对象,创建对象的格式为:

代码语言:javascript
复制
对象名 = 类名()

例如,创建一个学生对象:

代码语言:javascript
复制
stu1 = Student()

访问对象的属性和方法:

代码语言:javascript
复制
print(stu1.classroom)
print(stu1.address)
stu1.intro()

默认情况下,使用类似 obj=Student()的方式就可以生成一个类的实例。但是,通常每个类的实例都会有自己的实例变量,例如 name 和 age,为了在实例化的时候体现实例的不同,Python 提供了一个 def init(self):的实例化机制。任何一个类中,名字为__init__的方法就是类的实例化方法,具有__init__方法的类在实例化的时候,会自动调用该方法,并传递对应的参数。比如:

代码语言:javascript
复制
class Student:
    classroom = '101'
    address = 'beijing' 
    def __init__(self,name, age):
        self.name = name
        self.age = age
    def print_age(self):
        print('%s: %s' % (self.name, self.age))
li = Student("李四", 24)
zhang = Student("张三", 23)

5. init(): 方法

由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,age 等属性绑上去(上面的例子)。

需要注意:

  • 创建对象时,__init__方法会立刻被默认调用,不需要手动调用
  • __init__方法的第一个参数永远是 self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到 self,因为 self 就指向创建的实例本身
  • 有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但 self不需要传,Python 解释器自己会把实例变量传进去

6. 实例变量和类变量

类变量:

定义在类中,方法之外的变量,称作类变量。类变量是所有实例公有的变量,每一个实例都可以访问、修改类变量。在 Student 类中,classroom 和 address 两个变量就是类变量。可以通过类名或者实例名加圆点的方式访问类变量,比如:

代码语言:javascript
复制
Student.classroom
Student.address
li.classroom
zhang.address

实例变量:

实例变量指的是实例本身拥有的变量。每个实例的变量在内存中都不一样。Student 类中__init__方法里的 name 和 age 就是两个实例变量。通过实例名加圆点的方式调用实例变量。

我们打印下面四个变量,可以看到每个实例的变量名虽然一样,但他们保存的值却是各自独立的:

代码语言:javascript
复制
print(li.name)
print(li.age)
print(zhang.name)
print(zhang.age)
------------------------
李四
24
张三
23

在使用实例变量和类变量的时候一定要注意,使用类似 zhang.name 访问变量的时候,实例会先在自己的实例变量列表里查找是否有这个实例变量,如果没有,那么它就会去类变量列表里找,如果还没有,弹出异常。

7. 类的方法

在类的内部,使用 def 关键字来定义一个方法。

与一般函数定义不同,类方法至少包含一个 self 参数,且为第一个参数。执行类方法时,会自动将调用该方法的实例赋值给 self。self 代表的是类的实例,而非类本身。self 不是关键字,而是 Python 约定成俗的命名,你完全可以取别的名字,但不建议这么做。

例如,我们前面 Student 类中的 print_age()就是类的方法:

代码语言:javascript
复制
def print_age(self):
    print('%s: %s' % (self.name, self.age))
# --------------------------
# 调用方法
li.print_age()
zhang.print_age()

8. 成员保护和访问限制

在类的内部,有各种变量和方法。这些数据成员,可以在类的外部通过实例或者类名进行调用,例如:

代码语言:javascript
复制
class Student:
    classroom = "101"
    address=“Beijing”
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def print_age(self):
        print('%s: %s' % (self.name, self.age))
obj = Student("jack", 12)
obj.age = 18
obj.print_age()
print(People.title)

上面的调用方式是我们大多数情况下都需要的,但是往往我们也不希望所有的变量和方法能被外部访问,需要针对性地保护某些成员,限制对这些成员的访问。这样的程序才是健壮、可靠的,也符合业务的逻辑。

在类似 JAVA 的语言中,有 private 关键字,可以将某些变量和方法设为私有,阻止外部访问。但是,Python 没有这个机制,Python 利用变量和方法名字的变化,实现这一功能。

在 Python 中,如果要让内部成员不被外部访问,可以在成员的名字前加上两个下划线__,这个成员就变成了一个私有成员(private)。私有成员只能在类的内部访问,外部无法访问。

代码语言:javascript
复制
class Student:
    classroom = "101"
    address="Beijing"
    def __init__(self, name, age):
        self.__name = name
        self.__age = age
    def print_age(self):
        print('%s: %s' % (self.__name, self.__age))
obj = Student("jack", 18)
obj.__name
------------------------------
Traceback (most recent call last):
 File "F:/Python/pycharm/201705/1.py", line 68, in <module>
 obj.__name
AttributeError: 'People' object has no attribute '__name'

那外部如果要对__name 和 __age 进行访问和修改呢?在类的内部创建外部可以访问的 get 和 set 方法!

代码语言:javascript
复制
class Student:
    classroom = "101"
    address=‘Beijing’
    def __init__(self, name, age):
        self.__name = name
        self.__age = age
    def print_age(self):
        print('%s: %s' % (self.__name, self.__age))
    def get_name(self):
        return self.__name
    def get_age(self):
        return self.__age
    def set_name(self, name):
        self.__name = name
    def set_age(self, age):
        self.__age = age
obj = Student("jack", 18)
obj.get_name()
obj.set_name("tom")

这样做,对数据进行了保护的同时也提供了外部访问的接口,而且在get_name,set_name 这些方法中,可以额外添加对数据的检测、处理、加工、包裹等等各种操作。

比如下面这个方法,会在设置年龄之前对参数进行检测,如果参数不是一个整数类型,则抛出异常。

代码语言:javascript
复制
def set_age(self, age):
    if isinstance(age, int):
        self.__age = age
    else:
        raise ValueError

此外,有些时候,你会看到以一个下划线开头的成员名,比如_name,这样的数据成员在外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的标识符时,意思就是,“虽然我可以被外部访问,但是,请把我视为私有成员,不要在外部访问我!”。

还有,在 Python 中,标识符类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊成员,特殊成员不是私有成员,可以直接访问,要注意区别对待。同时请尽量不要给自定义的成员命名__name__或__iter__这样的标识,它们都是Python 中具有特殊意义的魔法方法名。

总结

  • name、name、name:建议性的私有成员,不要在外部访问。
  • __name、 _name :强制的私有成员,但是你依然可以蛮横地在外部危险访问。
  • name:特殊成员,与私有性质无关,例如__doc__。
  • name_、name__:没有任何特殊性,普通的标识符,但最好不要这么起名。
下一篇
举报
领券