Python学习笔记——类和实例

笔记内容由廖雪峰官网和菜鸟教程整理得到


面向对象编程的设计思想:抽象出Class类,根据Class创建Instance实例。
Class既包含数据又包含数据操作,面向对象的抽象程度比函数高。
数据封装、继承、多态是面向对象的三大特点。

类和实例

Class类是创建Instance实例的模板,而Instance实例是一个个具体对象。
每个实例拥有的数据都相互独立,Python允许对实例变量绑定任何的数据,同一个类的不同实例可以拥有不同的变量。

#-*- coding:utf-8 -*-

#定义类用class关键字,后面Student是类名
#括号内表示继承的类,没有合适继承用object表示所有类都会继承的类
class Student(object):
    #定义__init__,创建实例时强制填写必须属性
    #__init__第一个参数永远是self,指向创建实例本身
    def __init__(self, name, score):
        self.name = name
        self.score = score
    #在类内定义访问数据的函数以封装数据
    #数据和逻辑被封装起来,不必知道内部实现即可调用
    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'
#必须传入和__init__匹配的参数,self不需要传,会自动传入
#不能传入其他的参数
lisa = Student('Lisa', 99)
bart = Student('Bart', 59)
#调用数据和函数时要加实例名
print(lisa.name, lisa.score,lisa.get_grade())
print(bart.name, bart.score,bart.get_grade())
#允许同一个类中的实例拥有不同的变量
bart.age=8
print(bart.age)
lisa.gender='female'
print(lisa.gender)

#output
#Lisa 99 A
#Bart 59 C
#8
#female
访问限制
  • private
    在__init__定义的属性名称前加上两个下划线,表示private,只能内部访问的变量,保证外部代码不能随意修改对象内部状态。
  • __xxx __
    在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量。python中如果定义变量名前有一个下划线,则默认将其视为私有变量,不要随意访问。
  • 外部访问
    外部需要通过函数来访问或者修改private变量。
    不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量。【不同版本Python不同,但尽量不要这样访问】
#-*- coding:utf-8 -*-
class Student(object):    
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))
    
    #增加返回变量的函数,以访问private变量
    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score
        
        #增加用来修改private变量的函数
    def set_score(self, score):
        self.__score = score

#利用函数来访问private变量        
bart=Student('Bart',59)
print(bart.get_name())
print(bart.get_score())

#利用函数修改private变量
bart.set_score(100)
print(bart.get_score())

#内部的__name变量已经被Python解释器自动改成了_Student__name
# 外部代码只是给bart新增了__name变量
bart.__name='New'
print(bart.__name)
print(bart.get_name())

#output
#Bart
#59
#100
#New
#Bart
  • 作业练习:请把下面的Student对象的gender字段对外隐藏起来,用get_gender()和set_gender()代替,并检查参数有效性:
class Student(object):
    def __init__(self, name, gender):
        self.name = name
        self.__gender = gender
    def get_gender(self):
        return self.__gender
    def set_gender(self,gender):
        self.__gender=gender

# 测试:
bart = Student('Bart', 'male')
if bart.get_gender() != 'male':
    print('测试失败!')
else:
    bart.set_gender('female')
    if bart.get_gender() != 'female':
        print('测试失败!')
    else:
        print('测试成功!')
继承与多态
继承
  • 语法
    class 子类名(父类名):
    不继承父类的类声明用object class 类名:父类
  • 特点
    1、子类中构造函数存在三种情况:不重写父类、重写父类、重写同时继承父类
    2、类中调用普通函数不需要加上self参数,但调用父类的函数时需要加上父类的类名前缀同时加上self参数的变量。
    3、现在本类中查找函数,找不到再到基类中查找。
  • 判断子类
    issubclass(Classson,Classfather) - 布尔函数判断一个类是另一个类的子类或者子孙类。
    isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
__init__子类继承父类构造函数的三种情况

1、不重写__init__则调用父类定义的__init__
2、重写__init__则调用子类定义的__init__
3、super重写__init__的同时继承母类定义的__init__
super(子类名称,self).__init__(父类的参数)
父类名称.__init__(self,父类参数)

#-*- coding:utf-8 -*-
class Animal(object):
    def __init__(self,number):
        self.number=number
        print('number in Animal is %d' %(self.number))
    def getnumber(self):
        print('Animal',self.number)
    
