python学习之面向对象(四)

6.9 反射

反射是非常重要的内置函数之一。

反射是通过字符串去操作对象相关的属性,这里的对象包括:实列,类,当前模块,其他模块。

主要的四个函数:

查看: hasattr(对象,待查内容的字符串形式) 判断有没有,返回True或者False

获取: getattr(对象,要获取的内容的字符串形式,获取不到时的返回值)

增加: setattr(对象,要增加的内容的字符串形式)

删除: delattr(对象,要‘删除的内容的字符串形式)

6.9.1 实例化中使用

class LOL:
    place = '召唤师峡谷'
    def __init__(self,name,role):
        self.name = name
        self.role = role
    def equip(self):
        print('装备什么')

gailun = LOL('盖伦','战士')
print(gailun.name)

print(hasattr(gailun,'name'))
print(getattr(gailun,'name'))
print(getattr(gailun,'team','没有此属性'))

setattr(gailun,'team','德玛西亚')
print(getattr(gailun,'team','没有此属性'))
print(gailun.__dict__)

delattr(gailun,'team')
print(getattr(gailun,'team','没有此属性'))

# 通过hasattr判断,通过getattr获取,来操作对象的属性和方法
if hasattr(gailun,'equip'):   #判断对象里面有没有
    print(getattr(gailun,'equip'))  #若果有,看拿到的是什么
    getattr(gailun,'equip')()   #操作对象的方法

6.9.2 类中使用

class LOL:
    place = '召唤师峡谷'
    def __init__(self,name,role):
        self.name = name
        self.role = role

    def equip(self):
        print(self)
        print('装备什么')

gailun = LOL('盖伦','战士')

print(hasattr(LOL,'place'))
print(hasattr(LOL,'equip'))
getattr(LOL,'equip')(gailun)

6.9.3 当前脚本中使用

class LOL:
    place = '召唤师峡谷'
    def __init__(self,name,role):
        self.name = name
        self.role = role

    def equip(self):
        print(self)
        print('装备可以加强属性')

def func1():
    print('in func1')
def func2():
    print('in func2')
def func3():
    print('in func3')

# 获取当前脚本并把它赋值给一个变量
import sys
this_module = sys.modules[__name__]  #当前脚本这个对象
if print(this_module,'func1'):
    getattr(this_module,'func1')()

cla = getattr(this_module,'LOL')   #可以获取当前脚本中的类
cla.equip(cla)
nvjing = cla('凯特琳','射手')
print(cla)
print(nvjing)
print(nvjing.__dict__)

