python---面向对象-python中的实践(2)

news2024/12/23 15:17:46

如何定义一个类?

class 类名:
    pass

怎样通过类,创建出一个对象?

根据类创建对象
	one = Money()
执行流程
	1. 类的定义
	2. 根据类,创建出一个对象
	3. 将对象的唯一标识返回
class Money:
	pass

print(Money.__name__)
xxx = Money
print(xxx.__name__)

Money = 666
print(id(Money))
print(Money)
# 根据这个类,创建(实例化)一个对象
one = Noney()
print(one)
print(one.__class__)

在这里插入图片描述

属性相关

属性和变量的区别及判定依据?

区别
	概念
		变量是“可以改变的量值”
		属性是“属于某个对象的特性”
	访问权限
		变量:根据不同的位置,存在不同的访问权限
			全局变量
			局部变量
			...
		属性:只能通过对象来进行访问
			所以,必须先找到对象
			对象也是通过变量名来引用;而既然是变量,也有对应的访问权限
判定依据
	是否存在宿主

对象属性

怎样让一个对象拥有一些属性?(增)

1. 直接通过对象,动态添加
	语法:
	对象.属性 = 值
2. 通过类的初始化方法(构造方法)
	__init__方法
# _*_ encoding:utf-8 _*_
# 1. 定义一个类
class Person:
    pass

# 2. 根据类, 创建一个对象
p = Person()

# 3. 给p对象, 增加一些属性
p.age = 18
p.height = 180

# 4. 验证是否有添加成功
print(p.age)
print(p.__dict__)

在这里插入图片描述

怎样访问一个对象的属性?(查)

一般访问
	对象.属性
如果访问不到
	会直接报错
	需要记住错误提示

怎样修改一个对象的属性?(改)

同新增一样;系统会自动识别,不存在则新增,存在则修改
语法
	对象.属性 = 值
# _*_ encoding:utf-8 _*_
# 1. 定义一个类
class Person:
    pass

# 2. 根据类, 创建一个对象
p = Person()

# 3. 给p对象, 增加一些属性
p.age = 18
p.height = 180
p.pets = ["小花", "小黑"]
print(p.pets, id(p.pets))

p.pets.append("小黄")
print(p.pets, id(p.pets))

怎样删除一个对象的属性?(删)

del 对象.属性
# num = 10
# del num
# print(num)
class Person:
    pass
p.age = 18

del p.age
print(p.age)

补充:

查看对象的所有属性?
	对象.__dict__
不同对象之间不能互相访问对方的属性
_*_ encoding:utf-8 _*_
# 1. 定义一个类
class Person:
    pass

p1 = Person()
p2 = Person()

p1.age = 18
p2.address = "上海"

print(p1.__dict__)
print(p1.address) # 报错

类属性

万物皆对象,类也是一个对象
	比如,生产月饼的模板,对于月饼来说它是“类”
	但模板本身是不是也是一个具体的东西,也是由其他的东西创建出来的??

怎样让一个类拥有属性?(增)

方式1
	类名.类属性 = 值
方式2
	class Dog:
	dogCount = 0
class Money:
    pass

# one = Money()
# one.age = 10
# one.age = 18

Money.count = 1
Money.age = 18
Money.num = 666

print(Money.count)
print(Money.__dict__)

class Money:
    age = 18
    count = 1
    num = 666

怎样查询一个类的属性?(查)

通过类访问
	类名.类属性
通过对象访问
	对象.类属性
注意:
	为什么可以通过对象访问到类属性?
	答:和Python对象的属性查找机制有关
		优先到对象自身去查找属性
			找到则结束
		如果没有找到
			则根据__class__找到对象对应的类
			到这个类里面查找

class Money:
    age = 18
    count = 1
    num = 666
one = Money()

print(one.__class__)

print(one.age)
print(one.count)
print(one.num)

在这里插入图片描述

class Test:
	sex = "男"

class Money:
    age = 18
    count = 1
    num = 666


one = Money()
one.sex = "女"  
one.__class__ = Test
print(one.__class__)

print(one.sex)   # 打印结果为女
print(one.age) #会报错

在这里插入图片描述

怎样修改一个类的属性?(改)

通过类名改
	语法如同给类增加一个属性的方式1
		系统也会自动检测
		不存在,则新增
		存在,则修改
	类名.属性 = 值
能否通过对象改?
	不能!
class Money:
    age = 18
    count = 1
    num = 666

Money.age = 22

one = Money()
one.xxx = 999
print(one.xxx)

one.age = 13
print(one.age)  #结果为14,赋值语句只能修改对象本身
print(Money.age)
print(one.__dict__)

在这里插入图片描述

怎样删除一个类的属性?(删)

通过类名删除
	del 类名.属性
能否通过对象删除?
	不能!
	del 语句只删除直系属性
class Money:
    age = 18
    count = 1
    num = 666

one = Money()
del one.age  # 会报错

注意

类属性的内存存储问题
	一般情况下,属性存储在__dict__的字典当中
		有些内置对象没有这个__dict__属性
	一般对象可以直接修改__dict__属性
		但类对象的__dict__为只读;默认无法修改
		可以通过setattr方法修改
类属性被各个对象共享
	类属性修改之后,所有的对象访问到的类属性都会跟着修改
class Money:
    age = 18
    name = "sz"

# Money.__dict__ = {"sex": "男"}  #会报错,类对象的属性不可以更改
# Money.__dict__["age"] = 20 # 会报错,类对象的属性不可以更改

补充

查看一个类的所有属性
类名.__dict__

对象属性和类属性之间的区别联系?

存储不同
抽象层级不同
宿主不同
案例考察
	类
		class Person:
				 count = 1
	对象
		p = Person()
	问
		p.count += 1
			代码执行之后
		Person.count 与 p.count 打印的结果分别是多少?

如何限制对象的属性?

通过设置类属性:__slots__
这个属性是一个列表
	列表中的元素,即为通过这个类创建出的对象可以添加的对象属性
	如果这个类实例出的对象,添加了非列表之内的属性,则会报错
class person:
	__slots__ = ["age"]
	pass
p1 = person
p1.age = 1
p1.num = 2 # 报错

方法相关

方法的概念

描述一个目标的行为动作
	比如描述一个人怎样吃,怎样喝,怎样玩...