animal=Animal(1)
animal.getnumber()

#number in Animal is 1
#Animal 1 
    
    
#不重写__init__则调用父类定义的__init__
class Cat(Animal):
    def getnumber(self):
        print('Cat',self.number)
        #return self.number

#不重写__init__则调用父类定义的__init__
cat=Cat(50)
#子类中重写函数则调用重写后的函数
cat.getnumber()

#output
#number in Animal is 50
#Cat 50


#重写__init__则调用子类定义的__init__
class Dog(Animal):
    def __init__(self,number):
        self.number=number
        print('number in Dog is %d' %(self.number))
    def getnumber(self):
        print('Dog',self.number)
       # return self.number

dog=Dog(100)    
dog.getnumber()

#output
#number in Dog is 100
#Dog 100
    
#重写__init__的同时继承父类定义的__init__
class Pig(Animal):
    def __init__(self,number,name):
        #super(子类名称,self).__init__(父类的参数)
        #父类名称.__init__(self,父类参数)
        #等价于Animal.__init__(self,number)
        super(Pig,self).__init__(number)
        self.name=name
        print('name in Pig is %s' %(self.name))
        print('number in Pig is %d' %(self.number))
    def getnumber(self):
        print('Pig',self.number)
       # return self.number

pig=Pig(101,'ann')    
pig.getnumber()

#output
#number in Animal is 101
#name in Pig is ann
#number in Pig is 101
#Pig 101

#判断Pig类是否是Animal子类
print(issubclass(Pig,Animal))
#判断实例对象pig是否是Animal的类或子类的实例对象
print(isinstance(pig,Animal))
       
  • 多态
    Python动态语言‘file-like object,想要调用某种方法不一定要继承,只要保证传入参数是个对象,且具有该相似方法即可。而静动态语言如JAVA等则必须继承。
class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('Dog is running...')

    def eat(self):
        print('Eating meat...')
        
class Cat(Animal):
    pass

#由于Animal类型有run()方法
#只要传入Animal类或者子类,就会自动调用实际类型的run()方法
#当新增Animal子类时,不必对run_twice修改即可使用
def run_twice(animal):
    animal.run()
    animal.run()

#子类和父类使用run_twice
animal=Animal()
dog=Dog()
cat=Cat()
run_twice(animal)
run_twice(dog)
run_twice(cat)
#output
#Animal is running...
#Animal is running...
#Dog is running...
#Dog is running...
#Animal is running...
#Animal is running...

#file-like object
#只要有run()函数的对象,就可以调用run_twice
class Duck(object):
    def run(self):
        print('file-like object')

duck=Duck()
run_twice(duck)
#output
#file-like object
#file-like object
获取对象信息
判断类型(重点isinstance)

相同返回True,否则返回False

  • isinstance和issubclass
    类与类:issubclass(Classson,Classfather) - 布尔函数判断一个类是另一个类的子类或者子孙类。
    实例与类:isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
    isinstance(arg,(int,str,tuple))
  • isinstance和type
    type:
    type不考虑继承,不认为子类是父类的类型
    class type(object)
    | type(object_or_name, bases, dict)
    | type(object) -> the object’s type 输出obj的类型
    | type(name, bases, dict) -> a new type
print(type(123))
#<class 'int'>
print(type(123)==int)
#True

isinstance
isinstance考虑继承,认为子类实例既是子类类型,也是父类的类型
isinstance(obj, class_or_tuple, /)
isinstance(x, (A, B, …))判定obj是否是列表内中某一种(type不行)

>>> isinstance(d, Dog) and isinstance(d, Animal)
True
>>> isinstance([1, 2, 3], (list, tuple))
True
对象属性和方法
dir

dir()返回list:对象所有的属性和方法

>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
getattr,hasattr,setattr,delattr

hasattr(obj, name)判断是否有obj是否有name的变量,返回True False
getattr(object, name[, default]) -> value获取属性。如果有name属性则返回属性。如果没有name属性,没有defalut则报错,有default则赋值。
setattr(obj, name, value, /)设置属性,obj.name=value。
delattr(obj, name, /)删除属性,删除obj的name属性
(?以下这句话我还是有点不太明白,这种方法除了麻烦还有其它问题吗)
可以拿到class内部的数据,但只有在不知道对象信息的时候,才会去获取对象信息。
可以:
sum=obj.x+obj.y
就不要:
sum=getattr(obj,‘x’)+getattr(obj,‘y’)

