python3之类和对象

一、面对对象(OOP)的三大特征

1 多态

无需知道对象是什么类型就能对它执行操作
不同类型的对象执行相同的操作,操作结果随着对象的类型而异
多态是方法的多态,属性没有多态

示例

def add(x,y):
    return x+y

sum1=add(2,3)
sum2=add('aaa','bbb')
print(sum1)
print(sum2)

数值返回两数字的和,字符串返回两个字符串拼接后字符串

2 封装

将对象的状态信息隐藏在对象内部,只对外提供必要的方法,不允许外部直接访问对象内部信息
向外部隐藏不必要的细节
无需知道对象的构造就能对它执行操作
通过私有属性、私有方法的方式实现封装,即属性、方法前面加上双下划线("__")

3 继承

创建一个与已有类相似的类,但是比原有类多了一些方法
新创建的类被称为子类(派生类),原有的类被称为父类(基类、超类)
子类可以继承父类,一个子类可以有多个父类

二、面对对象(OOP)术语简介

类(Class)
具有相同的属性或方法的对象的集合
定义了该集合中每个对象所共有的属性和方法

属性
类中定义的所有变量和方法,包括类变量和方法,实例变量

数据成员
类变量或者实例变量,用于处理类及其实例对象的相关的数据

类变量
类的所有实例共享的属性,可以通过"类名.变量名"直接访问
类变量通常不作为实例变量使用


方法
类中定义的函数

类对象
通过类定义的数据结构实例
支持两种操作:属性引用和实例化

属性引用(对属性点号运算)
obj.属性名


实例对象
类实例化之后,类的具体实例对象

实例变量
实例化之后,每个实例单独拥有的变量
只作用于当前实例
以"self."开头,仅供各个实例对象调用

实例方法
实例化之后,每个实例都可以调用的方法
至少包含一个参数,第一个参数约定俗成命名为"self",通过它来传递实例的属性

方法重写
如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写

示例

class Bird:
    #类变量
    n = 999
    
    #实例方法
    def walk(self, name):
        print(name,'正在行走')
    
    #类方法
    @classmethod
    def fly (cls, name):
        print('类方法fly:',cls)
        print(name,'正在飞')

#类实例化,返回一个Bird对象,并赋值给变量u       
u = Bird()
#传入实例变量name的值
u.walk('monkey')
#通过实例对象调用类变量
print(u.n)
#通过类名调用类变量
print(Bird.n)
#通过类名调用类方法
Bird.fly('butterfly')



class Person:
    hair='black'
    
    def set_name(self,name):
        self.name=name
        
    def get_name(self):
        return self.name
        
    def greet(self):
        print("hello,world!I'm %s" % (self.name))

#直接调用类变量
print(Person.hair)
#类实例化,返回一个Persoon对象,并赋值给变量person
person = Person()
#通过实例调用类变量
print(person.hair)
#调用实例方法并传入实例变量name的值
person.set_name('marry')
#调用实例变量
print(person.name)
#调用实例方法
print(person.get_name())
#调用实例方法
person.greet()

三、类定义

格式

class class_name:
    <statement-1>
    .
    .
    .
    <statement-N>

四、方法

1 实例方法

类中定义的方法默认是实例方法,和定义普通函数方法一致,但实例方法至少包含一个参数(通常是self),self参数会自动绑定调用者,指向调用者本身
调用实例方法时不需要为self参数传入值

示例

class Person:
    def set_name(self, name):    
        self.name=name
        
    def get_name(self):
        return self.name
        
    def greet(self):
        print("hello,world!I'm %s" % (self.name))


#类实例化
person = Person()
#调用实例方法并传入实例变量name的值,第一个参数self会自动绑定到调用者
person.set_name('marry')
#调用实例变量
print(person.name)
#调用实例方法
print(person.get_name())
#调用实例方法
person.greet()

2 类方法

使用@classmethod修饰的方法
类方法的cls参数会自动绑定类,执行该类
可以通过实例对象调用也可以通过类对象直接调用
调用类方法时不需要为cls传入参数

示例

