python — 面向对象【3】

经典类和新式类

  • 在Python 2.x及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位 置),都属于“新式类”

  • 不由任意内置类型派生出的类,则称之为“经典类”。

  • “新式类”和“经典类”的区分在Python 3.x之后就已经不存在,在Python 3.x之后的版本,因为所有 的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”

  • 建议使用新式

经典类与新式类在类型上的区别

经典类

  • 所有的类都是classobj类型,而类的实例都是instance类型。

  • 类与实例只有通过class属性进行关联

新式类

  • 类实例的类型是这个实例所创建自的类(通常是和类实例的class相同)

#经典类
>>> class A:pass
>>> a = A()
>>> type(a)
<type 'instance'>
>>> a.__class__
<class __main__.A at 0x7fef2a9bd258>
#新式类
class A: pass
>>> a = A()
>>> type(a)
class '__main__.A'>

经典类与新式类的继承顺序

Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先

多重继承时,继承顺序 经典类和新式类是有区别的

  • 经典类 ———深度优先算法

  • 新式类 ———C3算法

class A:
    def test(self):
        print("from A")
class B(A):
    def test(self):
        print("from B")
class C(A):
    def test(self):
        print("from C")
class D(B):
    def test(self):
        print("from D")
class E(C):
    def test(self):
        print("from E")
class F(D,E):
    def test(self):
        print("from F")
f = F()
f.test()
#以上,会先找f自身,如果自身没有就先找D,D没有就找B(经典类和新式类一样)
#B没有,找A(0经典类)
#B没有,找E(新式类)
​
#mro方法解析序列
#经典类: F -->D -->B -->A -->E -->C
#新式类: F -->D -->B -->E -->C -->A

C3算法

静态方法、类方法、实例方法

属性

  • 静态属性(所有的实例共用一份=>引用)

  • 普通属性(每个实例都不同的数据=>引用)

方法

  • 普通(实例)方法(使用实例中的数据) => 给实例使用(一定要传递一个实例,由实例调用)

  • 静态方法(无需使用实例封装的内容@staticmethod)

  • 类方法(会自动加当前类的类名 @classmethod) => cls表示类本

各种方法的区别(@staticmethod、@classmethod)

  • 实例方法不能通过类名调用,但是静态方法和类方法是可以(不实例化访问)

  • 实例方法:可以通过self访问实例属性

  • 类方法:可以通过cls访问类属性(希望取的值不受实例影响时使用)

  • 静态方法:不可以访问,通过传值的方式

class A:
    name = "class A"
    def __init__(self):
         self.country = "china"
​
    #实例方法
    #第一个参数代表实例本身
    def normal_method(self,name):
        #方法的里面,及可以访问类属性,又可以访问实例属性
         print("normal")
         print(self.name,name)
​
    #类方法
    #第一个参数代表类 cls --类
    @classmethod
    def class_method(cls,name):
        #类方法里面,可以访问类属性
        print("classmethod")
        print(cls,cls.name)
​
    #静态方法
    @staticmethod
    def static_method(name):
        #静态方法里面,可以通过类名访问类属性
        print("static_method:",name,A.name)
a1 = A()
#############静态方法、实例方法、类方法都能通过实例去调用
# a1.normal_method("a1")
a1.class_method("a1")
# a1.static_method("a1")
​
#也可以通过类调用
# A.normal_method(a1,"A")
# A.class_method("A")
# A.static_method("A")

属性包装(@propert)

  • 把函数包装成属性,使用的时候用对象名.属性名

  • Person类中有一个属性为age,控制age的范围只能在0~150之间

属性包装的应用

property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检 查,这样,程序运行时就减少了出错的可能性

python类中的下划线

以下划线开头的标识符是有特殊意义的

以单下划线开头的(_foo)

  • 类:这类成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量

  • 模块:如果你写了代码“from <模块/包名> import *” ,那么以“_”开头的模块和包都不会被导 入,除非模块或包中的“all”列表显式地包含了模块和包

以双下划线开头的(__foo)

  • 类:只有类对象自己能访问,连子类对象也不能访问到这个数据。强行访问“对象名._类名 __xxx“这样的方式

  • 模块:不能用“from xxx import *“导入包/模块

