python学习笔记:类(Class)和实例(Instance)

 一、 什么是面向对象编程

      面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

面向对象编程(oop)是一种程序设计思想。oo把对象作为程序的基本单元,一个对象包含数据和操作数据的函数
在python中,所有数据类型都被视为对象,也可以自定义对象。自定义对象数据类型就是面向对象中类的概念

面向对象术语简介:

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 方法:类中定义的函数。
  • 类变量(属性):类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体(方法)之外。类变量通常不作为实例变量使用,类变量也称作属性
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待,以普通的类为基础建立专门的类对象。
  • 实例化:创建一个类的实例,类的具体对象。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
  • 多态:对不同类的对象使用同样的操作
  • 封装:对外部世界隐藏对象的工作细节

二、类的定义

python中类的定义语法如下:

class ClassName(object):
    <statement-1>
    .
    .
    .
    <statement-N>
  • python中定义类使用class关键字,class后面紧接类名,类名通常是大写开头的单词
  • 紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
  • 类包含属性(类变量)和方法(函数)
  • 一个对象的特征称为"属性",一个对象的行为称为"方法"。属性在代码层面上来看就是变量,方法实际就是函数,通过调用这些函数来完成某些工作
  • 在类中定义方法的形式和函数差不多,但其不称为函数,而是叫方法。方法的调用需要绑定到特定的对象上(通过self.),而函数不需要。

 三、类的使用

例1:

class MyClass:
    """一个简单的类实例"""
    i = 12345
    def f(self):
        return 'hello world'
  
x = MyClass()  # 实例化类(非常重要)

print("变量x指向的是:",x)
print("MyClass指向的是:",MyClass)

# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的属性 i 为:", MyClass.i)
print("MyClass 类的方法 f 输出为:", x.f())
 
#上面代码的输出结果为:
#变量x指向的是:<__main__.MyClass object at 0x10a67a590>
#MyClass指向的是:<class '__main__.MyClass'>

#MyClass 类的属性 i 为: 12345
#MyClass 类的属性 i 为: 12345
#MyClass 类的方法 f 输出为: hello world
  • 在未实例化类时(x = MyClass()前),只是定义了对象的属性和方法,此时其还不是一个完整的对象,将定义的这些称为类。需要使用类来创建一个真正的对象,这个对象就叫做这个类的一个实例,也叫作实例对象(一个类可以有无数个实例)
  • 创建一个对象也叫做类的实例化,即x = MyClass()。(此时得到的x变量称为类的具体对象)注意此时类名后面是跟着小括号的,这跟调用函数一样。另外赋值操作并不是必须的,但如果没有创建好的实例对象赋值给一个变量,那这个对象就没办法使用,因为没有任何引用指向这个实例
  • 可以看到,变量x指向的就是一个MyClass的实例,后面的0x10a67a590是内存地址,每个object的地址都不一样,而MyClass本身则是一个类。
  • 如果要调用对象里的方法,使用点操作符( . )即可。
  •  x.i用于调用类的属性(即变量),也就是我们前面所说的类变量;x.f()用于调用类的方法(即函数)
  • 类中定义方法的要求:在类中定义方法时,第一个参数必须是self,除第一个参数外,类的方法和普通的函数没什么区别,如可以使用默认参数,可变参数,关键字参数和命名关键字参数等
  • 在类中调用方法的要求:要调用一个方法,在实例变量上直接调用即可,除了self不用传递,其他参数正常传入
  • 类对象支持两种操作:即属性引用和实例化,属性引用的标准语法为:obj.name(obj代表类对象,name代表属性名)

备注:
      类是一个抽象的概念,对象则是一个实际存在的东西。就像我们说的"狮子",它只是一个抽象的东西,只有具体到狮子这种动物身上它才是实际存在的。在比如设计房子的图纸只能告诉你房子是什么样的,并不是真正的房子,只有通过钢筋水泥建造出来的房子才实际存在,才能住人

self是什么:为什么方法中第一个参数必须为self

  • self其实就相当于C++中的this指针
  • 如果把类比作图纸,那么由类实例化后的对象才是真正可以住人的房子。根据一张图纸就可以设计出成千上万的房子,他们都长得差不多,但他们都有不同的主人,每个人都只能回自己的家里.....所以self这里就相当于每个房子的门牌号,有了self就可以轻松找到自己房子。
  • python的self参数就是同一个道理,有同一个类可以生成无数对象,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,那么python就知道需要操作哪个对象的方法了

例2:

class Ball:
    def setname(self,name):
        self.name = name
    def kick(self):
        print("我叫%s" % self.name)
 
a = Ball()
b = Ball()
c = Ball()
 
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参数且其位置在第一个