和函数非常类似
	都封装了一系列行为动作
	都可以被调用的之后,执行一系列行为动作
	最主要的区别就是:调用方式

方法的划分

实例方法
	默认第一个参数需要接收到一个实例
类方法
	默认第一个参数需要接收到一个类
静态方法
	静静的看着前面俩装逼,第一个参数啥也不默认接收
注意
	1. 划分的依据是:方法的第一个参数必须要接收的数据类型
	2. 不管是哪一种类型的方法,都是存储在类当中;没有在实例当中的
	3. 不同类型方法的调用方式不同
		但,不管怎么调,把握一个原则
		不管是自己传递,还是解释器帮我们处理;最终要保证不同类型的方法第一个参数接收到的数据,是他们想要的类型
class Person:
    def eat2():
        print("这是一个实例方法")

    @classmethod
    def leifangfa(cls):
        print("这是一个类方法", cls)

    @staticmethod
    def jingtaifangfa():
        print("这是一个静态方法")


p = Person()
print(p)
p.eat2()
# Person.eat2()  # 会报错

Person.leifangfa()

Person.jingtaifangfa()

print(person.__dict__)
print(p.__dict__)

def run():
	print("run")
p.age = run
print(p.__dict__)

实例方法

class Person:
	def run(self):
		pass
类调用
	注意
		必须传递一个对象,因为实例方法要求呀。该方法没有实际意义,相当于将实例方法当作函数在调用
对象调用【主流】
	不用手动传,解释器会默认把调用对象本身传递过去
注意
	一般使用对象来调用
class Person:
    def eat(self, food):
        print("在吃饭,",self, food)
        print("在吃饭,", food)

    def eat2():
        print("123")
    def eat3(xxx):
    	print(xxx)

p = Person()
print(p)
p.eat("土豆") # 对象调用(标准调用)

print(Person.eat)

Person.eat(123, "abc") # 类调用


func = Person.eat # 间接调用

func("abc", 999)


# p.eat2() # 会报错
p.eat3() # 第一个参数,形参名字并不重要,解释器都会将示例对象传递到第一个参数

在这里插入图片描述

类方法

class Person:
	@classmethod
	def countPerson(cls):
		pass
类调用
	不用手动传递第一个参数,会自动的把调用的类本身给传递过去
对象调用
	不用手动传递第一个参数,会自动的把调用的对象对应的类给传递过去
注意
	一般使用类来调用
class Person:
    # def run(self):
    #     print(self)
    @classmethod
    def leifangfa(cls, a):
        print("这是一个类方法", cls, a)

Person.leifangfa(123)

p = Person()
p.leifangfa(666)


func = Person.leifangfa
func(111)

# 装饰器的作用: 在保证原本函数不改变的前提下, 直接给这个函数增加一些功能
class A(Person):
    pass
A.leifangfa(0) # 打印的是类A

静态方法

class Person:
	@staticemethod
	def countPerson():
		pass
类调用
	直接调用就可以, 不需要考虑第一个参数
对象调用
	直接调用就可以
注意
	具体使用谁来调用,根据场景,哪个比较适合方便就使用哪个
class Person:
    @staticmethod
    def jingtai():
        print("这是一个静态方法")


Person.jingtai()
p = Person()
p.jingtai()

func = Person.jingtai
func()

不同类型的方法访问不同类型的属性的规律

class Person:
    age = 0
    def shilifangfa(self):
        print(self)
        print(self.age)
        print(self.num)
    @classmethod
    def leifangfa(cls):
        print(cls)
        print(cls.age)
        print(cls.num)
    @staticmethod
    def jingtaifangfa():
        print(Person.age)

p = Person()
p.num = 10

p.shilifangfa()

# p.leifangfa() # 会报错,因为类方法只能访问类属性,访问不到实例的属性
Person.leifangfa()
Person.jingtaifangfa()

# # 类属性
print(Person.age)
print(p.age)

# # 实例属性
print(p.num)

补充

函数和方法的区别?
	是否有宿主
	函数都是独立的个体,函数之间几乎没有共享的数据
	方法有宿主
self-注意点
	代表调用的对象

补充

类相关补充

元类

概念
创建类对象的类
	对象怎样产生的?
		由类创建出来的
	类是不是对象?
		是
	所以,类对象是不是由另外一个类创建出来的?
		是
		元类
结构图
num = 10

print(num.__class__)

s = "abc"
print(s.__class__)

class Person:
    pass

p = Person()
print(p.__class__)

print("-"*20)
# 元类
print(int.__class__)  # 输出结果:<class 'type'>
print(num.__class__.__class__)  # 输出结果:<class 'type'>

print(str.__class__) # 输出结果:<class 'type'>

print(Person.__class__) # 输出结果:<class 'type'>
print(Person.__class__.__class__) # 输出结果:<class 'type'>
print(type.__class__) # 输出结果:<class 'type'>

在这里插入图片描述

类对象的创建方式以及创建流程

创建方式
	通过class 定义
		当我们这么写这个类描述的时候, 解释器会自动的帮我们创建对应的类对象
	通过type函数进行创建
类的创建流程
	1. 检测类中是否有明确 __metaclass__属性
		有, 则通过指定元类来创建这个类对象
	2. 检测父类中是否存在__metaclass__属性
		有, 则通过指定元类来创建这个类对象
	3. 检测模块中是否存在__metaclass__属性
		有, 则通过指定元类来创建这个类对象
	4. 通过内置的type这个元类,来创建这个类对象
# -----------------------------类的创建方式---------------------------
class Person:
    count = 0
    def run(self):
        pass

num = 10
print(type(num))  # 输出结果:<class 'int'>

def run(self):
    print("---", self)

xxx = type("Dog",(),{"count": 0, "run": run})
print(xxx)

print(xxx.__dict__)

d = xxx()
print(d)

d.run()

在这里插入图片描述

# -----------------------------类的创建流程------------------

class Test():
    pass
#最后通过type元类创建这个对象
#type

# 再其次模块中查找元类
__metaclass__ = Test  

# 其次父类级查找元类
class Animal:
    # __metaclass__ = Test
    pass

# 首先类中查找元类
class Person(Animal):  # 继承自Animal
    # __metaclass__ = Test  #由metaclass指定元类
    pass


