【Python】初学自用笔记 第十篇 面向对象高级编程

使用__slots__

  • 未使用__slots__,绑定 属性或函数 到 类或实例 上:

class Student(object):  #暂定一种名为Student的类
    pass
s=Student() #创建Student的一个实例s
s.name='Tom' #为s这个实例添加一个属性并赋值
print(s.name)
def set_age(self,age): #可以在类的定义外构造一个带有self参数的函数,以便于绑定给类
    self.age=age
from types import MethodType #从模块 types 里加载功能 MethodType
s.set_age=MethodType(set_age,s) #将函数set_age绑定到实例s上
s.set_age(25)
print(s.age)
s2=Student()
def set_score(self,score):
    self.score=score
Student.set_score=set_score #直接将函数 setscore 绑定到类 Studennt上
s.set_score(100)
s2.set_score(99)
print(s.score)
print(s2.score)
'''
Tom
25
100
99
'''
  • 使用__slots__限制实例的属性

class Student(object):
    __slots__=('name','age')  #用元组定义允许绑定的属性名称
s=Student()
s.name='Tom'
s.age=20
# s.city='Putian'  #没有出现在__slots__定义里的属性不能操作
# class GraduateStudent(Student):
#     pass
# gs=GraduateStudent()
# gs.name='Jack'  #__slots__定义的属性仅对当前类实例起作用,对其子类不起作用
class MiddleStudent(Student):
    __slots__=('city')  #在子类中也定义__slots__,这样子类允许定义的属性就是自身的slots加上父类的slots
ms=MiddleStudent()
ms.city='Beijing'
print(ms.city)

使用@property

  • 限制参数的修改范围,以防胡乱修改:

class Student(object):
    def set_score(self,value): #设置一个输入成绩的函数,同时可以进行错误数据检验
        if not isinstance(value,int):
            raise ValueError('score must be an integer!')
        if value<0 or value>100:
            raise ValueError('score must between 0~100!')
        self._score=value
    def get_score(self):  #再设置一个获取成绩的函数,通过这两个函数的设置,就不能随便改成绩了
        return self._score
s=Student()
s.set_score(100)
print(s.get_score())
'''
100
'''
  • 使用@property来·将类定义中的函数(方法)变成可修改属性:

class Student(object):
    @property  #将接下来的获取方法变成属性,其本身又创建了另一个装饰器 @score.setter
    def score(self):  #获取成绩的方法
        return self._score
    @score.setter  #负责把一个输入setter方法变成属性
    def score(self,value):
        if not isinstance(value,int):
            raise ValueError('score must be an integer!')
        if value<0 or value>100:
            raise ValueError('score must between 0~100')
        self._score=value
s=Student()
s.score=60  #这时的函数score就变成了属性score,可以直接赋值
print(s.score)
'''
60
'''
  • 使用@property定义只读属性,只定义getter方法,不定义setter方法:

class Student(object):
    @property
    def birth(self):
        return self._birth
    @birth.setter
    def birth(self,value):  #biirth为可读写属性
        self._birth=value
    @property
    def age(self):
        return 2023-self._birth  #age为只读属性1

多重继承

一个子类可以继承多个父类,这样的设计称为MixIn

class Animal(object):
    def fitht(self):
        return ('fighting!!!')
class Artificial(object):
    def think(self):
        return ('thinking!!!')
class Human(Animal,Artificial):
    def create(self):
        return ('creating!!!')
human=Human()
print(human.fitht())
print(human.think())
print(human.create())
'''
fighting!!!
thinking!!!
creating!!!
'''

定制类

python的class中有许多类似于__slots__的方法,这些方法其实就是有特殊用途的函数,将这些函数用于类的定义中,可以帮助我们定制类。

__str__

__str__()方法是用于打印简洁易懂的实例的:

class Student(object):
    def __init__(self,name):
        self.name=name
    def __str__(self):  #__str__方法是用于描述实例自身的输出方法,可以使打印出的实例简洁明了
        return 'Student object (name:%s)' % self.name
print(Student('Tom'))  #打印出一个实例,实例中name的值为Tom
'''
Student object (name:Tom)
'''

若不用__str__方法,打印出的实例比较复杂:

class Student(object):
    def __init__(self,name):
        self.name=name
print(Student('Moss')) 
'''
<__main__.Student object at 0x000002408B539390>
'''

之所以这里的实例这么复杂,是因为直接显示变量调用的不是__str__(),而是__repr__(),__str__()返回用户看到的字符串,__repr__()返回程序员看到的字符串,也就是说,__repr__()是为调试服务的。