class test:
    @classmethod
    def class_method(cls):
        print('类方法:',cls)
        
    @classmethod
    def classm(cls,name):
        print('类方法:',cls)
        print(name)

#类实例化
T = test()
#通过实例对象调用类方法,只有cls一个参数,指向test类,调用时不需要传入值
T.class_method()
#该方法有两个参数,第一个cls指向test类,第二个参数需要调用时需要传入值
T.classm('jack')
#通过类名调用类方法
test.class_method()
test.classm('marry')

3 静态方法

使用@staticmethod修饰的方法
可以通过实例对象调用也可以通过类对象直接调用
调用时,需要传入参数,不会自动绑定

示例

class static:
    @staticmethod
    def static_method(p):
        print('静态方法:',p)

#类实例化
S = static()
#通过实例对象调用类方法,必须传入参数值
S.static_method('message')
#通过类对象直接调用,必须传入参数值
static.static_method('info')

五、类内置方法

定义类时,前后都有双下划线定义的方法,都属于类的特殊方法
可以重写或者直接调用这些方法来实现特殊的功能

1 __init__(self) 方法

初始化方法(构造方法)
用于初始化实例化对象属性值
创建类的实例时就会调用该方法
若该方法有多个参数时,类实例化必须要传入参数

示例

class Rectangle():
    def __init__(self, length, width):
        self.length = length
        self.width = width
        
    def getPeri(self):
        return ((self.length + self.width) * 2)
        
    def getArea(self):
        return (self.length * self.width)

#类中定义了__init__方法且该方法不止一个参数,实例化时必须要传入length,width两个参数
R = Rectangle(6,5)
print(R.getPeri())
print(R.getArea())

2 __str__(self) 和 __repr__(self) 方法

如果两个方法都定义了,print() 方法会调用  __str__  方法
如果只想调用 __repr__ ,只需定义 __repr__ 方法
如果两个方法都没有定义,print()使用object基类中默认的 __str__ 方法,因为object是所有类的基类
__repr__ 和 __str__ 这两个方法都是用于显示的, __str__ 是面向用户的,而 __repr__ 面向程序员

只能输出字符串类型数据
使用中推荐至少有一个 __repr__ 方法

示例

class Repr:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Repr1:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    #重新定义__str__方法
    def __str__(self):
        return 'this is __str__'+'		'+self.name+":"+str(self.age)

    #重新定义__repr__方法
    def __repr__(self):
        return 'this is __repr__'+'		'+self.name+":"+str(self.age)

class Repr2:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    #重新定义__repr__方法
    def __repr__(self):
        return f'this is __repr__,    {self.name}:{self.age}'

     
R = Repr('mack',22)
#未定义__str__和__repr__方法,print(R)使用object基类中的默认__str__方法
print(R)
print(R.__repr__)
print(R.__str__)
print()
print()
print()

R1 = Repr1('jack',20)
#调用__str__方法输出
print(R1)
print(R1.__repr__)
print(R1.__str__)
print()
print()
print()

R2 = Repr2('maryy',18)
#调用__repr__方法输出
print(R2)

3 __del__(self) 方法

对象引用计数为0时,对象才会被回收,自动调用 __del__ 方法
即一个对象被多个变量引用时,del删除该对象时不会立即回收对象

一般出现在两个地方:
1、手动减少对象引用计数至0,被垃圾回收处理时调用
2、程序结束时调用

示例

class Del:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __del__(self):
        print("%s对象已被删除" % self)

D_1 = Del('maryy', 22)
#变量D_2也指向对象
D_2 = D_1
#对象不会被回收,程序执行完才会调用__del__方法
del D_1
print(D_2.name,D_2.age)
class Del:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __del__(self):
        print("%s对象已被删除" % self)

D = Del('maryy', 22)
#对象立即被回收,调用__del__方法
del D
print("是否回收对象")

4 __dir__(self) 方法

返回对象内部所有的变量名和方法名组成的列表

dir(object)返回对象的 __dir__ 方法经过排序后的列表

示例

class Dir:
    var1 = 'value1'
    var2 = 'value2'
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __repr__(self):
        return self.name+' '+str(self.age)
        
    def __del__(self):
        print("删除对象")