class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x

obj = MyObject()

#判断是否有属性
#hasattr(obj, name)判断是否有obj是否有name的变量
hasattr(obj,'x')
#True
hasattr(obj,'y')
#False

#获取属性
#getattr(object, name[, default]) -> value
getattr(obj,'x')
#9
getattr(obj,'y')
#找不到报错AttributeError: 'MyObject' object has no attribute 'y'
getattr(obj, 'z', 404)
#找不到则赋值404

# 设置一个属性'y'
setattr(obj, 'y', 19) 
hasattr(obj,'y')
#True
getattr(obj,'y')
#19

#setattr也可以更改__init__中的default
setattr(obj, 'x', 19) 
obj.x
#361
obj.power()
#361

#delattr删除属性
delattr(obj,'x')
hasattr(obj,'x')
#False

函数获也可以获取对象的方法

class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x

obj = MyObject()

hasattr(obj,'power')
%True

#getattr可以用来获取方法,将方法赋值给变量
f=getattr(obj,'power')
f
#<bound method MyObject.power of <__main__.MyObject object at 0x0000000005FE67F0>>
f()#等价于obj.f()
#81
常用重载功能__xxx__

__xxx__的属性和方法都是特殊用途
比如len(‘ABC’)等价于’ABC’.__len__(),当使用len()函数内部自动调用对象的__len__()方法。自己写的类如果需要用len(myobj)的话则在class声明一个__len__( )方法(函数)

__init__(self,args…) 构造函数
__del__(self) 删除一个对象
__repr__(self)转化为供解读器读取的形式?
__str__(self) 转化为适于人阅读的形式,当有print时,返回这个函数中的return
__cmp__(self)对象比较
__add__(self,other):运算符重载

#!/usr/bin/python
 
class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b

#如果没有__str__()
#返回对象<__main__.Vector object at 0x0000000005ADE860>
    def __str__(self):
        return 'Vector (%d, %d)' % (self.a, self.b)
 #运算符重载  
    def __add__(self,other):
        return Vector(self.a + other.a, self.b + other.b)
 
v1 = Vector(2,10)
v2 = Vector(5,-2)
print(v1 + v2)
实例属性和类属性

类属性:归Student类所有
实例属性:通过实例变量给实例绑定
编程中不要不要对实例属性和类属性使用相同的名字。因为实例属性的优先级高于类属性,相同名称的实例属性将屏蔽掉类属性。删除实例属性后,如果存在同名的类属性,则访问到的将是类属性。

class Student(object):
    school='Sun Yat-sen'#类属性:归Student类所有
    def __init__(self,name):
        self.name=name#实例属性:通过实例变量给实例绑定属性        

class Student_2(Student):
    pass

s=Student('Wayne')
print(s.name)#打印实例属性
#Wayne
print(s.school)#打印实例的school属性,因为实例没有则返回类的school属性
#Sun Yat-sen
print(Student.school)#打印类的school属性
#Sun Yat-sen
s.school='PEK'#给实例绑定school属性
print(s.school)#实例属性优先级更高,屏蔽掉类的school属性
#PEK
print(Student.school)#实例属性改变但类的属性保持不变
#Sun Yat-sen
del s.school#删除实例的属性
print(s.school)#无法找到实例的属性,返回类的属性
#Sun Yat-sen

#子类也会继承父类本身绑定的属性
s2=Student_2('Violette')
print(s2.school)#打印实例的school属性
#Sun Yat-sen
print(Student_2.school)#打印类的school属性
#Sun Yat-sen
练习
class Student(object):
    count = 0

    def __init__(self, name):#类属性不用作为参数
        self.name = name
        Student.count+=1#调用类属性必须(类名.属性),+=

# 测试:
if Student.count != 0:
    print('测试失败!')
else:
    bart = Student('Bart')
    if Student.count != 1:
        print('测试失败!')
    else:
        lisa = Student('Bart')
        if Student.count != 2:
            print('测试失败!')
        else:
            print('Students:', Student.count)
            print('测试通过!')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值