__iter__

这个方法用于迭代类本身,这里以斐波那契数列为例:

class Fib(object):
    def __init__(self):
        self.a,self.b=0,1  #初始化两个计数器
    def __iter__(self):
        return self  #实例本身就是迭代对象,所以返回自己
    def __next__(self):
        self.a,self.b=self.b,self.a+self.b  #计算下一个值
        if self.a>100:
            raise StopIteration()
        return self.a
for n in Fib():
    print(n)

__getitem__

这个方法用于下标访问:

class Fib(object):
    def __getitem__(self,n):
        a,b=1,1
        for x in range(n):
            a,b=b,a+b
        return a
f=Fib()
for i in range(1,11):
    print(f[i])

__getattr__

这个方法用于,当我们调用实例的一个属性时,若该属性不存在,__getattr__会尝试将我们输入的属性通过预设的条件语句进行比对,返回错误提醒:

class Student(object):
    def __init__(self):
        self.name='Tom'
    def __getattr__(self,attr):
        if attr=='score':
            return 99
s=Student()
print(s.name)
print(s.score)
print(s.city)  #若属性不存在于比对条件中,则会输出none
'''
Tom
99
None
'''

__call__

一个对象实例有自己的方法,要进行简易的调用,可以使用__call__方法:

class Student(object):
    def __init__(self):
        self.name='Tom'
    def __call__(self):
        return ('My name is %s.' % self.name)
s=Student()
print(s())
'''
My name is Tom.
'''

在调用之前,我们要判断这个对象是否可以调用,这就需要用到callable()函数:

print(callable(s))
print(callable(Student))
print(callable(abs))
print(callable('123'))
print(callable([1,2,3,4,5]))
'''
True
True
True
False
False
'''

使用枚举类

from enum import Enum  #从enum模块中加载Enum类,即枚举类
Month=Enum('Month',('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'))
for name,member in Month.__members__.items():
    print(name,'=>',member,',',member.value)  #value属性是自动赋值给成员的int常量,默认从1开始计数
'''
Jan => Month.Jan , 1
Feb => Month.Feb , 2
Mar => Month.Mar , 3
Apr => Month.Apr , 4
May => Month.May , 5
Jun => Month.Jun , 6
Jul => Month.Jul , 7
Aug => Month.Aug , 8
Sep => Month.Sep , 9
Oct => Month.Oct , 10
Nov => Month.Nov , 11
Dec => Month.Dec , 12
'''

若要精确地为每个成员赋值可以从Enum派生出自定义类:

from enum import Enum,unique
@unique  #unique装饰器可以检查保证没有重复值
class Weekday(Enum):
    Sun=0
    Mon=1
    Tue=2
    Wed=3
    Thu=4
    Fri=5
    Sat=6
day1=Weekday.Thu
print(day1)
date1=Weekday.Sat.value
print(date1)
print(Weekday(0))
'''
Weekday.Thu
6
Weekday.Sun
'''

使用元类

type()

  • 用来查看一个类型或变量的类型:

class Tree(object):
    def __init__(self,height,age):
        self.height=height
        self.age=age
    def fruit(self):
        print('I\'m %d years old,%d meters high.' % (self.age,self.height))
tree=Tree(15,6)
print(type(Tree))
print(type(tree))
tree.fruit()
print(type(tree.fruit))
'''
<class 'type'>  #Tree的类型就是 类 type
<class '__main__.Tree'>  #tree是一个实例,它的类型就是Tree
I'm 6 years old,15 meters high.
<class 'method'>  #fruit的类型就是 方法 Method 
'''
  • type()函数还可以创建出新的类型:

def fn(self,name='world'):
    print('Hello,%s.' % name)
Hello=type('Hello',(object,),dict(hello=fn))  #创建出一个class对象
h=Hello()
h.hello()
print(type(Hello))
print(type(h))
print(type(h.hello))
'''
Hello,world.
<class 'type'>
<class '__main__.Hello'>
<class 'method'>
'''

要创建出一个class,需要传入type()函数三个参数:

  1. class的名称,用字符表示

  1. 继承的父类集合,这里的集合用元组表示,若元组内只有一个元素object,那么需要加一个逗号

  1. 最后将预先定义好的函数和这个class的方法进行逐一绑定,在括号内逐一赋值,然后转化为字典dict

metaclass

metalclass就是元类,类是元类的“实例”,元类是类的“类”,因此先定义metaclass,就可以创建类,最后创建实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值