四、类变量和实例变量

1、类变量/实例变量

  • 实例变量是每个实例都独有的数据,而类变量是该类所有实例共享的属性和方法。其实我更愿意用类属性和实例属性来称呼它们,但是变量这个词已经成为程序语言的习惯称谓。
  • 即某个属性对于每个实例都是独有的,就需要将其定义为实例变量;是每个实例同共有的就可以定义为类属性

例3:

class Dog:
    dress = "china"
    def __init__(self,name):
        self.name = name 

类Dog中,类属性dress为所有实例所共享;实例属性name为每个Dog的实例独有(每个实例有不同的name)

注:

在类中调用实例属性时使用self.,在类外调用时使用实例名.实例属性名
2、类对象和实例对象
类对象:

Python中一切皆对象;类定义完成后,会在当前作用域中定义一个以类名为名字,指向类对象的名字。如

class Dog:
    pass

会在当前作用域定义名字Dog,指向类对象Dog。

总的来说,类对象仅支持两个操作:

  • 实例化:   使用instance_name = class_name()的方式实例化,实例化操作创建该类的实例。
  • 属性引用:使用class_name.attr_name的方式引用类属性。(类名.属性名)

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

  • 属性引用:与类对象属性引用的方式相同,使用instance_name.attr_name的方式。(实例对象名.属性名)

五、属性绑定

在定义类时,通常我们说的定义属性,其实是分为两个方面的:类属性绑定、实例属性绑定

用绑定这个词更加确切;不管是类对象还是实例对象,属性都是依托对象而存在的。我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作,使用objname.attr = attr_value的方式,为对象objname绑定属性attr
这分两种情况:

  • 若属性attr已经存在,绑定操作会将属性名指向新的对象;
  • 若不存在,则为该对象添加新的属性,后面就可以引用新增属性

类属性绑定
Python作为动态语言,类对象和实例对象都可以在运行时绑定任意属性。因此,类属性的绑定发生在两个地方

  • 类定义时
  • 运行时任意阶段

例4:

class Dog:
 
    kind = 'canine'
 
Dog.country = 'China'
 
print(Dog.kind, ' - ', Dog.country)  # 输出: canine  -  China
del Dog.kind
print(Dog.kind, ' - ', Dog.country)  #由于上一行删除的kind属性,因此输出为AttributeError: type object 'Dog' has no attribute 'kind'
  • 在类定义中,类属性的绑定并没有使用objname.attr = attr_value的方式,这是一个特例,其实是等同于后面使用类名绑定属性的方式。
  • 因为是动态语言,所以可以在运行时增加属性,删除属性。

实例属性绑定
与类属性绑定相同,实例属性绑定也发生在两个地方:类定义时、运行时任意阶段。
例5:

class Dog:
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
dog = Dog('Lily', 3)
dog.fur_color = 'red'
 
print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.fur_color))
 
#上面代码的输出结果为:Lily is 3 years old, it has red fur

Python类实例有两个特殊之处:

  • __init__在实例化时执行
  • Python实例调用方法时,会将实例对象作为第一个参数传递因此,__init__方法中的self就是实例对象本身,这里是dog,语句self.name = name,self.age = age以及后面的语句dog.fur_color = 'red'为实例dog增加三个属性name, age, fur_color。

1、属性引用

属性的引用与直接访问名字不同,不涉及到作用域。

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

数据属性引用很简单

例6:

class Dog:
 
    kind = 'canine'
 
Dog.country = 'China'
 
print(Dog.kind, ' - ', Dog.country)  # output: canine  -  China

通常很少有引用类函数属性的需求,

例7:

class Dog:
 
    kind = 'canine'
 
    def tell_kind():
        print(Dog.kind)
        
Dog.tell_kind()  # Output: canine

函数tell_kind在引用kind需要使用Dog.kind而不是直接使用kind,涉及到作用域

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

  • 总是先到实例对象中查找属性,再到类属性中查找属性
  • 属性绑定语句总是为实例对象创建新属性,属性存在时,更新属性指向的对象。

例8:

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)   #output:Lily 3 canine Britain

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

例9:

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
print(dog.__dict__)                               # {'name': 'Lily', 'age': 3, 'country': 'Britain'}
 
dog.kind = 'feline'
 
print(dog.name, dog.age, dog.kind, dog.country)   # Lily 3 feline Britain
print(dog.__dict__)                               # {'name': 'Lily', 'age': 3, 'country': 'Britain', 'kind': 'feline'}
print(Dog.kind)                                   # canine (没有改变类属性的指向)

    使用属性绑定语句dog.kind = 'feline',按照规则,为实例对象dog增加了属性kind,后面使用dog.kind引用到实例对象的属性。这里不要以为会改变类属性Dog.kind的指向,实则是为实例对象新增属性,可以使用查看__dict__的方式证明这一点。