D = Dir('maryy', 22)  
#通过实例化对象调用__dir__方法,返回类中所有实例属性组成的列表    
print(D.__dir__())
#返回实例化对象调用__dir__方法经过排序后的列表
print(dir(D))

5 __dict__(self) 方法

返回对象内部的所有属性名和属性值组成的字典,该方法可以通过字典的语法来访问或修改指定属性的值

通过类名调用 __dict__ 方法,输出类中所有的属性,包括类属性,实例属性
通过实例化对象调用 __dict__ 方法,输出类中所有实例属性组成的字典

示例

class Dict:
    var1 = 'value1'
    var2 = 'value2'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return self.name,self.age

#通过类名调用__dict__方法,返回类中所有的属性组成的字典
print(Dict.__dict__)
#类实例化
D = Dict('jack', 24)
#通过实例化对象调用__dict__方法,返回类中所有实例属性组成的字典
print(D.__dict__)
#以字典的语法调用__dict__方法访问属性值
print(D.__dict__['name'])
print(D.__dict__['age'])
#以字典的语法调用__dcit__方法修改属性值
D.__dict__['name'] = 'tom'
D.__dict__['age'] = 25
print(D.__dict__['name'])
print(D.__dict__['age'])

6 __getattr__(self) 、__setattr__(self) 、__delattr__(self) 方法

当对类和该类的所有父类(若有多层继承,沿着继承关系直到最后的基类)中未定义的属性(包括变量和方法)进行点号运算时,调用 __getattr__ 方法
如果可以找到该属性,则不调用此方法
仅在引用属性且属性不存在的时候才会触发 __getattr__ 方法


只要对属性(不管该属性是否在类中定义)赋值时都会调用 __setattr__ 方法
当在 __setattr__ 方法内对属性进行赋值时,不可使用self.attr=value,因为会再次调用 __setattr__ 方法,形成无限递归,导致堆栈溢出异常
一般在 __setattr__ 方法内对属性赋值,使用self.__dict__[attr]=value

删除属性时会调用 __delattr__ 方法

示例

class Set:
    def __init__(self,length,width):
        self.length = length
        self.width = width
    
    #重新定义__setattr__方法
    def __setattr__(self,attr,value):
        print('---设置对象属性---')
        #传入的attr参数名是否为size,若是,则重新设置length,width的值
        #否则新增一个名=attr,值=value的变量
        if attr == 'size':
            self.__dict__['length'],self.__dict__['width'] = value
        else:
            self.__dict__[attr] = value
   
    #重新定义__getattr__方法
    def __getattr__(self,attr):
        print('---访问对象属性---')
        #传入的attr参数名是否为size,若是,则返回原来length,width的值
        #否则引发AttributeError异常
        if attr == 'size':
            return self.length,self.width
        else:
            raise AttributeError
    
    #重新定义__delattr__方法
    def __delattr__(self,attr):
        print('---删除对象属性---')
        #传入的attr参数名是否为size,若是,则修改length,width的值为0
        #否则什么也不做
        if attr == 'size':
            self.__dict__['length'] = self.__dict__['width']=0
        else:
            pass

#实例化类,调用__init__方法和__setattr__方法
S = Set(5,6)
#返回所有实例属性组成的字典
print(S.__dict__)
#size属性赋值,调用__setattr__方法
S.size = 8,9
print(S.__dict__)
#删除size属性
del S.size
print(S.__dict__)
#big属性赋值,调用__setattr__方法
S.big = 1
print(S.__dict__)

7 序列相关的特殊方法

__len__(self)       返回元素的数量
__getitem__(self)   返回键对应的值
__setitem__(self)   设置给定键的值
__delitem__(self)   删除给定键对应的元素

示例

#key检查函数
#key必须是非负整数
#若key不是int类型,则引发TypeError
#若0<key<=pow(26,3),则引发IndexError
def check_key(key):
    if not isinstance(key, int):
        raise TypeError
    if (key<0) or (key >= pow(26,3)):
        raise IndexError