class Dog(Animal):
    __metaclass__ = xxx
    pass

print(Person.__metaclass__)
元类的应用场景
1)   拦截类的创建
2)   修改类
3)   返回修改之后的类
	后面补充

类的描述

目的
	方便理清逻辑思路
	方便多人合作开发时的沟通
	方便生成项目文档
	...
描述方式
	直接在类的下方,使用三个 "双引号"对就可以
	需要注明类的作用, 以及类属性描述
	至于方法, 则直接在方法下,使用三个"双引号"对描述即可
		作用
		参数
		返回值
class Person:
    """
    关于这个类的描述, 类的作用, 类的构造函数等等; 类属性的描述
    Attributes:
        count: int 代表是人的个数
    """
    # 这个表示, 是人的个数
    count = 1

    def run(self, distance, step):
        """
        这个方法的作用效果
        :param distance: 参数的含义, 参数的类型int, 是否有默认值
        :param step:
        :return: 返回的结果的含义(时间), 返回数据的类型int
        """
        print("人在跑")
        return distance / step
    def __init__(self):
        self.__name = "sz"

help(Person)

def xxx():
    """
    这是一个xxx函数, 有xxx作用
    :return:
    """
    print("xxx")
生成项目文档(补充)
	方式1
		使用内置模块
			pydoc
		具体步骤
			前置步骤:打开控制台,进入当前项目所在目录
			查看文档描述
				python3 -m pydoc 模块名称
			启动本地服务, 浏览文档
				python3 -m pydoc -p 端口号
					eg:python3 -m pydoc -p 1234
			生成指定模块html文档
				python3 -m pydoc -w 模块名称
python3 --help   //查看python3命令
python3 -m //以一个脚本的形式运行某个库文档
python3 -m pydoc -h  //查看相关使用方式
	方式2
		使用三方模块
			Sphinx
			epydoc
			doxygen
		具体步骤
			目前感兴趣了可以先自行研究
			后续讲完"包和模块"之后,会进行补充

属性相关补充

私有化属性

概念
是指将一些原本公开的属性设置权限, 只能小范围访问, 其他地方访问不了
意义
保证数据的安全性
提高代码的可维护性
注意
Python并没有真正的私有化支持,但是, 可以使用下划线完成伪私有的效果
类属性(方法)和实例属性(方法)遵循相同的规则

在这里插入图片描述

x
公有属性 
	类内部访问 【√】
	子类内部访问 【√】
	模块内其他位置访问 【√】
		类访问
			父类
			派生类
		实例访问
			父类实例
			派生类实例
	跨模块访问 【√】
		import形式导入
		from 模块 import * 形式导入
class Animal:
    x = 10
    def test(self):
        print(Animal.__x)
        print(self.__x)
    pass

class Dog(Animal):
	def test2(self):
		print(Dog.x)
		print(self.x)
	pass

# 测试代码
# 类内部访问
## 父类
a = Animal()
a.test()

# 子类内部访问
d = Dog()
d.test2()

# 模块内其他位置方位
# 类访问
## 父类
print(Animal.x)
## 派生类
print(Dog.x)

# 实例访问
## 父类实例
print(a.x)
## 派生类实例
print(d.x)

a = 666

# 其他模块【另建一个.py文件】

import 私有化属性
print(a)

from 私有化属性 import *
print(a)
_x
受保护属性
	类内部访问 【√】
	子类内部访问 【√】
	模块内其他位置访问 【警告】
		类访问
			父类
			派生类
		实例访问
			父类实例
			派生类实例
	跨模块访问
		import形式导入  【警告】
		from module import * 形式导入
			有__all__指明对应变量  【警告】
			没有__all__指明对应变量  【会报错】
class Animal:
    _x = 10
    def test(self):
        print(Animal._x)
        print(self._x)
    pass

class Dog(Animal):
    def test2(self):
        print(Dog._x)
        print(self._x)
    pass

# # 测试代码

# 类内部访问
## 父类
a = Animal()
a.test()

# 子类内部访问
d = Dog()
d.test2()

# 模块内其他位置方位
# 类访问
## 父类
print(Animal._x)
## 派生类
print(Dog._x)

# 实例访问
## 父类实例
print(a._x)
## 派生类实例
print(d._x)

_a = 666
__all__ = ["_a"] # __all__ 列表指定的对象,模块外部可以通过from 模块 import方式导入
# 其他模块【另建一个.py文件】

import 私有化属性
print(a)  

from 私有化属性 import *
print(a)
__x
私有属性
	类内部访问  【√】
	子类内部访问 【X】
	模块内其他位置访问 【X】
		类访问
			父类
			派生类
		实例访问
			父类实例
			派生类实例
	跨模块访问
		参照单下划线开头变量的访问原则
私有属性的实现机制
	名字重整(Name Mangling)
		重改__x为另外一个名称, 如
			_类名__x
	目的
		防止外界直接访问
		防止被子类同名称属性覆盖
应用场景
	数据保护
	数据过滤
class Animal:
    __x = 10
    def test(self):
        print(Animal.__x)
        print(self.__x)
    pass

class Dog(Animal):
    def test2(self):
        print(Dog.__x)
        print(self.__x)
    pass

# # 测试代码

# 类内部访问
## 父类
a = Animal()
a.test()

# 子类内部访问
d = Dog()
d.test2() # 会报错

# 模块内其他位置方位
# 类访问
## 父类
print(Animal.__x)  # 会报错
## 派生类
print(Dog.__x) # 会报错

# 实例访问
## 父类实例
print(a.__x) # 会报错
## 派生类实例
print(d.__x) # 会报错

__a = 666
__all__ = ["_a"] # __all__ 列表指定的对象,模块外部可以通过from 模块 import方式导入

# 私有属性的实现机制-命名机制:重改__x为另外一个名称, 如_类名__x

# print(Animal.__x) # 会报错
print(Animal.__dict__) 
print(Animal._Animal__x) # 成功输出10

# 其他模块【另建一个.py文件】
import 私有化属性
print(私有化属性.__a)  

from 私有化属性 import *
print(__a) # 会报错

