Python3学习笔记_D(面向对象)


笔记中代码均可运行在Jupyter NoteBook下(实际上Jupyter-lab使用体验也很棒)。

建议不要光看,要多动手敲代码。眼过千遭,不如手读一遍。

相关笔记的jupiter运行代码已经上传,请在资源中自行下载。

面向对象

'''
类:
class ClassName:
    pass

对代码基本相同的类抽取基类:当不同类中的方法基本相同时,
可以抽取出一个基类,用来简化代码

属性:

实例属性可以通过在__init__方法中设置,不必刻意写出

方法:

def func(self):
    pass
# 这里的self相当于java中的this,只是python中写成了self
'''
魔法方法
'''相当于java中的实例属性'''
__new__方法

通常__new__都不需要定义,在元类编程中才需要,它可以控制类的生成过程。

'''
__new__至少要有一个参数cls,代表要实例化的类,
此参数在实例化时由python解释器自动提供

__new__必须要有返回值,返回实例化出来的实例,
这点在自己实现__new__时要特别注意,
可以return父类__new__出来的实例,或者直接是object的__new__出来的实例

__new__(cls):这个方法在类被引用时会被执行
(自动的,如果不被创建,类会调用默认的__new__方法)
这里的cls此时指向的是类的名字[其实类是通过父类object.__new__(cls)来生成的]

__new__方法只负责创建,__init__方法只负责初始化

__init__的self参数就是__new__返回的实例,__init__在__new__的基础上完成初始化动作,__init__不需要返回值

注意,在创建对象时最先调用__new__方法,这时向类中添加参数会报错,
所以这时需要在__new__方法中设置虚参,只是一个样子,不需要用到
'''

# 在此比较java和c++中的构造方法,构造方法其实包含了Python中的这两个方法
'''单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。'''
# 创建单例对象:不管创建多少只有一个对象
class A(object):
    pass
d = A()
e = A()
print(id(d))
print(id(e))
#注意,这里的两个print的输出值并不相同
#这里不是单例模式

"""单例模式可以通过类变量来实现"""
# 这个单例模式只是一个例子,可以看出只能创建单例模式中的类属性,方法的创建就要添加参数
class A(object):
    __num = None
    def __new__(cls):
        if cls. __num == None: # 这里判断是否为第一次实例化
            cls.__num = object.__new__(cls) # 第一次实例化,进行实例化
            return cls.__num
        else :
            # 不是第一次实例化:返回上面生成的cls.__num
            return cls.__num

# 这里依据类属性在实例化对象中公用的原理,创建单例模式
'''在实例化a时,将A类的私有属性__num'''
a = A()
b = A()

print(id(a))
print(id(b))
#此时打印的a、b的id是相同的
#也就是表明此时是单例模式
139934035060440
139934035059712
139934035060216
139934035060216
__init__方法

用于初始化:初始化函数,将变量绑定到实例中,更新实例的__dict__字典。
其中第一个参数self就是__new__的返回值,是类的实例。__new__方法先于__init__方法执行。

# __init__方法:
class Demo:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return ('your name is {name},your age is {age}'.format(name = self.name,
                                                            age = self.age))
demo = Demo('shj', 22)
print(demo)
your name is shj,your age is 22
__str__方法

用于获取描述信息

# __str__方法:
class Demo:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return ('your name is {name},your age is {age}'.format(name = self.name,
                                                            age = self.age))
demo = Demo('shj', 22)
print(demo)
your name is shj,your age is 22
__del__方法

析构函数,释放对象时使用

在硬链接的obj完全删除时自动调用此方法,可视为善后处理

其他方法
''' 这些方法都是类(Class)专有方法
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方
'''
引用计数
'''
sys模块中的getrefcount()方法

sys.getrefcount() :用于查看一个对象被引用的次数

返回的值是引用次数+1(次数=返回值-1)
'''
# 引用计数例子
from sys import getrefcount


class DD:
    def __init__(self,info):
        self.info = info
    
    def __str__(self):
        return 'this is {} Demo'.format(self.info)
    
d1 = DD('d1')
d2 = DD('d2')

print(d1)
print(d2)
print('*'*8)

