进阶学python:python面向对象系列之魔法方法!(代码片段)

程序员_宇宁 程序员_宇宁     2022-12-28     230

关键词:

本篇主要介绍面向对象编程中类的魔法属性,这些魔法属性均有其特殊的功能,即执行某些操作时,会自动触发这些魔法方法的执行,了解这些魔法方法可以更好的了解面向对象编程的实现原理;

在学习魔法方法之前,我们先了解其他两个方法:

isinstance()issubclass()

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   demoOne.py
@Time    :   2019/10/30 08:52:50
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib

class A(object):
    pass
class B(A):
    pass

b = B()

# isinstance(o,c) -- 判断前者是否为后者所创建的对象
print(isinstance(b,A))  # True
print(isinstance(b,B))  # True

# issubclass --判断前者是否为后者的子类
print(issubclass(B,A))  # True

反射:hasattr、getattr、setattr、delattr 四个内置函数

  • 反射,又称自省(自我反省),该概念是由Smith于1982首次提出的,是指主要是指程序可以访问、检测和修改它本身状态或行为的一种能力;
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   fansheDemo.py
@Time    :   2019/10/30 08:54:08
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


class Programmer(object):
    """定义一个程序员类"""
    character = "intelligent"  # 特点:聪明

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

    def write_code(self):  # 写代码
        pass

    def debug(self):  #调试
        pass


p = Programmer("Mr_Chen", 21, "male")

# hasttr  - 查看该对象是否可以使用该属性或者方法
print(hasattr(p, "name"))
print(hasattr(p, "debug"))

# getattr - 获取对象属性
print(
    getattr(p, "write_code")
)  #<bound method Programmer.write_code of <__main__.Programmer object at 0x0000016F87ABBFD0>>
print(getattr(p, "character"))  # == p.character

# 可以指定第三个参数,当属性不存在时返回该值,而不会报错
# print(getattr(p,"balabala")) # 报错
print(getattr(p, "balabala", "不存在的"))

# setattr -修改对象属性
setattr(Programmer, "character",
        "handsome")  # == Programmer.character = "handsome"
print(p.character)  # handsome

# delattr - 删除该属性
delattr(p, "name")  # == del p.name
print(p.__dict__)  #'age': 21, 'gender': 'male',name没啦
delattr(Programmer, "debug")
print(Programmer.__dict__)  #debug属性没啦

反射的优点:可实现一种可插拔机制,例如:在实际项目的开发过程中,通常是多个程序员配合区完成一个大的项目,假如程序员A在开发过程中需要用到程序员B定义的类,但是程序员B请假陪老婆生孩子了,代码没有完成,这时候程序员B可以使用反射的机制继续去完成自己的代码,例如:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   yuanDemo1.py
@Time    :   2019/10/30 08:56:26
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