可变类属性引用
例10:

class Dog:
    
    tricks = []
 
    def __init__(self, name):
        self.name = name
 
    def add_trick(self, trick):
        self.tricks.append(trick)
 
d = Dog('Fido')
e = Dog('Buddy')
d.add_trick('roll over')
e.add_trick('play dead')
print(d.tricks)             output:# ['roll over', 'play dead']

语句self.tricks.append(trick)并不是属性绑定语句,因此还是在类属性上修改可变对象。

 

类、类对象、实例对象

class C:
    count = 0
a = C()
b = C()
c = C()
print(a.count,b.count,c.count)   #output:0,0,0
 
a.count += 10   #实例属性
print(a.count,b.count,c.count)   #output:10,0,0
 
C.count += 100  #类属性
print(a.count,b.count,c.count)   #output:10 100 100
 
#print(count)   #name 'count' is not defined,不能直接访问类属性,具体访问方法参考前面的属性访问
  • 对实例变量的count属性进行赋值后,就相当于覆盖了类对象C的count属性,如果没有赋值覆盖,那么引用的就是累对象的count属性
  • 即找属性的顺序为:现在当前实例中找,有就用当前实例中的,如果没有就找类中的
  • 如果属性的名字跟方法相同,属性会覆盖方法

 六、拓展:python中的self参数

例1:
定义任意一个类

class Student(object):
    pass
student = Student()

   由于类起到模板的作用,因此,可以在创建实例的时候,把我们认为必须绑定的属性强制填写进去。这里就用到Python当中的一个内置方法__init__方法,例如在Student类时,把name、score等属性绑上去:

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

这里注意:
1、__init__方法的第一参数永远是self,表示创建的类实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身
2、有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器会自己把实例变量传进去

>>>student = Student("Hugh", 99)
>>>student.name
"Hugh"
>>>student.score
99

    这里self就是指类实例本身,self.name就是student实例对象,是该student实例对象独有的。而name是外部传来的参数,不是Student类所自带的。故,self.name = name的意思就是把外部传来的参数name的值赋值给student实例对象自己的属性变量self.name。

例2:

class Person:
    def __init__(self,name,job = None,pay = 10):
        self.name = name
        self.job = job
        self.pay = pay
    
    def getRaise(self,percent):
        self.pay = (int)(self.pay*(1+percent))
        return self.pay
    
p = Person("xiaoming","jixie")
print(p.getRaise(0.8))             #output:18

   self是指当前被调用的对象,对的,就是上边刚被你实例化的对象p。当你需要调用当前对象(实例对象)的方法或者属性时,要用self. 来进行调用。

例3:

class CC:
    def setXY(self,x,y):
        self.x = x
        self.y = y
    def printXY(self):
        print(self.x ,self.y)
 
dd = CC()
dd.setXY(4,5)

  self参数:当实例对象dd去调用setXY方法的时候,它传入的第一个参数就是dd,那么self.x = 4,self.y = 5也就相当于dd.x = 4,dd.y = 5,所以你在实例对象,甚至类对象中都看不到x和y,因为这两个属性是只属于实例对象dd的

例4:

class MyClass:
    """一个简单的类实例"""
    i = 12345
    def f(self):
        return 'hello world'
 
x = MyClass()   # 实例化类
 
# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f())
 
#上面代码的输出结果为:
#MyClass 类的属性 i 为: 12345
#MyClass 类的方法 f 输出为: hello world
 
class TestClass(object):
    val1 = 100
 
    def __init__(self):
        self.val2 = 200
 
    def fcn(self, val=400):
        val3 = 300
        
        self.val4 = val
        self.val5 = 500
 
 
if __name__ == '__main__':
    inst = TestClass()
 
    print(TestClass.val1)
    print(inst.val1)
    print(inst.val2)
    #print(inst.val3)
    #val3为局部变量,无法在函数为调用'TestClass' object has no attribute 'val3'
    #print(inst.val4)
    #print(inst.val5)

这里

  • val1是类变量,可以由类名直接调用,也可以有对象来调用;
  • val2是成员变量,可以由类的对象来调用,这里可以看出成员变量一定是以self.的形式给出的,因为self的含义就是代表实例对象;
  • val3不是成员变量,它只是函数fcn内部的局部变量;
  • val4和val5也都不是成员变量,虽是以self.给出,但并没有在构造函数中初始化。
     

转载来自:

python:类基

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值