# 将以上函数的函数名的字符串形式放到列表中
l = [f"func{i}" for i in range(1,4)]
for item in l:      # 利用getattr运行l列中的函数
    getattr(this_module,item)(

6.9.4 其他模块中使用

在另一个py文件中,设置

# 反射2.py
def fun1():
    print('in fen1')
aa = 'aa'

在本文件中调用反射2.py中的函数

import 反射2 as other
getattr(other,'fun1')()

6.9.5 场景使用

class Auth:

    def login(self):
        print('登录函数')

    def register(self):
        print('注册函数')

    def exit(self):
        print('退出...')

obj = Auth()
while 1:
    func_name = input('请输入选择:').strip()
    if hasattr(Auth,func_name):
        getattr(Auth,func_name)(obj)

6.10 函数与方法的判断

该节旨在体验双下发放的触发情况,所以使用print和return来帮助提示相关方法的执行

通过名称

通过名称可以大致判断

def func1():
    pass

class A:
    def func(self):
        pass

print(func1)
obj = A()
print(obj.func)
# 输出信息中含有function的就是函数
# 输出的信息中含有bound method的就是方法

通过type模块验证

from types import FunctionType
from types import MethodType

def func():
    pass
class A:
    def func(self):
        pass
obj = A()
print(isinstance(func,FunctionType))       #True
print(isinstance(func,MethodType))         #False
print(isinstance(A.func,FunctionType))     #True   func在类中是函数
print(isinstance(obj.func,FunctionType))   #Flase
print(isinstance(obj.func,MethodType))     #True  func在对象中是方法

定义在类中的共有函数,在类中是函数,在对象中是方法

类的静态方法是函数

类方法是一种方法,静态方法是一种函数

对于写在类内部的静态方法实际上是函数,而类方法就是一种方法

from types import FunctionType
from types import MethodType

class A:

    @classmethod
    def func1(cls):
        pass

    @staticmethod
    def func2(self):
        pass
obj = A()

print(isinstance(A.func1,FunctionType))       #False
print(isinstance(A.func1,MethodType))         #True
print(isinstance(obj.func1,FunctionType))     #False
print(isinstance(obj.func1,MethodType))       #True
print(isinstance(A.func2,FunctionType))       #True
print(isinstance(A.func2,MethodType))         #False
print(isinstance(obj.func2,FunctionType))     #True
print(isinstance(obj.func2,MethodType))       #False

函数与方法的区别

函数是显式传递数据,俗话说,函数一般需要传参
函数与对象无关

方法中的数据是隐式传递数据
方法可以操作类内部的数据
方法是跟对象相关的

6.11 双下方法

双下方法主要是针对开发python语言的设计使用的,要慎用。

双下方法是具有特殊意义的方法,其执行方式也比较特殊,不同的双下方法有不同的触发方式。

__len__方法

一个对象之所以能够使用len()函数,根本原因是该对象的父类中含有__len__函数,在使用len()时,类中的__len__函数就会执行,并返回一个int值给调用者。

class A:
    def __len__(self):
        print('aaa')
        return 1

obj =  A()
print(len(obj))

__hash__方法

能够使用hash()函数的对象的父类内含有__hash__函数,并由hash()触发

class A:
    aa = 'aa'
    def __hash__(self):
        print('正在执行hash函数')
        return 1
obj = A()
print(hash(obj))

__repr__方法

如果类中定义了__repr__函数,repr对象时,默认输出该函数的返回值

class A:
    def __init__(self):
        pass
    def __repr__(self):
        return '输出__repr__的返回值'

obj = A()
print(repr(obj))
print('%r' %obj)

__str__方法**

如果类中定义了__str__函数,print对象时,默认输出该函数的返回值

class A:
    def __init__(self):
        pass
    def __str__(self):
        return '输出__str__的返回值'

obj = A()
print(obj)
print('%s' %obj)

__call__方法**

如果类中定义了__call__函数,实例化对象后,对象()或者A()()就能触发该函数

class A:
    def __call__(self):
        print('可以返回很多的内容,形式多样')
obj = A()
print(obj())
A()()

__del__方法**

析构方法,当对象在内存中被释放时,自动触发执行。

python本身具有垃圾回收机制,大多数情况下我们不必要去关心内存的分配与释放,该函数略显鸡肋

class A:
    def __del__(self):
        print('清空内存')
obj = A()
del obj
如果该程序运行结束,即使没有使用del也会触发__del__

__eq__方法

进行 == 比较时,就会触发该方法

class A:
    def __init__(self):

        self.aa = 11
        self.bb = 22
    def __eq__(self,obj):
        if self.aa == obj.aa and self.bb == obj.bb:
            print('正在执行__eq__')
obj1 = A()
obj2 = A()
print(obj1 == obj2)
class A:
    def __init__(self):

        self.aa = 11
        self.bb = 22
    def __eq__(self,obj):
        if self.aa == obj.aa and self.bb == obj.bb:
            print('正在执行__eq__')
class B(A):
    pass

obj1 = A()
obj2 = B()
print(obj1 == obj2)

__new__方法**

__new__真正的创建并返回一个对象的方法。实例化对象时,其实首先执行的是__new__创建内存空间

class A:
    def __init__(self):
        self.aa = 1
        print('创建了对象')

    def __new__(cls, *args, **kwargs):  #第二步:执行__new__,这里测试使用,没有创建对象空间的作用
        ret = super().__new__(cls, *args, **kwargs)   #执行一下父类的__new__创建对象使用,
        print('执行__new__对象')
        return ret

obj = A()   #第一步,类名()
s = obj.aa
print(obj)

类名()触发__new__并将类名自动传给cls

单例模式(设计模式)***

一个类只能实例化一个对象,无论实例化多少次,内存中都只有一个改类的对象

单例模式设计

class A:
    __instance = None  #对象空间

    def __new__(cls, *args, **kwargs):
        if not cls.__instance :  #如果没有创建过对象
            ret = super().__new__(cls, *args, **kwargs)   #创建一个对象
            cls.__instance = ret
        return cls.__instance

obj = A()
print(obj)
obj1 = A()
print(obj1)

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
【采用单例模式动机、原因】
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
【单例模式优缺点】
【优点】
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
【缺点】
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用

__item__系列

当对实例化的对象进行类似于字典的操作时,会触发__item__系列对应的方法

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

    def __getitem__(self, item):
        print(self.__dict__[item])
        print('在使用字典的方式查看属性时,getitem执行')

    def __setitem__(self, key, value):
        self.__dict__[key] = value
        print('在使用字典的方式添加属性时,setitem执行')

    def __delitem__(self, key):
        print('del obj[key]时,delitem执行')
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print('del obj.key时,我执行')
        self.__dict__.pop(item)

gailun = LOL('盖伦')
gailun['age'] = 18
print(gailun.__dict__['age'])
print(gailun.age)
del gailun['age']
del gailun.age
print(gailun.__dict__['age'])

难点

class StarkConfig:
    def __init__(self,num):
        self.num = num

    def run(self):
        self()

    def __call__(self, *args, **kwargs):
        print(self.num)

class RoleConfig(StarkConfig):
    def __call__(self, *args, **kwargs):
        print(1234567)

    def __getitem__(self, item):
        return self.num[item]

v1 = StarkConfig('sam')
v2 = RoleConfig('john')
v1.run()

上下文管理器相关

__enter__ __exit__这两个方法能够把对象像文件一样进行操作

# 如果没有这两个函数时,不能进行 with as 操作
class A:
    def __init__(self,txt):
        self.txt = txt

with A('盖伦') as f1:
    print(f1.txt)
class LOL:
    def __init__(self,name):
        self.name = name

    def __enter__(self):
        self.name  = '召唤' + self.name
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.name = self.name + '进行战斗'
        return self

with LOL('盖伦') as f1:
    print(f1.name)  #召唤盖伦
print(f1.name)  #召唤盖伦进行战斗

应用到文件中

class Opperation:
    def __init__(self,name,mode):
        self.name = name
        self.mode = mode

    def __enter__(self):
        print('这里是入口')
        self.file = open(self.name,self.mode)
        return self.file
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()
        print('已关闭')

with Opperation('test.py','r') as f:
    for item in f:
        print(item)

打开文件前显示  ----  这里是入口
文件关闭时显示  ----  已关闭

练习

class UserInfo:
    pass
class Department:
    pass

class StarkConfig:
    def __init__(self,num):
        self.num = num

    def change(self,request):
        print(self.num,request)

    def run(self):
        self.change(999)

class RoleConfig(StarkConfig):
    def change(self,request):
        print(666,self.num)

class AdminSite:
   def __init__(self):
       self._registry = {}

   def register(self,k,v):
       self._registry[k] = v(k)

site = AdminSite()
site.register(UserInfo,StarkConfig)
site.register(Department,RoleConfig)

for k,v in site._registry.items():
    v.run()
class StarkConfig:
    def __init__(self,num):
        self.num = num

    def run(self):
        self()

    def __call__(self, *args, **kwargs):
        print(self.num)

class RoleConfig(StarkConfig):
    def __call__(self, *args, **kwargs):
        print(1234567)

    def __getitem__(self, item):
        return self.num[item]

v1 = StarkConfig('sam')
v2 = RoleConfig('john')
v1.run()
class A:
    list_display = []

    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display
s = A()
print(s.get_list())  # [33]
class A:
    list_display = [1,2,3]
    def __init__(self):
        self.list_display = []
    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display
s = A()
print(s.get_list())  # [33]
class A:
    list_display = []
    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display
class B(A):
    list_display = [11,22]

s = B()
print(s.get_list())    #[33,11,22]

原文地址:https://www.cnblogs.com/jjzz1234/p/11178724.html

时间: 2024-11-11 04:55:44

python学习之面向对象(四)的相关文章

Python学习系列(四)Python 入门语法规则2

Python学习系列(四)Python 入门语法规则2 2017-4-3 09:18:04 编码和解码 Unicode.gbk,utf8之间的关系 2.对于py2.7, 如果utf8>gbk, utf8解码成Unicode,再将unicode编码成gbk 对于py3.5 如果utf8>gbk, utf8 直接编码成gbk(中间那一步直接被优化了) 3.很多时候,这个可以直接跳过,只有当编码出下问题的时候,再考虑这个知识点 二.运算符 1.算数运算: 2.比较运算: 3.赋值运算: 4.逻辑运算

python学习记录第四篇--数据库

只要用到MySQLdb,使用时请先安装MySQLdb,百度上可以下载! #coding=utf-8'''@author: 使用python操作MySQL数据库'''import MySQLdb#import MySQLdb.cursorsconn=MySQLdb.connect(user='root',passwd='root') #connect共三个值,user,passwd,host,无密码且连接本地数据库时,可以都为空.cur=conn.cursor() #创建游标,使用游标进行数据库操

Python学习系列(四)(列表及其函数)

Python学习系列(四)(列表及其函数) Python学习系列(一)(基础入门) Python学习系列(二)(基础知识) Python学习系列(三)(字符串) 一.基本概念 1,列表是什么? 一种序列型数据类型,一有序数据集合用逗号间隔用方括号括起来. 2,几种访问形式 1)索引访问,语法结构:list_name[index].注意,列表的索引值从0开始.例如: 1 >>> li=[1,2,3,4,5] 2 >>> print li[2],li[0] 3 3 1 删除

