python(11)面向对象

本文深入探讨了面向对象编程的概念,包括类的定义、对象的创建、属性和方法的使用。通过示例展示了如何定义类、初始化对象以及如何使用属性和方法。同时,讲解了类的静态属性、动态导入模块、反射机制以及描述符的使用。文章还涵盖了元类、继承、多态等核心特性,并提供了实际代码示例来帮助理解。
摘要由CSDN通过智能技术生成
有很多函数,把这些函数按照一定的关系聚堆,叫做分类
类就是一堆函数的合集
类就是某样东西
这个东西可能是人,有固定的属性,比如名字,生日,身份信息
如果是个活的,还会做出某些行为,就是方法
具体某一个人,这个人就是这个类的对象

类:把一类事物的相同的特征和动作整合到一起就是类
	类是一个抽象概念
对象:就是基于类而创建的一个具体的事物
	也是特征和动作整合到一起

一、基础####################
使用函数写一个面向对象设计
def school(name, addr, type):
    def init(name, addr, type):
        school_attribute = {
            "name": name,
            "addr": addr,
            "type": type,
            "exam": exam,
            "recruit":recruit}
        return school_attribute		#返回属性和动作的字典,方便调用
    def exam(school):
        print("%s 正在考试" % name)
    def recruit(school):
        print("%s 是一所 %s 学校,坐落在 %s" % (name, type, addr))
    return init(name, addr, type)	#初始化

s = school("清华", "北京", "公办")
print(s)
#{'name': '清华', 'addr': '北京', 'type': '公办', 'exam': <function school.<locals>.exam at 0x0000025C0C13BF28>, 'recruit': <function school.<locals>.recruit at 0x0000025C0C161048>}
print(s["name"])
#清华
s["recruit"](s)
#清华 是一所 公办 学校,坐落在 北京

#######################################
面向对象编程

class 类名:
	'类的文档字符串'
	类体

class 类名(父类):
	'类的文档字符串'
	类体
类
	变量属性		==》》数据属性
	函数属性		==》》方法属性
print(dir(classname))		#输出类的所有属性(包含隐藏属性)
print(classname.__dict__)	#查看类属性字典
	#可以通过key来调用
__name__		#类名
__doc__			#类的文档
__base__		#类的第一个父类
__bases__		#类的所有父类构成的元组
__module__		#类定义所在的模块
__class__		#实例对应的类(仅新式类中)

##############
class Chinese:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    def play_ball(self, ball):
        print("%s 正在打 %s" % (self.name, ball))
#############
def __init__(self,xx,xxx,)	#实例化的时候,会直接调用初始化函数,自动返回实例对象的属性字典,不需要自己return。里面的属性只属于实例自己,不是类的

self就是实例本身,会自动传给self,
如果类的方法参数中没有self,实例调用该方法,会报错

类具有增删改查
直接=
del

实例有增删改查
可以增加方法,但是只属于自己,不会影响到类
且不会自动把自己传给self

注意:
	实例操作类属性时,  =  和  append的坑

**********区别:类调用和实例调用*****

二、############################################################################
静态属性:		#就是数据属性


@property		#封装一段逻辑
@classmethod	#类方法,类级别的操作,不与实例绑定。
@staticmethod	#静态方法

三、############################################################
组合			#类与类的关联

四、
###################################################################
面向对象的三大特性:继承,多态,封装
	1、通过封装明确内外
	2、通过继承+多态在语言层面支持了归一化设计
抽象/实现
封装/接口
合成
派生/继承/继承结构
泛化/特化
多态
自省/反射

1#反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
	四个可以实现自省的函数(适用于类和对象)
	hasattr(object,name)	#检测对象有没有name属性
	getattr(object, name, default = None)
	setattr(object, name, value)	#object.name = value
	delattr(object, name)	#删除object.name