以双下划线开头和结尾的( foo )

  • 代表Python中特殊方法专用的标识。其实,这只是一种惯例,对Python系统来说,这将确保不会 与用户自定义的名称冲突。

  • 例如init()代表类的构造函数。

  • 虽然你也可以编写自己的特殊方法名,但不建议用户使用这种命名方式

class P:
    """this is p"""
    _min = 1    #保护属性
    __max = 10    #私有属性
​
    def __init__(self):
        self.name = "sc"
        self._age = 4
        self.__desc = "it"
​
    def __make(self):
        print("这是一个私有方法")
        print(self.__desc)
    def _protectmake(self):
        print("这是一个保护方法")
    def show(self):
        print(self.__max,self.__desc)
​
class Child(P):
    def show(self):
        print(self.__max)
​
p = P()
c = Child()
print(c._min,p._min,Child._min,P._min)
#子类访问不到私有成员
# c.show()
# print(c.__make)
#类对象也不能访问私有成员
# print(P.__max)
# P.__make()
#私有成员只能在类的内部进行访问
# p.show()
#查看属性
# print(dir(p))
​
#python 中的似有都是伪私有,其实就是把双下划线开头的标识符,改了一个名字存储 _类名__标识符
# print(p._P__max)
​

常见的以双下划线和以双下划线结尾的特殊变量

#__dict__查看命名空间
# print(P.__dict__)   #类空间
# print(p.__dict__)   #实例空间
# __name__类名
print(P.__name__)
# def func1(cls):
#     a = cls()
#     print(f"{cls.__name__}进行了实例化")
# class A:
#     pass
# class B:
#     pass
# func1(A)
# func1(B)
#__class__查看对象属于那个类
print(p.__class__)
#__module__查看所在模块
print(P.__module__)
#__doc__查看文档注释
print(P.__doc__)  #help自动调用__doc__属性

常用魔术方法和属性

魔术方法:一般以双下划线开头和双下划线结尾,而且是特殊含义的方法,与一般不需要手动去调用,他会在某种特定的场景下自动执行

构造函数(__new__/__init__)

  • __new__:创建实例

  • __init__:初始化实例

  • 析构函数(__del__

    • 在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作, 如关闭一些数据库连接,关闭 打开的临时文件

  • 调用方法(__call__) • 把类实例化后的对象当做函数来调用的时候自动被调用

  • 获取数据(__getitem__

    • a[key]来访问对象,a[1:3]切片时调用__getitem__

  • 删除数据(__delitem__

    • del r[1] 时调用__delitem__方法

  • 设置数据(__setitem__

    • r['e']=213时调用__setitem__

  • 获取可迭代(__iter__

class A:
    def __del__(self):   #
        print("this is A.del")
​
a1 = A()
del a1   #手动释放
print("XXXXXX")
​
#####__call__
把实例化之后的对象当作函数去调用
class A:
    def __call__(self,name):
        print(f"i am A.__call__,name is {name}")
​
a1 = A()
a1("sc")
​
def func1():
    pass
print(dir(func1))
__getitem__
__setitem__
__delitem__
对象以字典的形式去设置或获取参数
class A:
    def __init__(self):
        self.data = {}
    def __getitem__(self,key):
        print("get data")
        return self.data.get(key,0)
    def __setitem__(self,key,value):
        print("set data:",key,value)
        self.data[key] = value
    def __delitem__(self,key):
        print("delete data")
        del(self.data[key])
​
a1 = A()
print(a1["key1"])
a1["key1"] = "XXXXXXXX"
del a1["key1"]
  • __str__

  • __repr__

__str__   __repr__
__str__ 给用户看的,调用方式a = A(),没有str就调用repr
__repr__给程序员看的 调用方式a
返回对象的描述信息
ie = IndexError("test")
print(ie)
​
class A:
    def __str__(self):
        return "this is A"
a1 = A()
print(a1)

查看类属性和方法

  • dir(Person):了解Person类里的变量和方法

  • Person.__dict__ :可以了解哪些是变量哪些是方法

内置属性及其功能

  • __dict__:类的属性(包含一个字典,由类的数据属性组成)

    • __doc__:类的文档字符串

  • __name__:类名

  • __module__:类定义所在的模块

  • __bases__:类的所有父类构成元素

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值