python 学习_第四模块 并发编程(多线程)

python 学习_第四模块 并发编程(多线程) 1  开启线程方式 from threading import Thread import time def say(name): time.sleep(2) print("%s hello"%name) if __name__ =="__main__": t = Thread(target=say,args=("alex",)) t.start() print("主线程")

python学习之面向对象高级特性

类属性与实例属性类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本.在前面的例子中我们接触到的就是实例属性(对象属性),它不被所有类对象的实例对象所共有,在内存中的副本个数取决于对象个数. 05_类属性鱼实例属性.py import random class Turtle(object): # power是类属性. power = 100 def __init__(self): # x,y:实例属性. self.x = random.randint(0, 10)

Python学习笔记-面向对象

一.什么是面向对象的程序设计 1.面向过程的程序设计 面向过程:核心是过程二字,过程即解决问题的步骤,就是先干什么,再干什么.基于该思想写程序就好比在设计一条流水线,是一种机械式的思维方式. 优点:复杂的过程流程化,进而简单化 缺点:扩展性差 2.面向对象的程序设计 面向对象:核心是对象二字,对象是特征与技能的结合体.基于该思想编写程序就好比在创造一个世界,世界是由一个个对象组成,是一种"上帝式"的思维方式 优点:可扩展性强 缺点:编程复杂度高,容易出现过度设计问题 二.类与对象 对象

