2.4.1Python-类基础

总目录:https://blog.****.net/qq_41106844/article/details/105553392

Python - 子目录:https://blog.****.net/qq_41106844/article/details/105553333

 

 

类是用来描述具有相同的属性和方法的对象的集合。

 

如何定义一个类

类代码块以class关键字开头,后紧接类标识符。类标识符通常是大写开头的单词。

类内容以冒号起始,并且缩进。

 

类的描述

类包含属性和方法

一个对象的特征称为"属性",一个对象的行为称为"方法"。属性在代码层面上来看就是变量,方法实际就是函数,通过调用这些函数来完成某些工作

在类中定义方法的形式和函数差不多,但其不称为函数,而是叫方法。方法的调用需要绑定到特定的对象上(通过self.),而函数不需要。

 

语法格式

class  ClassName:

    语法块

 

类的使用

类的使用分两种方式,分别是属性引用和实例化。

属性引用

例子

class My:

    i = 123

    def a(self):

        return 'hello world'

 

# 访问类的属性和方法

 

print(My.i)

print(My.a())

 

123

hello world

如果要引用对象里的方法和属性,使用点操作符( . )即可。

My.i用于调用类的属性,也就是我们前面所说的类变量;My.a()用于调用类的方法。

 

属性引用相当于直接去类中调用需要调用的属性和方法,但是此时的类还是一个类,还不是一个对象,还不能进行复杂的对象操作,只能简单的调用。那么为了让类变成对象,需要进行类的实例化。

 

类实例化

我们在上一个例子上扩展

class My:

    i = 123

    def a(self):

        return 'hello world'

x = My()        #类的实例化

# 通过实例化的对象访问类的属性和方法

print(x.i)

print(x.a())

 

123

hello world

在未实例化类前,只是定义了对象的属性和方法,此时其还不是一个完整的对象。

将定义的这些称为类。需要使用类来创建一个真正的对象,这个对象就叫做这个类的一个实例,也叫作实例对象。(一个类可以有无数个实例)

创建一个对象也叫做类的实例化,即x = My()。(此时得到的x变量称为类的具体对象)

注意此时类名后面是跟着小括号的,这跟调用函数一样。

需要先创建好实例再进行类的实例化。

 

知识点扩展

类中定义方法的要求

在类中定义方法时,除第一个参数必须是self外,类的方法和普通的函数没有区别。

在类中调用方法的要求

调用一个方法,在实例变量上直接调用即可。除了self不用传递,其他参数正常传入

类和对象的区别

类是一个抽象的概念,对象则是一个具体的东西。

我们说小明有两个眼睛,一个嘴巴,两条腿,一个脑袋,但是这些只是我们对小明的形容。如果我们说:有两个眼睛,一个嘴巴,两条腿,一个脑袋的东西是小明,这就是类的实例化。

在举一个例子,楼房的设计图就是类,通过设计图使用钢筋混凝土盖出来的东西才是楼房。

类是对对象的描述,对象是类的具体实现。

self是什么

self其实就相当于C++中的this指针

我们通过小明的例子再拓展,小明有两条腿,他如果要行走,必须要分的清左右腿,那么self就相当于与一个标识,一个能让小明分得清他用的是左腿还是右腿的标识。

如果一个类中有很多一样的方法,那么这些方法可以理解为楼房中的房间,self就是门牌号。

python的self参数就是这样一个道理,同一个类可以生成无数对象,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,那么python就知道需要操作哪个对象的方法了。

 

继承

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

我们先定义一个动物类 Animal,让他有一个run方法:

class Animal(object):

    def run(self):

        print('Animal is running...')

之后我们定义两个类,分别是猫类和狗类,让他们直接继承Animal。

class Animal(object):   

     def run(self):       

         print('Animal is running...')  

 

class Dog(Animal):

    pass

 

class Cat(Animal):

    pass

对于他们来说,Animal就是他们的父类,他们就是Animal的子类。

继承最大的用途是子类能够拥有父类的所有属性和方法。

dog = Dog()

dog.run()

Animal is running...

cat = Cat()

cat.run()

Animal is running...

 

但是不管我们dog.run()或者cat.run(),出来的都是Animal is running...,所以我们需要重新定义Dog和Cat的run方法。

class Animal(object):

    def run(self):

        print('Animal is running...')

 

class Dog(Animal):

    def run(self):

        print('Dog is running...')

 

class Cat(Animal):

    def run(self):

        print('Cat is running...')

 

dog = Dog()

dog.run()

Dog is running...

cat = Cat()

cat.run()