## 私有化属性的应用场景
```python
class Person:

    # 主要作用, 当我们创建好一个实例对象之后, 会自动的调用这个方法, 来初始化这个对象
    def __init__(self):
        self.__age = 18

    def setAge(self, value):
        if isinstance(value, int) and 0 < value < 200:
            self.__age = value
        else:
            print("你输入的数据有问题, 请重新输入")

    def getAge(self):
        return self.__age

p1 = Person()
# p1.__age = -10  # 报错
# print(p1._Person__age)  # 不建议

p1.setAge("abc")
# print(p1._Person__age)

print(p1.getAge())

p2 = Person()


p3 = Person()

# print(p1.age)
# print(p2.age)
# print(p3.age)
# print(p1.__dict__)
补充
xx_
	"变量名_" 这个格式是为了与系统属性作区分
__xx__
	两端__一般为系统内置属性或方法, 所以以后命名注意避免
# 为了与系统属性作区分
class_

# 系统内置属性或方法,
__xx__

只读属性

概念
	一个属性(一般指实例属性), 只能读取, 不能写入
应用场景
	有些属性, 只限在内部根据不同场景进行修改, 而对外界来说, 不能修改, 只能读取
	比如
		电脑类的网速属性, 网络状态属性
方式1
	方案
		全部隐藏
			私有化
				既不能读
				也不能写
		部分公开
			公开读的操作
	具体实现
		私有化
			通过"属性前置双下划线"实现
		部分公开
			通过公开的方法
			优化
				property
					作用
						将一些"属性的操作方法"关联到某一个属性中
					概念补充
						经典类
							没有继承(object)
						新式类
							继承(object)
						Python2.x版本定义一个类时, 默认不继承(object)
						Python3.x版本定义一个类时, 默认继承(object)
						建议使用
							新式类
					property
						在经典类中
							只能管理一个属性的读取操作
						在新式类中
							可以管理一个属性的删改查操作

方式2
	方案
		借助系统内置的方法进行拦截
	具体实现
		__setattr__方法
			当我们使用 "实例.属性 = 值" 这种格式给一个实例增加或修改属性的时候, 都会调用系统内置的这个方法
			在这个方法的内部, 才会真正的把属性以及对应的值给存储到 __dict__当中
		解决方案
			在这个方法中, 进行拦截
# 方式一
## 公开方法
class Person(object):
    def __init__(self):
        self.__age = 18
	
	def getAge(self):
		return self.__age

p1 = Person
print(p1.getAge())

## 优化
class Person(object):
    def __init__(self):
        self.__age = 18

    # 主要作用就是, 可以以使用属性的方式, 来使用这个方法
    @property
    def age(self):
        return self.__age
        
p1 = Person()

print(p1.age)
p1.age = 10 # 报错,不能设置这个属性

# 存储层面修改,是修改不了的
p1._Person__age = 999  # 输出结果:999
p1.__dict__["_Person__age"] = 999   # 输出结果:999

p1.__age = 999  # 新增属性__age = 999
print(p1.__dict__)

## 新式类和经典类
class Person(object):
    pass

print(Person.__bases__)

# Python2.x 如果定义一个类, 没有显示的继承自object , 那么这个类就是一个经典类
# 必须显示的继承自, object, 它才是一个新式类


# Python3.x , 如果直接定义一个类, 会隐式的继承object, 默认情况下, 就已经是一个新式类

# propery在新式类和经典类中的使用
# -------------------------------property在新式类中的使用-----------------------------------
class Person(object):
    def __init__(self):
        self.__age = 18

    def get_age(self):
        print("----, get")
        return self.__age

    def set_age(self, value):
        print("----, set")
        self.__age = value

    age = property(get_age, set_age)

p = Person()
print(p.age)

p.age = 90
print(p.age)

print(p.__dict__)

# 第二种使用方式 - 装饰器方法
class Person(object):
    def __init__(self):
        self.__age = 18

    @property
    def age(self):
        print("----- get")
        return self.__age

    @age.setter
    def age(self, value):
        print("----- set")
        self.__age = value

p = Person()
print(p.age)

p.age = 10
print(p.age)

# -------------------------------property在经典类中的使用-----------------------------------
class Person:
    def __init__(self):
        self.__age = 18

    def get_age(self):
        print("----, get")
        return self.__age

    def set_age(self, value):
        print("----, set")
        self.__age = value


    age = property(get_age, set_age)

p = Person()
print p.age

p.age = 19 #此方法会新增一个属性,而不是修改实例属性
print p.age
print p.__dict__

# 第二种使用方式-装饰器方法
class Person:
    def __init__(self):
        self.__age = 18

    @property
    def age(self):
        print "-----get"
        return self.__age

    @age.setter
    def age(self, value):
        self.__age = value

p = Person()
# print p.age

p.age = 19
print p.age
print p.__dict__



# 方式二
class Person:
    # 当我们通过 "实例.属性 = 值", 给一个实例增加一个属性, 或者说, 修改一下属性值的时候, 都会调用这个方法
    # 在这个方法内部, 才会真正的把, 这个属性, 以及对应的数据, 给存储到__dict__字典里面
    def __setattr__(self, key, value):
        print(key, value)

        # 1. 判定, key, 是否是我们要设置的只读属性的名称
        if key == "age" and key in self.__dict__.keys():
            print("这个属性是只读属性, 不能设置数据")
        # 2. 如果说不是, 只读属性的名称, 真正的给它添加到这个实例里面去
        else:
            # self.key = value  # 会报错、陷入死循环
            self.__dict__[key] = value
p1 = Person()
p1.age = 18
# p1.name = "sz"
# print(p1.age)
print(p1.age)


p1.age = 999
print(p1.age)

print(p1.__dict__)

内置特殊属性

类属性
	__dict__ : 类的属性
	__bases__ : 类的所有父类构成元组
	__doc__ :类的文档字符串
	__name__: 类名
	__module__: 类定义所在的模块
实例属性
	__dict__ : 实例的属性
	__class__: 实例对应的类
class Person:
    """
    这是一个人, 类
    """
    age = 19
    def __init__(self):
        self.name = "sz"

    def run(self):
        print("run")


# __dict__ : 类的属性
# __bases__ : 类的所有父类构成元组
# __doc__ :类的文档字符串
# __name__: 类名
# __module__: 类定义所在的模块


print(Person.__dict__)
print(Person.__bases__)
print(Person.__doc__)
# help(Person)
print(Person.__name__)
print(Person.__module__)

p = Person()
print(p.__class__)

方法相关补充

私有化方法

	私有方法
		def __方法():
			pass
	注意
		不要定义 "_类名__方法名" 这种方法
class Person:
	__age = 18
	def __run(self):
		print("pao")
	def _Person__run(self)
		print("Xxx")

p = person
# p.__run()  #会报错
p.__Person_run()  #输出结果Xxx,_Person__run()会覆盖掉run()方法
print(Person.__dict__)

内置特殊方法

生命周期方法(下一小节单独介绍)
其他内置方法
信息格式化操作
__str__方法
	作用
		一个对象的描述字符串, 更加方便用户阅读, 对用户更友好
	触发方式
		print 打印一个对象时
		str() 函数时
	格式
		def __str__(self):
			return "描述信息"
class Person:
    def __init__(self, n, a):
        self.name = n
        self.age = a

    def __str__(self):
        return "这个人的姓名是%s, 这个人的年龄是:%s" % (self.name, self.age)

p1 = Person("sz", 18)
# # print(p1.name)
# # print(p1.age)
print(p1)

p2 = Person("zhangsan", 19)
# # print(p2.name)
# # print(p2.age)
print(p2)

# s = str(p1)
# print(s, type(s))

__repr__方法
	作用
		一个对象的描述字符串, 更加方便机器处理, 对机器更友好(开发人员查看)
	触发方式
		当我们在交互模式下, 直接执行某个变量, 就会输出对应信息
		repr() 函数时
	格式
		def __repr__(self):
			return "描述信息"
	注意
		一般情况下, 应满足如下等式
			obj == eval(repr(obj))
		或者描述一个实例详细的信息(类名等等)
class Person:
    def __init__(self, n, a):
        self.name = n
        self.age = a

    def __str__(self):
        return "这个人的姓名是%s, 这个人的年龄是:%s" % (self.name, self.age)

    def __repr__(self):
        return "reprxxxxx"

p1 = Person("sz", 18)
# # print(p1.name)
# # print(p1.age)
print(p1)

p2 = Person("zhangsan", 19)
# # print(p2.name)
# # print(p2.age)
print(p2)

s = str(p1)
print(s, type(s))

print(repr(p1))

import datetime

t = datetime.datetime.now()
print(t)
print(repr(t))

tmp = repr(t)

result = eval(tmp)
print(result)
调用操作
__call__方法
	作用
		使得“对象”具备当做函数,来调用的能力
	使用
		1. 实现实例方法 __call__
		2. 那么创建好的实例, 就可以通过函数的形式来调用
			实例(参数)
	应用场景
		有点类似于之前所讲的"偏函数"的应用场景
		可以将"常变参数"和"不常变参数"进行分离
	案例
		不同类型的笔, 画不同的图形
class Person:
    def __call__(self, *args, **kwargs):
        print("xxx", args, kwargs)
        pass

p = Person()

p(123, 456, name="sz")

# 创建很多个画笔, 画笔的类型(钢笔, 铅笔), 画笔的颜色(红, 黄色, 青色, 绿色)
# 方法一
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "红色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "黄色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "青色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "绿色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "橘色"))

# 方法二
def createPen(p_color, p_type):
    print("创建了一个%s这个类型的画笔, 它是%s颜色" % (p_type, p_color))

createPen("钢笔", "红色")
createPen("钢笔", "绿色")
createPen("钢笔", "黄色")

# 方法三
import functools

gangbiFunc = functools.partial(createPen, p_type="钢笔")

gangbiFunc("红色")
gangbiFunc("黄色")
gangbiFunc("绿色")

# 方法四
class PenFactory:

    def __init__(self, p_type):
        self.p_type = p_type

    def __call__(self, p_color):
        print("创建了一个%s这个类型的画笔, 它是%s颜色" % (self.p_type, p_color))

gangbiF = PenFactory("钢笔")
gangbiF("红色")
gangbiF("绿色")
gangbiF("黄色")


qianbiF = PenFactory("铅笔")
qianbiF("红色")
qianbiF("绿色")
qianbiF("黄色")
索引操作
作用
	可以对一个实例对象进行索引操作
步骤
	1. 实现三个内置方法
		设置元素的方法
			def __setitem__(self, key, value):
		获取元素的方法
			def __getitem__(self, item):
		删除元素的方法
			def __delitem__(self, key):
	2. 可以以索引的形式操作对象
		增/改
			p[1] = 666
			p["name"] = "sz"
		查
			p["name"]
			p[1]
		删
			del p["name"]
			del p[1]
class Person:
    def __init__(self):
        self.cache = {}

    def __setitem__(self, key, value):
        # print("setitem", key, value)
        self.cache[key] = value

    def __getitem__(self, item):
        # print("getitem", item)
        return self.cache[item]

    def __delitem__(self, key):
        # print("delitem", key)
        del self.cache[key]

p = Person()
p["name"] = "sz"

print(p["name"])

del p["name"]

print(p["name"])
print(p.cache)
切片操作
作用
	可以对一个实例对象进行切片操作
步骤
	Python2.x
		1. 实现三个内置方法
			__setspice__
				设置某个元素切片时调用
			__getspice__
				获取某个元素切片时调用
			__delspice__
				删除某个元素切片时调用
		2. 可以直接按照切片的方式操作对象
			p[1, 6, 2]
		注意: 过期
	Python3.x
		统一由"索引操作"进行管理
			def __setitem__(self, key, value):
			def __getitem__(self, item):
			def __delitem__(self, key):
l = [1, 2, 3, 4, 5]
print(l[3])
print(l[1: 4: 2])

class Person:

    def __init__(self):
        self.items = [1, 2, 3, 4, 5, 6, 7, 8]

    def __setitem__(self, key, value):
        # print(key, value)
        # print(key.start)
        # print(key.stop)
        # print(key.step)
        # print(value)
        # self.items[key] = value
        if isinstance(key, slice):
            self.items[key.start: key.stop: key.step] = value

    def __getitem__(self, item):
        print("getitem", item)

    def __delitem__(self, key):
        print("delitem", key)

p = Person()
p[0: 4: 2] = ["a", "b"]
print(p.items)

# slice
p[0: 5: 2]
del p[0: 5: 2]
比较操作
作用
	可以自定义对象 "比较大小, 相等以及真假" 规则
步骤
	实现6个方法
		相等
			__eq__
		不相等
			__ne__
		小于
			__lt__
		小于或等于
			__le__
		大于
			__gt__
		大于或等于
			__ge__
注意
	如果对于反向操作的比较符, 只定义了其中一个方法但使用的是另外一种比较运算那么, 解释器会采用调换参数的方式进行调用该方法
		例如
			定义了 "小于" 操作
				x < y
			使用 x > y
				会被调换参数, 调用上面的 "小于操作"
	但是, 不支持叠加操作
		例如
			定义了 "小于" 和 "等于" 操作
			不能使用 x <= y
补充
	使用装饰器, 自动生成"反向" "组合"的方法
		步骤
			1. 使用装饰器装饰类
				@functools.total_ordering
			2. 实现
				> 或 >= 或 < 或 <= 其中一个
				实现 ==
	上下文环境中的布尔值
		__bool__
class Person:
    def __init__(self, age, height):
        self.age = age
        self.height = height
    # == != > >= < <=

    def __eq__(self, other):
        print("eq")
        return self.age == other.age

	def __ne__(self, other):
    	pass

	def __gt__(self, other):
   		pass

	def __ge__(self, other):
    	pass

	def __lt__(self, other):
    	# print("lt")
    	print(self.age)
    	print(other.age)
    	return self.age < other.age

	def __le__(self, other):
    	pass


p1 = Person(18, 190)
p2 = Person(19, 190)
print(p1 < p2)
print(p1 <= p2) # p2 < p1
print(p1 == p2)
print(p1 != p2)
print(p1 <= p2) #报错,不支持叠加操作

# ----------------------------比较操作-补充------------------------------------

import functools


@functools.total_ordering
class Person:
    def __lt__(self, other):
        print("lt")
        # pass
        return False

    def __eq__(self, other):
        print("eq")
        pass

    # def __le__(self, other):
    #     print("le")

p1 = Person()
p2 = Person()

print(p1 <= p2)

print(Person.__dict__)

# ----------------------------上下文环境的布尔值------------------------------------

class Person:
    def __init__(self):
        self.age = 20

    def __bool__(self):
        return self.age >= 18
    pass

p = Person()

if p:
    print("xx")
遍历操作
怎样让我们自己创建的对象可以使用for in 进行遍历?
	实现__getitem__方法
		优先级低
		每次for in 获取数据时, 都会调用这个方法
	或者
	实现__iter__方法
		优先级高
		这个方法, 必须返回一个"迭代器"; 即, 具备"__iter__"和"__next__"方法
		当for in 遍历这个对象时, 会调用这个__iter__方法返回的迭代器对象的__next__方法
怎样让我们自己创建的对象可以使用next函数进行访问?
	实现__next__方法
补充
	1. __iter__方法可以恢复迭代器的初始化值, 复用迭代器
	2. "可迭代" 与 "迭代器"必须实现的方法
	3. iter方法的使用
# ----------------------------遍历操作------------------------------------
class Person:
    def __init__(self):
        self.result = 1

    def __getitem__(self, item):
        self.result += 1
        if self.result >= 6:
            raise StopIteration("停止遍历")

        return self.result
    pass

p = Person()

for i in p:
    print(i)


# 方式2
class Person:
    def __init__(self):
        self.result = 1

    def __iter__(self):
        print("iter")
        self.result = 1
        # return iter([1, 2, 3, 4, 5])
        return self 

    def __next__(self):
        self.result += 1
        if self.result >= 6:
            raise StopIteration("停止遍历")
        return self.result

p = Person()

# for i in p:
#     print(i)

print(next(p))
print(next(p))
print(next(p))
print(next(p))
print(next(p))
print(next(p))

result = next(p)
while result:
    print(result)
    result = next(p)

# ----------------------------恢复迭代器初始值------------------------------------


class Person:
    def __init__(self):
        self.age = 1

    def __getitem__(self, item):
        return 1
	def __iter__(self):
    	self.age = 1 # 此处语句使得迭代器可以使用多次,请思考原因
    	return self

	def __next__(self):
    	self.age += 1
    	if self.age >= 6:
        	raise StopIteration("stop")

    return self.age

next()
p = Person()

for i in p:
    print(i)
print(p.age)
for i in p:
    print(i)

import collections
print(isinstance(p, collections.Iterator))
print(isinstance(p, collections.Iterable))

# ----------------------------iter函数的使用------------------------------------
class Person:
    def __init__(self):
        self.age = 1

    def __getitem__(self, item):
        self.age += 1
        if self.age >= 6:
            raise StopIteration("stop")
        return self.age

    def __iter__(self):
        self.age = 1 
        return self

    def __next__(self):
        self.age += 1
        if self.age >= 6:
            raise StopIteration("stop")
        return self.age

    def __call__(self, *args, **kwargs):
        self.age += 1
        if self.age >= 6:
            raise StopIteration("stop")
        return self.age
p = Person()


pt = iter(p)
pt = iter(p.__next__, 4) # 输出结果:2,3
pt = iter(p, 4) # 输出结果:2,3

print(pt is p)

for i in pt:
    print(i)

l = [1, 2, 3]
lt = iter(l)
print(lt)
描述器
概念
	可以描述一个属性操作的对象
		对象
		属性的操作
			增/改
			删
			查
		描述
作用
	可以代为管理一个类属性的读写删操作, 在相关方法中, 对数据进行验证处理, 过滤处理等等
	如果一个类属性被定义为描述器,那么以后对这个类属性的操作(读写删), 都将由这个描述器代理
定义
	定义方式1
		property
	定义方式2
		三个方法
			__get__
			__set__
			__delete__
调用细节
	使用实例进行调用
		最多三个方法都会被调用
	使用类进行调用
		最多会调用get方法
	不能够顺利转换的场景
		新式类和经典类
			描述器仅在新式类中生效
		方法拦截
			一个实例属性的正常访问顺序
				实例对象自身的__dict__字典
				对应类对象的__dict__字典
				如果有父类, 会再往上层的__dict__字典中检测
				如果没找到, 又定义了__getattr__方法, 就会调用这个方法
			而在上述的整个过程当中, 是如何将描述器的__get__方法给嵌入到查找机制当中?
			就是通过这个方法进行实现
				__getattribute__
				内部实现模拟
					如果实现了描述器方法__get__就会直接调用
					如果没有, 则按照上面的机制去查找
注意
	"资料描述器"和"非资料描述器"
		如果实现了
			_get__
		如果实现了
			__get__
			__set__
	描述器和实例属性同名时, 操作的优先级问题
		资料描述器 > 实例字典 > 非资料描述器
# class Person:
# 	def __init__(self):
# 		self.__age = 10
# 	def get_age(self):
# 		return self.__age)
# 	def set_age(self,value):
# 		if value < 0:
# 			value = 0
# 		self.__age = value
# 	def del_age(self):
# 		del self.__age
# p = Person()
# print(p.age)
# p.set_age = -10
# print(p.get_age())
# p.del_age()
# print(p.get_age())

help(Person)

class Person:
    def __init__(self):
        self.__age = 10

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, value):
        if value < 0:
            value = 0
        self.__age = value

    @age.deleter
    def age(self):
        print("del age")
        del self.__age

    # age = property(get_age, set_age, del_age)
    # name = "sz"

p = Person()
p.age = 19
del p.age
print(p.age)

# ----------------------------描述器-定义方式2------------------------------------

class Age:
    def __get__(self, instance, owner):
        print("get")

    def __set__(self, instance, value):
        print("set")

    def __delete__(self, instance):
        print("delete")

class Person:
    age = Age() # 类属性
    def __init__(self):
        self.__age = 10
    
    # @property
    def get_age(self):
        return self.__age
    
    @age.setter
    def set_age(self, value):
        if value < 0:
            value = 0
        self.__age = value
    
    @age.deleter
    def del_age(self):
        print("del age")
        del self.__age
    
    age = property(get_age, set_age, del_age)

p = Person()
p.age = 10
print(p.age)
del p.age

# ----------------------------描述器-调用细节------------------------------------
class Age(object):
    def __get__(self, instance, owner):
        print("get")

    def __set__(self, instance, value):
        print("set")

    def __delete__(self, instance):
        print("delete")

class Person(object):
    age = Age()
    def __getattribute__(self, item):
        print "xxxxx"

p = Person()

p.age = 10
print(p.age)
del p.age

print(Person.age)
Person.age = 19
del Person.age

# ----------------------------描述器-和实例属性同名时, 操作优先级------------------------------------

# 资料描述器 get set
# 非资料描述器 仅仅实现了 get 方法, 那么他就是一个非资料描述器
# 资料描述器 > 实例属性 > 非资料描述器
class Age(object):
    def __get__(self, instance, owner):
        print("get")

    def __set__(self, instance, value):
        print("set")

    def __delete__(self, instance):
        print("delete")

class Person(object):
    age = Age()
    def __init__(self):
        self.age = 10

p = Person()

p.age = 10
print(p.age)
del p.age

print(p.__dict__)

# ----------------------------描述器-值的存储问题------------------------------------
class Person:
    def __init__(self):
        self.__age = 10

    def get_age(self):
        return self.__age

    def set_age(self, value):
        if value < 0:
            value = 0
        self.__age = value

    def del_age(self):
        print("del age")
        del self.__age
        
    age = property(get_age, set_age, del_age)

p = Person()
p.age = 10
print(p.age)
del p.age

class Age(object):
    def __get__(self, instance, owner):
        print("get")
        return instance.v

    def __set__(self, instance, value):
        print("set", self, instance, value)
        instance.v = value

    def __delete__(self, instance):
        print("delete")
        del instance.v

class Person(object):
    age = Age()

p = Person()
p.age = 10
print(p.age)
del p.age

p2 = Person()
p2.age = 11
print(p2.age)
print(p.age)
装饰器
使用类当做装饰器来使用
# ----------------------------使用类, 实现装饰器------------------------------------


# def check(func):
#     def inner():
#         print("登录验证")
#         func()
#     return inner
class check:
    def __init__(self, func):
        self.f = func

    def __call__(self, *args, **kwargs):
        print("登录验证")
        self.f()

@check
def fashuoshuo():
    print("发说说")
# fashuoshuo = check(fashuoshuo)

fashuoshuo()

x = "abc"
y = [x]
z = [x, y]
import objgraph
# objgraph.show_refs(y, filename='test.png')
objgraph.show_refs(z, filename="test.png")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2252390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构-散列函数的构造方法

一.数字关键词 关键词存储应该尽可能的离散 直接定址法:利用线性函数,例如上面的例子,h(key)key-1990,key1990&#xff0c;这个就被存放在0的位置 数字分析法:关键字可能有很到位组成,每一位变化可能都不一样&#xff0c;有的位是不变的,就是说不同的对象这一位都是一样的,有的…

单点登录解决方案 CAS(Central Authentication Service)详解

目录 CAS 的工作原理 票据&#xff08;Ticket&#xff09;详解 CAS 的优势 CAS 的应用场景 小结 参考资料 Central Authentication Service&#xff08;中央认证服务&#xff0c;简称 CAS&#xff09;是一个开源的企业级单点登录&#xff08;Single Sign-On, SSO&#xf…

输入json 达到预览效果

下载 npm i vue-json-pretty2.4.0 <template><div class"newBranchesDialog"><t-base-dialogv-if"addDialogShow"title"Json数据配置"closeDialog"closeDialog":dialogVisible"addDialogShow":center"…

U盘文件夹变打不开的文件:深度解析、恢复策略与预防之道

一、U盘文件夹变打不开的文件现象解析 在日常使用U盘的过程中&#xff0c;我们时常会遇到这样的困扰&#xff1a;原本存储有序、可以轻松访问的文件夹&#xff0c;突然之间变成了无法打开的文件。这些文件通常以未知图标或乱码形式显示&#xff0c;双击或右键尝试打开时&#…

2025年软考-网络工程师新旧教程及考纲变化对比!

2025网工教材改版基本确认&#xff01;网络工程师一直是软考中级的热门科目。最近&#xff0c;官方发布了官方第六版的网工教材&#xff0c;本次出版在原有第五版的基础上做了大量的删减&#xff0c;并新增了部分新内容。明年的软考考纲大概率会根据这次的新版教材进行修改&…

视觉处理基础1

目录 一、CNN 1. 概述 1.1 与传统网络的区别 1.2 全连接的局限性 1.3 卷积思想 1.4 卷积的概念 1.4.1 概念 1.4.2 局部连接 1.4.3 权重共享 2. 卷积层 2.1 卷积核 2.2 卷积计算 2.3 边缘填充 2.4 步长Stride 2.5 多通道卷积计算 2.7 特征图大小计算方法 2…

大疆T100大载重吊运植保无人机技术详解

大疆T100作为一款大载重吊运植保无人机&#xff0c;融合了全新的AI和AR功能&#xff0c;旨在进一步提升安全性并满足喷洒、播撒、吊运等多种作业场景的需求。以下是对其技术的详细解析&#xff1a; 一、总体性能 最大起飞重量&#xff1a;149.9公斤 喷洒容量&#xff1a;75升…

Kylin Server V10 下 RocketMQ 主备自动切换模式部署

一、NameServer简介 NameServer 是一个注册中心,提供服务注册和服务发现的功能。NameServer 可以集群部署,集群中每个节点都是对等的关系,节点之间互不通信。 服务注册 Broker 启动的时候会向所有的 NameServer 节点进行注册,注意这里是向集群中所有的 NameServer 节点注册…

ESP32+VSCODE开发过程无法使用Debug调试问题解决

1.点击Debug按钮报错 Error: libusb_open() failed with LIBUSB_ERROR_ACCESS Error: esp_usb_jtag: could not find or open device! 2.解决办法 1.找见espidf的安装目录下的如下文件&#xff08;如下自己的安装目录&#xff09; home\fjq\esp-idf\espidfv5.3.1\tools\tool…

【CSS】一篇掌握CSS

不是因为有了希望才去坚持,而是坚持了才有了希望 目录 一.导入方式 1.行内样式 2.内部样式 3.外部样式(常用) 二.选择器 1.基本选择器(常用) 1.1标签选择器 1.2类选择器 1.3id选择器 2.层次选择器 2.1后代选择器 2.2子选择器 2.3相邻兄弟选择器 2.4通用兄弟选择器…

MySQL底层概述—6.索引原理

大纲 1.索引原理 2.二叉查找树 3.平衡二叉树(AVL树) 4.红黑树 5.B-Tree 6.BTree 7.Hash索引 8.聚簇索引与非聚簇索引 1.索引原理 索引会在数据文件中(ibd文件)&#xff0c;通过数据页(Page)进行存储。索引可以加快检索速度&#xff0c;但也会降低增删改速度&#xff0…

C语言学习笔记:循环结构

循环结构 什么是循环 代码的重复执行&#xff0c;就叫做循环。 循环的分类 无限循环&#xff1a;程序设计中尽量避免无限循环&#xff0c;其实就是死循环。程序中的无限循环必须是可控的。有限循环&#xff1a;循环限定循环次数或者循环的条件。 循环的构成&#xff1a; …

stable diffusion实践操作-大模型介绍:SD的发展历史,SD1.5和SDXL之间的差别

大家有没有这样的困惑&#xff1a;在找模型时&#xff0c;老是会出现一些奇怪的标签&#xff0c;像 sd1.5、sdxl 之类的模型后缀&#xff0c;真让人摸不着头脑&#xff0c;一会儿 1.0&#xff0c;一会儿 1.5&#xff0c;一会儿 XL&#xff0c;完全搞不清楚状况。今天就来给大家…

AI高中数学教学视频生成技术:利用通义千问、MathGPT、视频多模态大模型,语音大模型,将4个模型融合 ,生成高中数学教学视频,并给出实施方案。

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下AI高中数学教学视频生成技术&#xff1a;利用通义千问、MathGPT、视频多模态大模型&#xff0c;语音大模型&#xff0c;将4个模型融合 &#xff0c;生成高中数学教学视频&#xff0c;并给出实施方案。本文利用专家模…

PyCharm中Python项目打包并运行到服务器的简明指南

目录 一、准备工作 二、创建并设置Python项目 创建新项目 配置项目依赖 安装PyInstaller 三、打包项目 打包为可执行文件 另一种打包方式(使用setup.py) 四、配置服务器环境 五、上传可执行文件到服务器 六、在服务器上运行项目 配置SSH解释器 配置部署 上传代…

git clone超大仓库时报错:fatal: early EOF

环境版本&#xff1a; 系统&#xff1a;Ubuntu git版本&#xff1a;version 2.43.0 在执行git clone命令时报错&#xff0c;信息如下&#xff1a; 系统&#xff1a;Win10 git版本&#xff1a;version 2.47.0 解决办法1&#xff1a; 1、关闭压缩&#xff1a; git conf…

C++基础:list的基本使用

文章目录 1.基本构造和插入删除基本构造和尾插数据迭代器的分类内置排序sort任意位置插入删除 2.链表的合并,去重和剪切链表的合并链表去重链表的剪切 list的本质就是带头双向循环列表 1.基本构造和插入删除 基本构造和尾插数据 与之前vector的方法相同直接调用即可 迭代器的分…

C++ explicit关键字的作用

C explicit关键字的作用 explicit的作用 这个关键字只能用于类的构造函数&#xff0c;被修饰的构造函数不能发生相应的隐式类型转换&#xff0c;只能以显式的方式进行类型转换。 另外&#xff0c;这个关键字只能用于单个参数&#xff08;这里的单个参数包括多参但是具有默认…

Leecode刷题C语言之N皇后②

执行结果:通过 执行用时和内存消耗如下&#xff1a; struct hashTable {int key;UT_hash_handle hh; };struct hashTable* find(struct hashTable** hashtable, int ikey) {struct hashTable* tmp NULL;HASH_FIND_INT(*hashtable, &ikey, tmp);return tmp; }void insert(…

全场景——(八)低成本 Modbus 传感器的实现

文章目录 一、硬件资源介绍与接线二、创建与体验第 1 个工程2.1 创建工程2.2 配置调试器2.3 配置 GPIO 操作 LED 三、UART 编程3.1 使用 STM32CubeMX 进行配置3.1.1 UART13.1.2 配置 RS485方向引脚 3.2 封装 UART3.3 上机实验3.3.1 硬件连接3.3.2 STM32H5 程序改造3.3.3 STM32F…