python学习第十四天 -面向对象编程基础

python也是支持面向对象编程的.这一章节主要讲一些python面向对象编程的一些基础. 什么是面向对象的编程? 1.面向对象编程是一种程序设计范式 2.把程序看做不同对象的相互调用 3.对现实世界建立对象模型 面向对象编程的基本思想: 1.类用于定义抽象类型 2.实例根据类的定义被创建出来 如何定义一个类并创建实例? >>> class Animal(object): pass >>> dog = Animal() >>> cat = Animal

Python 学习笔记 - 面向对象(类成员)

上一篇学习了Python面向对象的3大特性,封装,继承和多态,这一篇继续学习类成员,包括字段,方法,属性以及他们的修饰符. 1.字段 字段分为静态字段和普通字段.静态字段属于类,而普通字段属于对象,因此静态字段在内存中只保存一份,而普通字段在每个对象中都保存了一份.定义的时候静态字段定义在类的范围里面,而普通字段定义在方法里面. 例如: >>> class Foo:     # 字段(静态字段)     CC = 123     def __init__(self):         #

Python 学习笔记 - 面向对象(基础)

之前学习的编程方式都是通过面向过程来实现的,对于一些重用的代码,进一步的使用了函数,增强了代码的可读性和重用性.Python同时还支持面向对象的编程. 面向对象有三大特性: 封装 继承 多态 首先来看看封装.封装包括两点,把内容封装到某个地方:调用封装的内容 例1: class c1:     def __init__(self,name,obj):         self.name = name         self.obj = obj class c2:     def __init_