Cat is running...

我们重新在子类中定义了run方法,子类的run方法会覆盖掉他继承父类的run方法。

 

多态

多态用大白话来说,就是这个量有多重状态,举个例子

小明是第三小学的学生,同样他是北京人。小明就有个多个身份,这就是多态。

class Animal(object):

    def run(self):

        print('Animal is running...')

 

class Dog(Animal):

    def run(self):

        print('Dog is running...')

 

class Cat(Animal):

    def run(self):

        print('Cat is running...')

 

a = Animal()# b是Animal类型

d = Dog()# c是Dog类型

 

print(isinstance(a, Animal))

print(isinstance(d, Dog))

print(isinstance(d, Animal))

True 

True 

True 

d不仅是Dog类型,也是Animal类型。

对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定。

这就是多态真正的威力:

调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。

这就是著名的“开闭”原则:

对扩展开放:允许新增Animal子类;

对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。

 

类变量和实例变量

我们先看一个例子

class My2:

    def setname(self,name):

        self.name = name

    def kick(self):

        print("我是%s" % self.name)

 

a = My2()

b = My2()

c = My2()

 

a.setname("A")

b.setname("B")

c.setname("C")

print(a.kick())

print(b.kick())

print(c.kick())

我是A

我是B

我是C  

从上面例子可以看出,有Ball类生成了三个实例对象a,b,c,这三个对象在调用kick()方法时,是通过self参数去确定究竟当前是哪个对象在调用方法的。因此在写类方法时一定要写self参数且其位置在第一个。

 
2.4.1Python-类基础
 

实例变量是每个实例都独有的数据,而类变量是该类所有实例共享的属性和方法

即某个属性对于每个实例都是独有的,就需要将其定义为实例变量;是每个实例同共有的就可以定义为类属性

 

实例

class Dog:

    dress ="china"    

    def __init__(self,name):

            self.name = name

 

x = Dog()

TypeError: __init__() missing 1 required positional argument: 'name'

 

#在实例化类时需要传入参数 

y = Dog('哈士奇')

print(y)  

<__main__.Dog object at 0x0000020E8D26C2E8>

print(y.name)

哈士奇

在这个实例中,dress是类属性,这个类中所有的实例都可以调用它。name是实例属性,只有这个实例可以调用它。

调用时需要注意的地方

在类中调用实例属性时使用self. 实例属性 ,在类外调用时使用实例名.实例属性

类中存在__init__方法时,在实例化类时需要传入参数(实例变量的实参),在调用类的方法时也需要传入方法的实参(方法中存在形参时)。

 

类对象和实例对象

一切皆对象

类对象不需要多加赘述,我们来看一些实例对象。

实例对象是类对象实例化的产物,实例对象仅支持一个操作:属性引用

 

属性绑定

不管是类对象还是实例对象,属性都是依托对象而存在的。我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作。

绑定有两种情况:如果属性存在,则覆盖,反之直接添加。

类属性绑定

Python是一个动态语言,绑定可以发生在任意时刻。

class Dog:

    kind ='canine'

 

Dog.country ='China'

print(Dog.kind, ' - ', Dog.country)

canine - China

del Dog.kind

print(Dog.kind, ' - ', Dog.country)

AttributeError: type object 'Dog' has no attribute 'kind'

这是使用类名绑定属性的方法。

 

实例属性绑定

class Dog:

    def __init__(self, name, age):

        self.name = name

        self.age = age

dog = Dog('Lily', 3)

dog.color = 'red'

print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.color))

Lily is 3 years old, it has red fur

这里是使用objname.attr = attr_value语句的方式。

属性引用

属性应用分为类属性引用和实例属性引用。

类属性引用

类属性的引用,肯定是需要类对象的,属性分为两种:数据属性、函数属性

这些我们在讲述类的时候讲述过了,这里就就简单举个例子

class Dog:

    kind ='canine'

    def tell_kind(): 

        print(Dog.kind)  

 

print(Dog.kind)        #类数据属性引用

print(Dog.tell_kind)   #类函数属性引用

 

实例属性引用

使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:

先到实例对象中查找属性,再到类属性中查找属性;

 

实例

class Dog:

    kind ='canine'

    country ='China'

    def __init__(self, name, age, country):

        self.name = name

        self.age = age

        self.country = country

 

dog = Dog('Lily', 3, 'Britain')

print(dog.name, dog.age, dog.kind, dog.country)

Lily 3 canine Britain

dog.country会引用到实例对象的属性;但实例对象dog没有属性kind,按照规则会引用类对象的属性。