# 程序员A --moduleA
class A(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


# ---------------------------------------------------------
# 程序员B
from moduleA import A
a = A(10, 20)
if hasattr(a, "cal"):  # 判断是否有该计算方法,不管有没有不影响我其他逻辑的书写和调试
    print(a.cal())
else:
    print("该计算方法没有定义")
    print("继续执行其他的逻辑")

魔法方法

__doc__ 查看类的描述信息

class Foo(object):
    """这是一段关于该类的介绍和描述"""
    pass

print(Foo.__doc__)  #这是一段关于该类的介绍和描述
__module__ 和 __class__
前者查看当前操作的类所在模块,后者查看当前对象的类是什么;

class Bar(object):
    pass

b1 = Bar()
print(Bar.__module__)  # __main__   ----》当前文件所在模块
print(Bar.__class__)  # <class 'type'>
print(b1.__class__)  # <class '__main__.Bar'>

# 注:从上述结果可以看出,类也是对象,该Bar类对象其是由type类实例化得到的,而对象b1是由当前模块的Bar类实例化得到的
__init__  构造方法
当通过类实例化成对象时,自动触发执行__init__方法。
该方法下定义的属性即为实例属性,即会自动开辟一个内存空间,
用来存放该实例对象的属性和类方法的指针。

class Foo(object):
    # 构造方法
    def __init__(self,name):
        self.name =name
        print("in the init")

foo = Foo("sunny chen")   # in the init
__del__ 方法
当由该类创建的实例对象,被删除或者说在内存中被释放时,将会自动触发执行。

class Foo(object):
    # 析构方法
    def __del__(self):
        print("in the __del__")

foo = Foo()
del foo  # in the __del__

此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。当然我上面重新了析构方法时,则无法真正内存回收,底层会有很多实现的功能被封装。

__call__   对象后面加括号,触发执行。

class Bar(object):
    pass

bar = Bar()
# bar()    # TypeError: 'Bar' object is not callable

# 当一个类中有__call__,其实例化得到的对象便是可调用的即callable
class Foo(object):

    def __call__(self):
        print("in the call")

foo = Foo()
foo()  # in the call

构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 *call* 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

__dict__   类或者实例的属性字典
类或这实例的属性字典,用来存放类或者实例的属性和方法;

class Bar(object):
    gender = "male"
    def __init__(self,name):
        self.name = name
    def tt(self):
        pass

bar = Bar("sunny chen")
print(Bar.__dict__)
# 输出为:'__module__': '__main__', 'gender': 'male', '__init__': <function Bar.__init__ at 0x0000020F94F10B70>, 'tt': <function Bar.tt at 0x0000020F94F10BF8>, '__dict__': 
# <attribute '__dict__' of 'Bar' objects>, '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None

print(bar.__dict__)
#'name': 'sunny chen'

该属性字典中以键值对的形式,存放类对象的属性和其对应的值 、方法和其对应的方法指针。

__str__方法

class Bar(object):

    def __str__(self):
        return "<bar object <Bar> at 000000xxxx>"

# 如果一个类中定义了__str__方法,那么在打印对象 时,默认输出该方法的返回值。
bar = Bar()
print(bar)  # <bar object <Bar> at 000000xxxx>


# 其实在其他的对象中也是这样实现,当打印该对象给用户一些提示信息
import threading
def test():
    pass
t = threading.Thread(target=test)
print(t)  #<Thread(Thread-1, initial)>

该方法当用户不清楚该实例对象是什么时,通过打印的方式自动执行该类的内部的__str__方法,用来给用户一定的提示信息。

__getattr__、__setattr__、__delattr__

在学习这三个魔法方法时,我们先了解一下一个概念叫反射,其通过四个内置函数来实现的效果,即 hasattr、getattr、setattr、delattr ;其实当我们调用后面三个方法时,便是执行了类中的魔法方法;例如:

#---------------- copy---------------
class Foo:
    x=1
    def __init__(self,y):
        self.y=y

    def __getattr__(self, item):
        print('----> from getattr:你找的属性不存在')


    def __setattr__(self, key, value):
        print('----> from setattr')
        # self.key=value #这就无限递归了,你好好想想
        # self.__dict__[key]=value #应该使用它

    def __delattr__(self, item):
        print('----> from delattr')
        # del self.item #无限递归了
        self.__dict__.pop(item)

#__setattr__添加/修改属性会触发它的执行
f1=Foo(10)
print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
f1.z=3
print(f1.__dict__)

#__delattr__删除属性的时候会触发
f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
del f1.a
print(f1.__dict__)

#__getattr__只有在使用点调用属性且属性不存在的时候才会触发
f1.xxxxxx
__getitem__、__setitem__、delitem__

用法与上面三种十分相似,只是触发的方式不太相同,上面的attr魔法方法是通过点" . “的方式调用触发,而后者item魔法方法是通过字典”[ ]"的方式调用触发;例如:

class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        print("in the setitem.")
        self.__dict__[key]=value

    def __delitem__(self, key):
        print('in the delitem..')
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print('in the delattr..')
        self.__dict__.pop(item)

# obj.["key"]的方式触发__xxxitem__魔法方法
f1=Foo("sunny chen")
ret = f1["name"]  # 触发__getitem__执行
f1["age"]=18   # 触发__setattr__执行


del f1['age']  # 触发__delitem__执行
f1['name']='sunny'
del f1.name  # 触发__delattr__执行
print(f1.__dict__)
  1. 当然还有[迭代器和生成器];

快去动手试试吧!

进阶学python:python面向对象基础!(代码片段)

什么是编程范式?在了解面向对象编程之前,我们需要了解三大编程范式以及其之间的区别和利弊即:面向过程编程、函数式编程、面向对象编程。编程:是程序员用特定的语法+数据结构+算法组成的代码来... 查看详情

进阶学python之pandas系列之导出为.csv文件(代码片段)

本文所用表格内容如下:本文所用表格内容如下:商品信息表1.设置导出路径和前面保存为.xlsx差不多,只是.csv文件的路径是通过path_or_buf参数设置的importpandasaspd​goods_df=pd.read_excel(r'C:\\Users\\viruser.v-desktop\\Desktop\\商品信息表.xls... 查看详情

面向对象之进阶继承

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生或子类Python中类的继承分为:单继承和多继承在python3中,所有类默认继承boject但凡是继承了object类的子... 查看详情

面向对象之进阶

简介:python中关于OOP的常用术语面向对象的软件开发一、Python中关于oop的常用术语抽象/实现抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于绘程序结构,从而实现这种模型。抽象不仅包括... 查看详情

python之面向对象知识点汇总(小白必会)(代码片段)

目录Python基础之面向对象一、编程思想1、面向过程2、面向对象二、类与对象的创建1、类的语法结构2、定义与调用3、给对象添加独有属性4、对象独有属性修改三、动态、静态方法1、直接在类中定义的函数2、绑定给类的函数3、... 查看详情

python基础详解

...浅copypython文件操作python函数部分python函数初识python函数进阶python装饰器python迭代器,生成器python内置函数,匿名函数python递归函数python二分查找算法python面向对象部分01面向对象之:初识02面向对象之:类空间问题以及类之间的关系03... 查看详情

进阶学python之python的open函数之文件处理(代码片段)

文件处理的流程:打开文件,得到文件句柄并将其赋值给一个变量通过文件句柄对文件进行操作(其实文件句柄本身是一个迭代器对象。)关闭文件(即释放操作系统分配的内存空间)请先创建一个test.txt... 查看详情

零基础学pythonday16python面向对象(代码片段)

昨天跟大家一起学习了Python异常处理,回顾之前内容看这里零基础学Python,今天让我们开始学习Python面向对象吧。需注意的是,【零基础学Python】此系列都使用Python3。面向对象说面向对象之前,我们先聊下什么是... 查看详情

零基础学pythonday16python面向对象(代码片段)

昨天跟大家一起学习了Python异常处理,回顾之前内容看这里零基础学Python,今天让我们开始学习Python面向对象吧。需注意的是,【零基础学Python】此系列都使用Python3。面向对象说面向对象之前,我们先聊下什么是... 查看详情

python进阶—面向对象编程(代码片段)

目录文章目录目录面向对象思想面向对象编程面向对象编程的特性封装继承多态面向对象编程的优势Python的类属性与类方法Python类的实例化Python的对象属性与对象方法Python类的继承面向对象思想面向对象不仅是一种编程思想࿰... 查看详情

8--oop

oop-Python面向对象Python的面向对象面向对象编程基础共有私有继承组合,Mixin魔法函数魔法函数概述构造类魔法函数运算类魔法函数1.面向对象概述(ObjectOriented,00)OOP思想几个名词OO:面向对象OOA:面向对象的分析OOD:面向对象的... 查看详情

面向对象进阶

目录面向对象进阶classmethod和staticmethodclassmethodstaticmethodisinstance和issubclassisinstanceissubclass反射魔法方法单例模式面向对象进阶Wisdomisknowingwhattodonext,virtueisdoingit.classmethod和staticmethodclassmethod装饰给类内部的方法 查看详情

javascript初探系列之面向对象

    面向对象的语言有一个标志,即拥有类的概念,抽象实例对象的公共属性与方法,基于类可以创建任意多个实例对象,一般具有封装、继承、多态的特性!但JS中对象与纯面向对象语言中的对象是不同的,ECMA标... 查看详情

python面向对象进阶(代码片段)

在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息。为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解。@pr... 查看详情

python面向对象编程进阶(代码片段)

python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super)isinstance(obj,cls)检查是否obj是否是类cls的对象1classFoo(object):2pass34obj=Foo()56isinstance(obj,Foo)issubclass(sub,super)检查sub类是否是super类的派生类1class 查看详情

python面向对象编程进阶(代码片段)

前言上上篇我们讲解了Python面向对象编程的基础知识,《Python基础篇:面向对象怎样炼成的》这篇我们继续来讨论面向对象编程相关的内容。目录前言可见性和属性装饰器动态属性静态方法和类方法继承和多态总结可见... 查看详情

测开之面向对象进阶篇・《多态》(代码片段)

面向对象三大特征面向对象编辑的三大特征:封装、继承、多态。封装:客观的失误封装成类(将数据和方法放在一个类中构成了封装)。继承:python中一个类可以继承于一个类,也可以继承多个类,... 查看详情

python基础——魔法方法

...性访问魔法方法前面在介绍类和对象时,已经接触过Python常用的魔法方法,那么什么是魔法方法呢?魔法方法总是被下划线包围,例如__init__()。魔法方法是面向对象的Python的一切,如果不知道魔法方法,... 查看详情