Python中的类与对象

参考文章:7篇文章搞懂Python的类与对象

上面看着是一篇博文,其实是七篇博文,每篇都不长,我觉得对类与对象写得还蛮清楚的,我在此系统整理一下。因为是基于自己的理解进行的排版,所以如果有理解有偏颇的地方,欢迎讨论。

一、关于类与对象的理解

类:可以把“类”当成是制造产品的图纸,或者是一个模具,里面有一些设定好的东西。在进行产品生产时就依照产品图纸与模具进行生产。

对象:依照图纸与模具生产的产品。产品之间大同小异。也称对象是类的实例(instance),可以理解为是概念产品的实例化。

再从一些比较专业的角度谈甚么是对象:

  • 对象是内存中专门用来存储数据的一块区域。
  • 对象中可以存放各种数据(比如:数字、布尔值、代码)
  • 对象由三部分组成:

    1.对象的标识(id)
    2.对象的类型(type)
    3.对象的值(value)

常规开发中,我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名。

二、简单案例

类的基本结构

class 类名([父类]):
    代码块

1. 定义一个最简单基础的类

class MyClass():
    pass

print(MyClass)

这个类里面甚么都没有,所以也就不会输出甚么有用信息。

2. 定义好类之后就可以创建对象

mc = MyClass() # mc就是通过MyClass创建的对象,mc是MyClass的实例

print(mc)

mc就是我们用Myclass这个模具创造出来的一个实际产品(对象)。因为这个模具里面啥都没有,所以这个产品实际上也是啥都没有。

听起来有点玄学,那么我们来创建一个有东西的类试一下。不过在创建有东西的类之前,我们需要知道两个东西——变量与函数。

三、变量与方法

在类的代码块中,我们可以定义变量和函数。

定义变量

变量会成为该类实例的公共属性,所有的该类实例都可以通过以下形式访问: 对象.属性名

class Person :
    name = 'swk'

#再创建对象p1与p2,此时p1与p2中的值一模一样
p1 = Person()
p2 = Person()
print(p2.name)#访问的是‘swk’
print(p2.name)#访问的是‘swk’

此时name为公共属性,所有实例都可以访问。比如 p2.name 访问的就是swk这样一个名字。( p1.name 访问的也是这一个名字)

定义方法

在类中也可以定义函数,类中的定义的函数,我们称为该类实例的公共方法。所有的该类实例都可以通过以下形式访问: 对象.方法名() 

class Person :
    name = 'swk'

#如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参。所以要在方法say_hello()中定义一个参数,在括号里面定义一个占位用的a也行。
    def say_hello(self) :
        print('你好!')

#再创建对象p1与p2,此时p1与p2中的值一模一样
p1 = Person()
p2 = Person()
#print(p2.name)
#调用方法:对象.方法名
p1.say_hello() # p1调用方法say_hello()

总结:p1与p2是制造出来的两个产品,依照“Person”这个类制造出来的,两个此时是一模一样的东西。

四、个性化定制

这是我自己瞎取的名。

不过我们已经了解到一个类,可以制造出很多相同的对象。但是我们开始思考一个问题,就是我利用类创造出的对象,他就必须得是一模一样吗?当然不是啦小笨蛋,每一个对象也可以建立一个自己的独有属性。

class Person:
    def say_hello(self):
        print("你好")

p1 = Person()
p2 = Person()
# p1.say_hello()
p1.name = "孙悟空"
print(p1.name)

可以看见name这个属性在Person的类里面并没有,是之后我们自己给p1这个对象创建的,是p1特有的,如果输出 print(p2.name) 是会报错的,因为对象p2中没有这个name属性。

当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性,如果有,则直接返回当前的对象的属性值;如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值,如果没有则报错!

关于放在类里与个性化定制一点提醒:

如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中;
如果这个属性(方法)是某个实例独有,则应该保存到实例对象中。

 五、类的特殊方法init

在介绍init之前,我们先来看之前提到的,在设定方法时必须设定的那一个参数。

关于在方法中必须设定的参数方法每次被调用时,解析器都会自动传递第一个实参,其实第一个参数,就是调用方法的对象本身。示例代码和注释如下:

class Person :
    name = 'swk' 
    def say_hello(self) :
        #   如果是p1调的,则第一个参数就是p1对象
        #   如果是p2调的,则第一个参数就是p2对象
        # 一般我们都会将这个参数命名为self
      '''
say_hello()这个方法,可以显示如下格式的数据:
       你好!我是 xxx
注意:在方法中不能直接访问类中的属性,此处只写name是会报错的,所以要通过`self.name`的形式:
     '''
        print('你好!我是 %s' %self.name)

# 创建Person的实例
p1 = Person()
p2 = Person()

# 修改p1的name属性
p1.name = '猪八戒'
p2.name = '沙和尚'

p1.say_hello() # '你好!我是 猪八戒'
p2.say_hello() # '你好!我是 沙和尚'

上面的例子表明,对于类一开始所具有的属性,在建立对象后,我们可以通过 对象.属性 方法调用进行修改。

不过在一开始,我们也可以不在类中设立属性,仅仅设立方法。此时方法中使用的属性,需要在创建对象后再利用 对象.属性 对属性赋值。

class Person:
    def say_hello(self):
        print("你好,我是%s" % self.name)

p1 = Person()
p2 = Person()
# p1.say_hello()
p1.name = "孙悟空"
p1.say_hello()

此时如果输出 p2.say_hello() 是会报错的。

但是对于Person类来讲,name是必须的。由于每一个对象的name属性基本上都不同。

我们采取的解决方法是在建立对象后,手动将name属性添加到对象中,这种方法很容易出错,可能会忘记赋值,致使有些对象没有name属性,产生错误。

更好的解决方法:在设置对象的时候就必须建立name属性,如果不设置,则无法建立对象。并且属性的创建应该是自动完成的,不是在创建对象之后手动完成。

在类中可以定义一些特殊方法(魔术方法),特殊方法都是以__开头,__结尾的方法,特殊方法不需要我们自己调用。不要尝试去调用特殊方法,特殊方法将会在特殊的时刻自动调用。

init就是Python的一种特殊方法,会在对象创建之后立刻执行,可以用来向新创建的对象中初始化属性。

调用类创建对象时,类后面的所有参数都会自动一次传递到init()中。

class Person :
    def __init__(self,name):
        # 通过self向新建的对象中初始化属性
        self.name = name

    def say_hello(self):
        print('大家好,我是%s'%self.name)

p1 = Person('孙悟空')
p2 = Person('猪八戒')
p3 = Person('沙和尚')
p4 = Person('唐僧')


p4.say_hello()

此时就完成了强制赋值,因为如果不给传递name的话就会报错

总结一下,类的基本结构:

class 类名([父类]) :

        公共的属性...

        # 对象的初始化方法
        def __init__(self,...):
            ...

        # 其他的方法    
        def method_1(self,...):
            ...

        def method_2(self,...):
            ...

        ...

在原博文的第七篇博文中有一个小狗的例子,感兴趣的可以试一下。

posted @ 2021-03-02 15:14  不知天高地厚的小可爱  阅读(318)  评论(0编辑  收藏  举报
1