class seq:
    def __init__(self):
        #存储被修改的数据
        self.__chaged = {}
        #存储被删除元素的索引
        self.__deleted = []
    
    #获取元素个数
    def __len__(self):
        print('---返回元素个数---')
        return pow(26,3)

    #获取索引对应的元素的值
    def __getitem__(self, key):
        print('---获取key=%s对应元素的值---'% (key))
        #调用key检查函数
        check_key(key)
        #如果在self.__chaged找到数据,则返回已修改的值
        if key in self.__chaged:
            return self.__chaged[key]
        #如果在self.__deleted中找到数据,说明元素被删除,返回None
        elif key in self.__deleted:
            return None
        #否则,根据计算规则返回元素,得到一个AAA,AAB,AAC,AAD,...,的序列
        else:
            three = key//(pow(26,2))
            two = (key-three*pow(26,2))//26
            one = key%26
            return chr(65+three)+chr(65+two)+chr(65+one)

    #设置索引对应元素的值
    def __setitem__(self, key, value):
        print('---设置key=%s对应元素的值---'% (key))
        #调用key检查函数
        check_key(key)
        self.__chaged[key] = value

    #删除索引对应元素的值
    def __delitem__(self, key):
        print('---删除序列key=%s对应元素的值---'% (key))
        #调用key检查函数
        check_key(key)
        #如果在self.__deleted中未找到key,则添加该key到删除列表中
        if key not in self.__deleted:
            self.__deleted.append(key)
        #如果在self.__chaged中找到key,则删除该key
        if key in self.__chaged:
            del self.__chaged[key]


#得到一个AAA,AAB,AAC,AAD,...,元素个数为pow(26,3)的序列
Seq = seq()

#获取元素,调用__len__方法
print(len(Seq))

#获取key=1元素的值,调用__getitem__方法
print(Seq[1])
#删除key=1元素的值,调用__delitem__方法
del Seq[1]
#获取key=1元素被删除后的值,调用__getitem__方法
print(Seq[1])

#获取key=2元素的值,调用__getitem__方法
print(Seq[2])
#修改key=2元素的值,调用__setitem__方法
Seq[2] = 'asd'
#获取key=2元素被修改后的值,调用__getitem__方法
print(Seq[2])
class ArithemeticSequence:
    def __init__(self,start,step):
        self.start=start
        self.step=step
        self.myData={}
    
    #定义获取元素个数的方法
    def __len__(self):
        print('---返回元素个数---')
        return len(self.myData)
   
   #定义获取值的方法
    def __getitem__(self,key):
        print('---获取key=%s对应元素的值---'% (key))
        try:
            return self.myData[key]
        except KeyError:
           return self.start+key*self.step
    
    #定义修改元素的方法
    def __setitem__(self,key,value):
        print('---设置key=%s对应元素的值---'% (key))
        self.myData[key]=value
    
    #定义删除元素的方法
    def __delitem__(self, key):
        print('---删除序列key=%s对应元素的值---'% (key))
        del self.myData[key]

#得到一个等差序列实例对象     
s=ArithemeticSequence(1,2)
#获取元素个数,初始状态0个元素
print(len(s))
#获取key=3元素的值
print(s[3])
#修改key=3元素的值
s[3]=100
#获取key=3元素被修改后的值
print(s[3])
#获取元素个数,只有一个元素
print(len(s))
#删除key=3元素的值
del s[3]
#获取元素个数,0个元素
print(len(s))

 六、类继承

格式

class SubClass(SuperClass1,SuperClass2,..):
     <statement-1>
    .
    .
    .
    <statement-N> 


其中
SubClass是子类,SuperClass1,SuperClass2,..是父类(基类|超类),多个父类以逗号隔开
若多个父类中有相同的属性,则使用(SuperClass1,SuperClass2,..)中排在最前面的父类的属性,所以不是很有必要,尽量不使用继承多个父类
object是所有类的直接父类或间接父类

示例

class Fruit:
    def info(self):
        print('水果:%s,重量:%s'%(self.name,self.weight))
        
class Food:
    def taest(self):
        print('不同食物口感不同')
        
class Apple(Fruit,Food):
    def __init__(self,name,weight):
        self.name=name
        self.weight=weight

A=Apple('apple',5)
A.info()
A.taest()

1 重写父类方法

