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

如何定义一个类?

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")

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

以达梦为数据库底座时部署的微服务页面报乱码,调整兼容模式

1.问题描述 部署微服务&#xff0c;文件、代码是延用的mysql类型的&#xff0c;部署前做了部分适配&#xff0c;但是在使用dm数据库进行安装的服务在页面上查询出的数据却都是乱码 2.查询官网&#xff0c;注意到一个参数COMPATIBLE_MODE兼容模式的配置 考虑是延用mysql&…

.net core MVC入门(三)——Product页面添加

文章目录 项目地址一、Product数据库准备 项目地址 教程作者&#xff1a;教程地址&#xff1a; 代码仓库地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow一、Product数据库准备 添加Product的EF上下文 public DbSet<Category> Categories { get; set; …

DDR3与MIG IP核(三)

.init_calib_complete&#xff1a;DDR3初始化信号 MIG IP核的28位地址对应DDR3地址的对应关系&#xff1a;3代表8个bank 写数据时序图&#xff1a;&#xff08;三种写数据的方式&#xff09; 1&#xff1a;写数据app_wdf_data时序发生在写命令app_cmd和写地址app_addr之前 2…

Python酷库之旅-第三方库Pandas(251)

目录 一、用法精讲 1186、pandas.tseries.offsets.BusinessMonthEnd.is_year_start方法 1186-1、语法 1186-2、参数 1186-3、功能 1186-4、返回值 1186-5、说明 1186-6、用法 1186-6-1、数据准备 1186-6-2、代码示例 1186-6-3、结果输出 1187、pandas.tseries.offs…

写NFC微信小程序跳转Uri标签

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1b8bEEGz&ftt&id615391857885 Dim dispstr As String Dim status As Byte Dim status1 As Byte Dim afi As Byte Dim myctrlword As Byte Dim mypiccserial(0 To 7) …

关于单片机的原理与应用!

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///目前正在学习C&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于单片…

【Linux】————(日志、线程池及死锁问题)

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;Linux 创作时间 &#xff1a;2024年11月29日 日志 关于日志&#xff0c;首先我们来说一下日志的作用&#xff0c; 作用&#xff1a; 问题追踪&#xff1a;通过日志不仅仅包括我们程序的一些bug&#xff0c;也可以在…

基于深度学习的甲状腺结节影像自动化诊断系统(PyQt5界面+数据集+训练代码)

随着医学影像技术的发展&#xff0c;计算机辅助诊断在甲状腺结节的早期筛查中发挥着重要作用。甲状腺结节的良恶性鉴别对临床治疗具有重要意义&#xff0c;但传统的诊断方法依赖于医生的经验和影像学特征&#xff0c;存在一定的主观性和局限性。为了解决这一问题&#xff0c;本…

本地项目通过git传递给新建的github库

第一步&#xff0c;打开终端进入本地项目目录 第二步&#xff0c;初始化Git仓库 git init第三步&#xff0c;添加远程仓库 git remote add origin https://github.com/用户名/仓库名.git第四步&#xff0c;添加所有文件到Git版本控制 git add .这个命令会将所有文件添加到暂…

【Maven Helper】分析依赖冲突案例

目录 Maven Helper实际案例java文件pom.xml文件运行抛出异常分析 参考资料 《咏鹅》骆宾王 鹅&#xff0c;鹅&#xff0c;鹅&#xff0c;曲项向天歌。 白毛浮绿水&#xff0c;红掌拨清波。 骆宾王是在自己7岁的时候就写下了这首杂言 Maven Helper A must have plugin for wor…

第426场周赛:仅含置位位的最小整数、识别数组中的最大异常值、连接两棵树后最大目标节点数目 Ⅰ、连接两棵树后最大目标节点数目 Ⅱ

Q1、仅含置位位的最小整数 1、题目描述 给你一个正整数 n。 返回 大于等于 n 且二进制表示仅包含 置位 位的 最小 整数 x 。 置位 位指的是二进制表示中值为 1 的位。 2、解题思路 我们需要找到一个整数 x&#xff0c;使得&#xff1a; x ≥ nx 的二进制表示中仅包含置位…

Vue框架开发一个简单的购物车(Vue.js)

让我们利用所学知识来开发一个简单的购物车 &#xff08;记得暴露属性和方法&#xff01;&#xff01;&#xff01;&#xff09; 首先来看一下最基本的一个html框架 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…

注册表修改键盘位置

1.winr 输入 regedit 2.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout 3.右键Keyboard Layout->新建->二进制值->取名Scancode Map 4.右键Scancode Map&#xff0c;修改如下 //第一列 自动生成序号&#xff0c;不用管 第一行 输入8个00 第二…

【Verilog】实验二 数据选择器的设计与vivado集成开发环境

目录 一、实验目的 二、实验环境 三、实验任务 四、实验原理 五、实验步骤 top.v mux2_1.v 一、实验目的 1. 掌握数据选择器的工作原理和逻辑功能。 2. 熟悉vivado集成开发环境。 3. 熟悉vivado中进行开发设计的流程。 二、实验环境 1. 装有vivado的计算机。 2. Sw…

一、文本预处理

文本预处理 前言一、文本处理的基本方法1.1 分词1.1.1 举例&#xff1a;1.1.2 作用1.1.3 分词工具——jieba1.1.3.1 jieba特性1.1.3.2 jieba 的 API 代码演示 二、命名实体识别2.1 命名实体2.2 命名实体识别2.3 举例2.4 作用 三、词性标注3.1 词性3.2 词性标注3.3 jieba词性对照…

【HM-React】02. React基础-下

React表单控制 受控绑定 概念&#xff1a;使用React组件的状态&#xff08;useState&#xff09;控制表单的状态 function App(){const [value, setValue] useState()return (<input type"text" value{value} onChange{e > setValue(e.target.value)}/>) …

二分法篇——于上下边界的扭转压缩间,窥见正解辉映之光(2)

前言 上篇介绍了二分法的相关原理并结合具体题目进行讲解运用&#xff0c;本篇将加大难度&#xff0c;进一步强化对二分法的掌握。 一. 寻找峰值 1.1 题目链接&#xff1a;https://leetcode.cn/problems/find-peak-element/description/ 1.2 题目分析: 题目要求返回数组内…

【C语言】结构体(一)

一&#xff0c;是什么 结构体就是一些值的集合&#xff0c;这些值称为成员变量。 结构体的每个成员可以是不同类型的变量。说到集合&#xff0c;数组也是集合&#xff0c;但是不同的是数组只能是相同类型元素的集合。 二&#xff0c;结构体的声明 struct tag {   member1;…

Leetcode - 周赛425

目录 一&#xff0c;3364. 最小正和子数组 二&#xff0c; 3365. 重排子字符串以形成目标字符串 三&#xff0c;3366. 最小数组和 四&#xff0c;3367. 移除边之后的权重最大和 一&#xff0c;3364. 最小正和子数组 本题可以直接暴力枚举&#xff0c;代码如下&#xff1a; …

uniapp Electron打包生成桌面应用exe文件

1.uniapp Electron打包生成桌面应用exe文件 随着跨平台开发的需求日益增长,UniApp 成为了开发者们的首选之一。通过 UniApp,你可以使用 Vue.js 的语法结构和组件系统来构建原生应用、Web 应用甚至是桌面应用。本文将详细介绍如何使用 UniApp 将你的项目打包成 Windows 桌面端…