反射:两个人合作写代码,a负责的模块没写完,b写的块,需要调用a的模块,使用反射,b可以继续写自己的逻辑,不受a没写完的影响。
ex:
	if hasattr(object, name):
		func_get = getattr(object, name)
		func_get
	else:
		print("还不存在,先继续其他逻辑")

python
#######################	
#动态导入模块
#用字符串方式导入模块
1、不完整
module_name = __import__("packge1.modulename")
#__import__从字符串中提取模块
#无论字符串里有多少级(.),返回的都是最高级的那个包
print(module_name)	#<module 'package1' (namespace)>
module_name.modulename.func()

2、完整
import importlib	#引入模块
module_name = importlib.import_module("packge1.modulename")
print(module_name)	#<module 'package1.modulename' from ''>
#此时就是完整导入
module_name.func()
########################
类内置的的函数属性:(若不重写,系统自己有,若重写,系统调用你定义的)(day26-10-11class name:
	def __init__(self, xx):
		self.xx = xx
		
	def __getattr__(self, item):
		print("当获取的属性不存在的时候才会执行此方法, 若存在,就不执行, 不信可以试试")
		#常用
		#所以可以有以下应用
		print("你找的属性 %s 不存在" % item)
		#这样提示不存在的属性,避免系统报错
	
	#可以定制属性的删除,比如筛选删除,不可删除	
	def __delattr__(self, item):
		print("删除属性的时候会触发,此方法")
		self.__dict__.pop(item)	#本质
		
	#可以定制设置属时的过程,无限想象空间
	def __setattr__(self, key, value):
		print("修改属性时,会执行")
		#self.key = value	#会报错,因为一直递归自己,好好想想
		self.__dict__[key] = value
		#本质就是在操作字典,直接字典加入新设置的键值对

2、继承+派生  ==>> 包装(在子类中重写父类函数)
super()		#父类
组合   ==》》》  授权(定制修改,类似于权限管理)
牛逼


五、
##############################################################################
isinstance(obj,cls)			#判断对象obj是否是有类cls实例化来的
issubclass(cls1,cls)		#判断cls1是否是cls的子类

def __getattr__(self,item)			#属性不存在时,调用此方法
#当__getattribute__抛出异常时,才会调用__getattr__
def __getattribute__(self, item)	#无论属性存不存在,都会调用此方法

def __getitem__(self, item)
def __setitem__(self, key, value)
def __delitem__(self, key)
#与__getattr__作用一样,区别在于除法方式不同
#attr使用“.”的方式触发,item使用[key]字典的方式触发

def __str__(self):			#print时用
	return "自定制的对象的输出,print(obj)时调用"
	#默认返回<__main__.foo object at 0x0000010F3AEABA90>
def __rptr__(self):			#在解释器中用
	return "自定制的对象的输出,obj时调用"
#两者共存时,如果找不到__str__,会找__rptr__	
#return 字符串		否则会报错

#format(obj,spec) = obj.__format__(self, spec)
def __format__(self, spec):		#对格式进行自定义

__slots__ = ["a","b"]		#慎用
#当类的方法属性很多时,为了节省空间,会用slots替代dict
#类自身的__dict__还存在,但是由这个类产生的实例,不在有__dict__属性,实例对象只能运用slots包含的属性

class foo:
	'''我是描述信息'''
	pass
__doc__		#不可被继承

print(func.__module__)	#输出func所在模块
print(func.__class__)	#输出func所属类

def __del__(self)		#析构函数,解释器会自动释放内存

def __call__(self, *args, **kwargs)	#构造函数,对象后面加(),触发执行

#迭代器协议
class foodef __init__(self, n)
		self.n = n
	def __iter__(self):		#1、将对象变成可迭代对象
		return self
	def __next__(self):		#2、next可以返回下一个元素
		if self.n == 100:	#3、终止条件
			raise	StopIteration("抛出异常")
		self.n += 1
		return slf.n
f = foo()
for i in f:		#obj = iter(f)  ====>>>  f.__iter__()
	print(i)	#obj.__next__()


##########描述符
**************重要*************
[参考链接](https://www.cnblogs.com/linhaifeng/articles/6204014.html)
优先级:由高到低
类属性
数据描述符
实例属性
非数据描述符
找不到的属性触发__getattr__()

描述符:__get__ __set__ __delete__
描述符分为数据描述符和非数据描述符。
	至少实现了内置__set__()和__get__()方法的描述符称为数据描述符;实现了除__set__()以外的方法的描述符称为非数据描述符。

定义成一个类的类属性
#################################
'''
描述符总结:
    描述符可以实现大部分python类特性中底层魔法,包括@classmethod @staticmethod @property 甚至是__slots__属性
'''
#描述符变量类型限制
class Typed:
    def __init__(self, key, expectType):
        self.key = key
        self.expectType = expectType

    #instance 被描述的实例对象  owner 实例所属的类  value 对象元素的值
    def __get__(self, instance, owner):
        print("get方法")
        # print("instance参数 %s" % instance)
        # print("owner参数 %s" % owner)
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        print("set方法")
        # print("instance参数 %s" % instance)
        # print("value参数 %s" % value)
        if not isinstance(value, self.expectType):
            #raise TypeError(" 5s 不是 %s  类型" % (self.key, self.expectType))
            print("typeError 不是字符串类型")
            return
        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print("del方法")
        # print("instance参数 %s" % instance)
        instance.__dict__.pop(self.key)

#限制变量类型
class People:
    name = Typed("name", str)          #p.__set__()  self.__set__()
    age = Typed('age', int)

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

p = People("Q", 18, 55.55)
p.name = "h"
print(p.name)               #None,没有真正的设置
print(p.__dict__)           #name被代理啦,不在dict里
del p.name
print(p.__dict__)
##################################################
#装饰器+描述符	限制变量类型
class Typed:
    def __init__(self, key, expectType):
        self.key = key
        self.expectType = expectType

    #instance 被描述的实例对象  owner 实例所属的类  value 对象元素的值
    def __get__(self, instance, owner):
        print("get方法")
        # print("instance参数 %s" % instance)
        # print("owner参数 %s" % owner)
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        print("set方法")
        # print("instance参数 %s" % instance)
        # print("value参数 %s" % value)
        if not isinstance(value, self.expectType):
            #raise TypeError(" 5s 不是 %s  类型" % (self.key, self.expectType))
            print("typeError 不是字符串类型")
            return
        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print("del方法")
        # print("instance参数 %s" % instance)
        instance.__dict__.pop(self.key)

def deco(**kwargs):         #
    def wrapper(obj):       #obj = People
        for key, val in kwargs.items():
            setattr(obj, key, Typed(key, val))          #name = Typed("name", str)
            return obj
    return wrapper

#限制变量类型
@deco(name = str, age = int, salary = float)
class People:
    # name = Typed("name", str)          #p.__set__()  self.__set__()
    # age = Typed('age', int)
    # salary = Typed("salary", float)

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

p = People("Q", 18, 55.5)
p.name = 3          #typeError 不是字符串类型
print(p.__dict__)
###################################################
'''
@装饰器name,在执行的时候,被修饰的函数,不被调用,不会执行,但是装饰器会被提前转化
@装饰器放在类里,修饰类的属性时,就等于添加了描述符
区别类调用和实例对象调用
数据描述符和非数据描述符(优先级应用)
\
'''
#模拟@property
class selfProperty:
    def __init__(self, obj):
        print("obj是  %s" % obj)         #obj是  <function Room.area at 0x0000017AC823BE18>   类的area方法
        self.obj = obj

    def __get__(self, instance, owner):
        print("执行我")
        print("instance 是 %s" % instance)
        if instance == None:                        #类调用,方法时,instance为None,返回装饰器本身
            return self
        res = self.obj(instance)                    #类调用方法需要传入实例对象
        #setattr(instance, self.obj.__name__, res)
        instance.__dict__[self.obj.__name__] = res  #若果不定义__set__则为非数据描述符,此时将area的值直接写入字典
                                                    #对象属性大于非数据描述符,所以后面不会执行装饰器,直接从字典中调取属性的值
                                                    #可避免重复计算
                                                    #这种方式叫延迟计算???
        return  res

class Room:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    #@property           #area = property(area)
    @selfProperty
    def area(self):
        return self.width * self.height


r = Room(1,2)
#print(r.area())
#实例调用
print(r.area)           #第一次需要走装饰器
print(r.area)           #如果装饰器里没有__set__,那么第二次往后调用直接从字典里取,不需要重复走装饰器了
print(r.__dict__)
#类调用
print(Room.area)        #类调用会报错,注意与实例调的区别
print(Room.__dict__)

#classmethod,staticmethod也模拟了
#############################################
'''
#xx可以在property修饰的情况下,修改删除
@property
def xx(self):
@xx.setter          #依赖上一个
def xx(self,val):
@xx.deleter
def xx(self):
#或者以下方式:
def get_xx(self)
def set_xx(self, val
def del_xx(self)
xx = property(get_xx, set_xx, del_xx)   #顺序不能变(获取,设置, 删除)
'''
#使用property的该功能进行类型限制,更简洁
#但是只是单个儿限制
class People:
    def __init__(self, name, age, salary):
        self.name = name            #实例化就触发property
        self.age = age
        self.salary = salary

    @property
    def name(self):
        print("get ----->")
        return self.SuiBianQi

    @name.setter
    def name(self, value):          #不能使用return,这里依赖property,操作property返回的值
        print("set ------>")
        if not isinstance(value, str):
            raise TypeError(" %s 不是str类型")
        self.SuiBianQi = value

    @name.deleter
    def name(self):
        print("delte ------>")
        del self.SuiBianQi

p = People("Q", 18, 55.5)       #self.name实际上是被存放在了self.SuiBianQi里了
print(p.name)
print(p.name)
print(p.__dict__)               #{'SuiBianQi': 'Q', 'age': 18, 'salary': 55.5}
p.name = "H"
print(p.name)
#p.name = 123                   #类型出错误
#############################################################################################
元类
'''
metaclass
元类是类的类
def __init__(self,name, age):
    self.name = name
    self.age = age
type("classname",(object,),{key:value,"__init__":__init__})

一个类如果没有声明自己的元类,默认它的元类是type,
除了使用元类type,用户也可以通过继承type类来自定义元类
'''

class Mytype(type):
    def __init__(cls, a, b, c):     #看着四个参数是什么
        print("元类的构造函数执行")

    def __call__(cls, *args, **kwargs):
        obj = object.__new__(cls)
        cls.__init__(obj, *args, **kwargs)
        return obj

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

f = Foo("Q")



[参考链接](https://www.cnblogs.com/linhaifeng/articles/6182264.html#_label7)
#########24#############
二、
class Chinese:
    li = [1, 2, 3]
    __Area = 960                #将该属性隐藏,不可以被类和对象从外部获取,只可以在内部调用
    __home = "种花家"          #双下划线,隐藏
    def __init__(self, name, age, gender, city):
        self.Name = name
        self.Age = age
        self.Gender = gender
        self.__City = city      #将该属性隐藏,不可以被类和对象从外部获取,只可以在内部调用
    def play_ball(self, ball):  #与(对象)self绑定
        print("%s 正在打 %s" % (self.Name, ball))

    # def length(self):
    #     print("名字的长度为 %s" % len(self.Name))
    @property                   #像数据属性一样调用
    def length(self):           #与(对象)self绑定,可是使用类和对象的属性和方法
        return len(self.Name)

    @classmethod                #没有实例对象类也可调用
    def tell_info(cls):         #与(类)cls绑定,可以使用类的属性和方法
        print("类方法")

    @staticmethod               #类的工具包
    def wash_face(a, b):         #不与类和对象绑定,也不可使用类和对象的属性和方法
        print("%s 和 %s 在洗脸" % (a, b))

    def print_hide(self):       #通过函数,输出被隐藏属性
        print("被隐藏的类属性__Area = %d, 对象属性__City = %s" % (self.__Area, self.__City))#注意self
    #方法(def _name)前加下划线,表示私有,外部不可调用

p = Chinese("Q", 18, "male", "jiangsu")    #实例化对象p
#增删数据属性
#类
Chinese.addr = "zhongguo"
print(Chinese.addr)
print(Chinese.__dict__)         #添加addr数据属性
del Chinese.addr
print(Chinese.__dict__)         #删除addr数据属性
#实例对象
p.Phone = 123456
print(p.__dict__)               #实例对象添加新属性,不会影响到类的属性
del p.Phone
print(p.__dict__)               #实例对象的删除,不会影响到类
p.li = ["a", "c"]               #属于新建列表li,不是操作的类中的列表li
print(p.__dict__)               #新建的列表li,属性里有,不同于类的li,不影响类
print(Chinese.__dict__)         #li没受到影响
#注意
p.li.append("a")                #实例对象有自己的li所以类的li不受影响
print(p.__dict__)
print(Chinese.__dict__)
del p.li                        #删除实例对象的li
p.li.append("a")                #此时操作的是实例调用的类的li    append(self,xx),此方法细品
print(p.__dict__)               #属性字典里没有
print(Chinese.__dict__)         #类的li被修改

#del p.li                          #报错,对象不可以删除类属性

#增删方法属性
def drink(self,tea):            #只做例子,方法最好都集成在class里
    print("%s喜欢喝 %s" % (self.Name, tea))
#类
Chinese.drink_tea = drink       #注意不加(),不传参,只是将函数地址存入类的字典中
p.drink_tea("hongcha")          #实例对象可引用新添加的方法,
print(Chinese.__dict__)
del Chinese.drink_tea           #删除方法
print(Chinese.__dict__)
#实例对象
p.drink_tea = drink             #不建议这么使用
p.drink_tea(p,"ss")             #需要将给self绑定对象
#Chinese.drink_tea(p,"xx")      #报错,类没有这个属性
print(p.__dict__)               #该方法被添加进实例对象的属性字典
del p.drink_tea                 #删除

#del p.play_ball                #报错,实例对象不可以删除类属性
print(Chinese.__dict__)

#方法
#Chinese.play_ball("football")   #不给self传实例会报错
Chinese.play_ball(p, "football")#类调用与self(对象)绑定的方法,必须先实例化一个对象,传给self
p.play_ball("basketball")       #实例对象,调用类方法,会自动传给self
#p.length()
#@property
print(p.length)                 #逻辑被封装,可以省去()
#@classmethod
Chinese.tell_info()             #与cls绑定,自动传
p.tell_info()                   #实例对象可以正常调用与cls绑定的方法
#@staticmethod
Chinese.wash_face("q", "h")     #类可调用
p.wash_face("q", "H")           #对象可调用
#如果不加@staticmethod,wash_face只是普通函数
#类可以调用,实例对象不可以调用,因为对象p会把自己当做参数传进去

#隐藏属性,名字前加_,表示
#Chinese.__Area
#p.__City                       #报错,属性不可获取
p.print_hide()                  #隐藏的属性,通过方法输出

#自省函数,可以增删函数
print(hasattr(p, "Name"))       #检测对象是否有xx属性,有True

print(getattr(p, "Age"))        #获取属性值,没有会报错
func = getattr(p, "play_ball")  #获取xxx方法地址,没有会报错
func("basketball")              #执行方法
print(getattr(p, "noAge", "没有这个属性"))   #若属性不存在,返回default

setattr(p, "Age", "22")         #设置p.Age=22
print(getattr(p, "Age"))

delattr(p, "Age")               #删除p.Age
print(hasattr(p, "Age"))        #False

setattr(p, "Age", "18")         #设置p.Age=18
print(getattr(p, "Age"))

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值