示例

class Father(object):
    def __init__(self, name):
        self.name = name
        print('父类__init__方法')
        
    def getName(self):
        print('父类getName方法')
        return 'Father '+self.name
 
class Son(Father):
    #重写父类中的getName方法,父类的getName方法被覆盖
    def getName(self):
        print('子类getName方法')
        return 'Son name: '+self.name
 
son = Son('test_class')
print(son.getName())
class Father(object):
    def __init__(self, name):
        self.name = name
        print('父类__init__方法')
        
    def getName(self):
        print('父类getName方法')
        return 'Father name:'+self.name
 
class Son(Father):
    #重写父类的 __init__ 方法,父类中的 __init__ 方法会被覆盖
    def __init__(self, name):        
        self.name = name
        print('子类__init__方法')
        
    #重写父类中的 getName 方法,父类的 getName 方法被覆盖
    def getName(self):
        print('子类getName方法')
        return 'Son name:'+self.name
 
son = Son('test_class')
print(son.getName())

2 子类中调用父类方法

格式

父类名.方法名(参数)
参数必须和父类方法中参数一致,包括self参数

示例

class Father(object):
    def __init__(self, name):
        self.name = name
        print('父类__init__方法')
        
    def getName(self):
        print('父类getName方法')
        return 'Father name:'+self.name
 
class Son(Father):
    #重写父类中的getName方法
    def getName(self):
        print('子类getName方法')
        #调用父类方法
        print(Father.getName(self))
        return 'Son name:'+self.name
 
son = Son('test_class')
print(son.getName())

3 使用super()函数继承父类的 __init__(self) 方法

格式

super().__init__(self): 参数包括父类方法中除了self参数的所有参数

示例

class Father(object):
    def __init__(self, name):
        self.name = name
        print('父类__init__方法')
        
    def getName(self):
        print('父类getName方法')
        return 'Father name: '+self.name
 
class Son(Father):
    def __init__(self, name):
        #继承父类中的__init__方法
        super().__init__(name)
        print('子类__init__方法')
        
    def getName(self):
        print('子类getName方法')
        #子类方法中调用父类方法
        print(Father.getName(self))
        return 'Son name: '+self.name
 
son = Son('test_class')
print(son.getName())

七、枚举类

类的对象有限而且固定,例如季节,星期几
枚举类不能用来实例化,且一旦定义创建,不能在外部修改成员值
可以使用==或者is比较成员,并且可以迭代枚举

包括

enum.Enum
创建枚举常量的基类,value为任意数据类型

enum.IntEnum
创建枚举常量的基类,value只能是整型数字

enum.IntFlag
创建枚举常量的基类,value只能是整型数字
使用按位运算符对其进行组合而不会丢失其IntFlag成员资格

enum.Flag
创建枚举常量的基类,value为任意数据类型
使用按位运算符对其进行组合而不会丢失其IntFlag成员资格

enum.unique()
name不能相同,value也不相同

enum.auto
成员值随机生成,初始值1

示例

from enum import Enum, IntEnum, unique

#枚举类的装饰器,若有value相同则引发ValueError错误并附带相关细节信息
@unique
class Season(Enum):
    SPRING = "春天"
    SUMNNER = '夏天'
    FALL = '秋天'
    WINTER = '冬天'

@unique
class color(IntEnum):
    red = 1
    yellow = 2
    green = 3
    pink = 4

class color2(IntEnum):
    red = 1
    beown = 1
    yellow = 2
    green = 3
    ping = 4

#获取Season枚举类成员SPRING的值
print(Season.SPRING.value)
#获取成员的name
print(Season.SPRING.name)
#通过成员value获取成员的name
print(Season('春天'))
#获取成员name=SPRING的信息
print(repr(Season.SPRING))
#获取成员name=SPRING属于哪个枚举类
print(type(Season.SPRING))


menber = Season.SPRING
#获取成员的name
print(menber.name)
#获取成员的value
print(menber.value)

#枚举类成员比较
print(Season.SPRING == Season.SPRING)
print(Season.SPRING is Season.SPRING)
原文地址:https://www.cnblogs.com/gudanaimei/p/13463756.html