count = getrefcount(DD)-1
print('the getrefcount is {}'.format(count))
this is d1 Demo
this is d2 Demo
********
the getrefcount is 6
继承
'''
class sonClass(FatherClass):
    pass
世袭:子类可以继承父类(基类),也可以继承父类的父类

多继承

class sonClass(Base1, Base2, Base3):
    pass

继承后对方法的查找顺序:从左至右

可用className.__mro__打印这个类可调用的类

私有方法、私有属性不能被继承
但是调用的公有方法中包含私有方法或属性,这个公有方法可以被继承
'''
# 多继承例子

#类定义
class people:
    #定义基本属性
    name = ''
    age = 0
    #定义私有属性,私有属性在类外部无法直接进行访问
    __weight = 0
    #定义构造方法
    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w
    def speak(self):
        print("%s 说: 我 %d 岁。" %(self.name,self.age))
 
#单继承示例
class student(people):
    grade = ''
    def __init__(self,n,a,w,g):
        #调用父类的构函
        people.__init__(self,n,a,w)
        self.grade = g
    #覆写父类的方法
    def speak(self):
        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
 
#另一个类,多重继承之前的准备
class speaker():
    topic = ''
    name = ''
    def __init__(self,n,t):
        self.name = n
        self.topic = t
    def speak(self):
        print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
 
#多重继承
class sample(speaker,student):
    a =''
    def __init__(self,n,a,w,g,t):
        student.__init__(self,n,a,w,g)
        speaker.__init__(self,n,t)
 
test = sample("Tim",25,80,4,"Python")
test.speak()   #方法名同,默认调用的是在括号中排前地父类的方法
print('\nthe class sample can use BASE CLASS IS:\n {}'.format(sample.__mro__))
我叫 Tim,我是一个演说家,我演讲的主题是 Python

the class sample can use BASE CLASS IS:
 (<class '__main__.sample'>, <class '__main__.speaker'>, <class '__main__.student'>, <class '__main__.people'>, <class 'object'>)
重写
'''
子类重写父类方法和java相同

调用被重写的方法:
BaseClass.funcName()
super.funcName()

'''
'''多态:定义的方法根据传递进的方法的不同而得到不同的结果'''
# 一个多态的小例子

class F1(object):
    def show(self):
        print ('F1.show')

class S1(F1):
    def show(self):
        print ('S1.show')

class S2(F1):
    def show(self):
        print ('S2.show')

# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象
'''
对java或C#
def Func(F1 obj):
    """Func函数需要接收一个F1类型或者F1子类的类型"""

    print (obj.show())
'''
# python
def func(obj):
    obj.show()
    print("*"*8)


s1_obj = S1()
func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show

s2_obj = S2()
func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
S1.show
********
S2.show
********
类属性
'''
定义在class内部,但是在方法外部的变量称为类的属性
类属性属于类,并且类属性在实例间共享
'''
实例属性
'''
和具体的某个实例对象有关,在类内部的实例属性不同实例对象共用,类外部单独创建的实例属性不共用

实例属性和类属性重名会强制覆盖类属性,但是无法通过实例属性对类属性进行更改
'''

有关类方法、实例方法、静态方法的笔记参考了蔷薇Nina这位朋友的笔记

导向链接

https://www.cnblogs.com/wcwnina/p/8644892.html

类方法

类的方法,需要在方法前添加@classmethod
注意:类方法必须有有一个cls变量做形参,这个cls表示类本身(当前类对象)
,通过它来传递类的属性和方法(不能传实例的属性和方法);

调用:实例对象和类对象都可以调用。

@classmethod
def classFunc(cls): # 这里必须要定义一个形参,名称无所谓,惯用cls,这个变量表示类本身
    pass

原则上,类方法是将类本身作为对象进行操作的方法。
假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。
另外,如果需要继承,也可以定义为类方法。

# 假设我有一个学生类和一个班级类,想要实现的功能为:
#     执行班级人数增加的操作、获得班级的总人数;
#     学生类继承自班级类,每实例化一个学生,班级人数都能增加;
#     最后,我想定义一些学生,获得班级中的总人数。

# 思考:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,
# 但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。
# 同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import hashlib
from math import pi


class ClassRoom(object):
    __num = 0

    @classmethod
    def add_num(cls):
        cls.__num += 1

    @classmethod
    def get_num(cls):
        return cls.__num

    def __new__(self):
        ClassRoom.add_num()
        return super().__new__(self)


class Student(ClassRoom):
    def __init__(self):
        self.name = ""


stu_a = Student()
stu_a.name = "lee"
stu_b = Student()
stu_b.name 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值