一切皆为对象
以搬家具到屋子为例
面向过程分析这个事 把事情分成几步 从上到下按照流程走下去自然就完成了 这个也是我们常见的逻辑思维思路
1。人去搬动家具 2 移动到屋子 3 重复 1 2步若干次 4 所有家具都搬进去了或者屋子满了为止 5流程结束
面向对象分析这事 首先分析 办这个事的主体都有谁 然后这个事 需要这几个对象都有什么特点 然后就是这些对象的特点怎么样交互才能完成这事
对象:
1 人对象 2 家具对象 3 屋子对象
要办这事这些对象之间需要什么特点:
1 人对象需要有搬动这个功能 2 家居对象 需要有个占地面积的功能还有家具编号 3 屋子对面需要有总面积 剩余面积的特点
交互来完成目标(利用这几个对象和对象自身的特点来进行交互以达到目标):
人这个对象的搬动操作 搬动目标是家具对象n 搬动到的地方是屋子对象 判断完成条件是 所有家具都搬动过了 或者 屋子对面的剩余面具属性小于等于0 其实交互也可以部分看作是按照流程 面向过程
类就是汽车图纸 这个类的对象 就是按照这图纸制造的一辆一辆的汽车
class TestClassObject(object): """ 展示下新类的常见结构 """ name = "TestClassObject.name" # 类属性 name 可以在该类的所有实例下调用 但是只能通过类名.类属性进行修改 不能类实例.类属性进行修改 fun = "测试用类" # 类属性 fun def __init__(self, a, b, c): # 固定的类初始化函数 在类实例化的时候自动隐式调用 该类方法内也是统一声明类实例属性的地方 self.a = a # 类实例属性 a self.b = b # 类实例属性 b self.c = c # 类实例属性 c def test1(self): # 类实例方法 第一个参数是self 但是调用类实例方法第一个参数不用写 print(self.a + self.b) @classmethod def test2(cls): # 这是类方法 第一个参数代指类本身 可以在这个类方法里面调用类属性 其他类方法来运算 print(cls.name) @staticmethod def test4(): # 这是静态方法 注意这个静态方法不能有 类的属性方法 或者 类实例的属性和方法在 看做是一个普通的函数即可 print("这里是静态方法")
1.每次创建对应实例就会自动隐式调用__init__()
2 第一个参数必然是self 类方法的参数self代表的是类实例本身 注意不是类本身 类本身用cls来代表
3 普通的类实例属性一般都在init里面声明 也是规范的类实例化赋初值的地方
4 类属性和类实例属性
(1)类属性和类实例属性的区分: 定义在类方法外 但是依然在类内声明的就是类属性 类实例属性是定义在类方法里面并且以self.变量名声明和使用的的都是类实例属性 还有一种是在类方法中声明 但是只是以 变量名 = 值 的形式的只是一个单纯的局部变量 一般而言统一规范 类实例属性都在init方法里面声明初值
(2)修改类属性:类属性是在该类下的所有实例都共享该类属性 都可以通过类实例.类属性名 获取到类属性的内容 但是 无法通过类实例.类属性名 = 新值 来修改类属性的内容 修改类属性 还是要以 类名.类属性 = 新值 来修改
(3)修改类实例属性: 自然是 类实例.类实例属性 = 新值
类的实例化
实例名1 = 类名(初始化的参数1,初始化的参数2,初始化的参数3,…)
类实例的使用
实例名1.类实例属性
实例名1.类实例方法(参数)
类实例属性的添加和删除
添加:直接在代码中写 实例名1.新属性名 = 值 就好 不过这种写法太随意了 不太规范 还是在类内提前声明好就是 也方便管理代码
删除:del(实例名1.新属性名)
类方法:
1.第一个参数必须是cls 类方法可以使用类属性和其他类方法 但是不能使用 类实例属性和方法 因为cls代指类本身 而不是类实例
2. 调用 类名.类方法()
3 类方法定义的时候开头加上@classmethod
类实例方法:
1.第一个参数必须是self 类实例方法可以使用 类实例属性和类实例方法 但是切不可以使用 类属性类方法
2 调用 类实例名.类实例方法() 还有一种未绑定方法 类名.类实例方法(实例名,参数1,参数2….)
静态方法:
1.参数不能包含cls self 方法内不能调用 类属性类方法 类实例属性 类实例方法 可以理解为一个在类内的普通函数
2 调用 类名.静态方法() 类实例名.静态方法()
3 类方法定义的时候开头加上@staticmethod
class TestClassObject(object): """ 展示下新类的常见结构 """ name = "TestClassObject.name" # 类属性 name 可以在该类的所有实例下调用 但是只能通过类名.类属性进行修改 不能类实例.类属性进行修改 fun = "测试用类" # 类属性 fun def __init__(self, a, b, c): # 固定的类初始化函数 在类实例化的时候自动隐式调用 该类方法内也是统一声明类实例属性的地方 self.a = a # 类实例属性 a self.b = b # 类实例属性 b self.c = c # 类实例属性 c def test1(self): # 类实例方法 第一个参数是self 但是调用类实例方法第一个参数不用写 print(self.a + self.b) @classmethod def test2(cls): # 这是类方法 第一个参数代指类本身 可以在这个类方法里面调用类属性 其他类方法来运算 print(cls.name) @staticmethod def test3(): # 这是静态方法 注意这个静态方法不能有 类的属性方法 或者 类实例的属性和方法在 看做是一个普通的函数即可 print("这里是静态方法") # 调用类属性 类方法: 类名.类属性 类名.类方法() 不推荐 类实例名.类属性 类实例名.类方法() print("类属性为:{}".format(TestClassObject.name)) # 类方法 TestClassObject.test2() # 实例属性 print("类实例属性为:{}".format(test_class_object.a)) # 类实例方法 test_class_object.test1() # 类静态方法 类名.静态方法() 类实例名.静态方法() 都可以 TestClassObject.test3() test_class_object.test3()
Python下 没有public 和 protected private
1.public :默认情况下 类属性 类方法 类实例属性 类实例方法 静态方法 都是public public下 类内可用 类外 和子类中都可以直接使用
2 protected:属性方法前加 _ 就是protected 能在本类和子类中使用 但是类外直接访问不行
3.private :属性方法 名字前加上 __则表示为private 只能在本类中使用 在类外或者子类中都无法使用
4.__doc__ __init__ __new__之类的固定的类方法 不是私有 只是固定的写法
5.封装函数property() 用于给私有属性提供进一步的封装控制
私有属性=property(读取该私有属性触发的类方法,[修改该私有属性触发的类方法],[del该私有属性触发的类方法],【读取该私有属性__doc__触发的类方法],)
这4个参数不是都必须写的 可以写一个 可以写2个 3个 4个 分别用来控制 外界或者子类访问私有属性触发的函数 比如我们只要让他有只读权限 就只设置第一个参数 其他不管即可
6.如果知道了 类名 和私有属性或者私有方法真正的名 我们可以用 实例名._类名私有属性名 的方式直接访问修改 私有属性 比如下面的testaa._TestProperty__aa的用法
class TestProperty(object): """ 测试私有属性的Property的用法 """ def __init__(self, aa): self.__aa = aa # 给私有属性赋初值 # 外界想要用 类实例名.变量名的方式来获取这个私有变量的时候触发 注意 类实例名.变量名的变量名 以下面的 变量名=property 为准 def getaa(self): print("=[获取]私有属性aa的值=") return self.__aa # 外界想要用 类实例名.变量名的方式来修改这个私有变量的时候触发 def setaa(self, v): print("=[修改]私有属性aa的值=") self.__aa = v # 外界想要用 del(类实例名.变量名)的方式来修改这个私有变量的时候触发 注意的是del函数无法真正的销毁这个私有属性 要想彻底销毁这个私有属性 需要在类内执行del才可以 def delaa(self): print("=[删除]私有属性aa的值=") # del(self.__aa) # 要想彻底销毁这个私有属性 需要在类内执行del才可以 self.__aa = 0 # 假装销毁一下归零吧 # 这个变量才是外面要直接调用的变量名 而不是私有属性名 这个变量可以随意改 aaa = property(getaa, setaa, delaa, "doc1111") # aaa = property(getaa) #设置为外界只读 testaa = TestProperty(14) print("私有类属性aa为:{}".format(testaa.aaa)) testaa.aaa = 24 print("私有类属性aa为:{}".format(testaa.aaa)) del(testaa.aaa) print("私有类属性aa为:{}".format(testaa.aaa)) print(testaa._TestProperty__aa) testaa._TestProperty__aa = 34 # 知道了类名和私有属性名 用这种方式可以直接修改访问私有属性 print("私有类属性aa为:{}".format(testaa.aaa))
public protected private三种封装类型 在 当前类 当前类的子类 和外部访问的权限情况
范围\封装类型 | public | protected | private |
类内 | ok | ok | ok |
外部访问 | ok | 无法直接访问修改 | 无法直接访问修改 |
子类是否继承到这些封装属性方法 | ok | ok | 虽然dir(子类)显示有该私有属性方法但是无法在子类中调用该继承属性方法 |
子类中能否直接调用父类.封装属性方法 | ok | ok | 调用失败 没找到对应的属性方法 |
结论:public是哪个地方都能用 protected是类内 子类能继承 子类也能直接调用 但是就是外部无法直接访问 private是只能类内调用 子类继承这种私有属性方法但无法使用 子类更无法直接使用这种父类的私有属性方法
单继承
class TestObject(object): # 括号内是父类名字
pass
多继承
class TestObject(TestA, TestB): # 括号内是父类们的名字
pass
多继承的问题
一个子类继承多个父类,如果这些父类的方法属性重名相互冲突 一般都是前面的父类的同名方法属性覆盖后面的 并且并不推荐使用多继承
子类的属性方法的来源
由于存在继承 类实例使用的属性方法 可能是源于类本身 也可能是源于类的父类中 或者源于 父类的父类 祖父类 等等一级一级的向上找 都是有可能的 至于先找谁后找谁就涉及到了 mro问题
父类的方法的重写
没什么说的
class TestFather(object):
def hobby(self): # 父类的爱好方法是喜欢喝酒
print(“爱好是喝酒”)
class Tom(TestFather): # 但是tom这个不喜欢喝酒 但是会自动继承父类 TestFather的爱好方法 所以这里重写下 这个爱好方法改变他的内容
def hobby(self):
print(“爱好是睡觉”)
非绑定方法
解决通过类名调用该类对应的实例方法 通过类名调用实例方法 叫非绑定方法 具体形式 类名.实例方法名(实例名,参数1,参数2….) 这样可以使用类名来调用实例方法 注意严格按照实例方法的参数来写入参数 一个都不能少 不会自动省略self了 如果该实例方法内部还掺杂 其他实例属性或者其他实例方法无法在参数里面完全给予 则只能另想其他思路
super()函数
解决 子类调用父类中的方法的问题 一般是用来载入父类的__init__方法 而且注意父类的__init__()的参数个数 也要原样的写上 如果是多继承,那么除了第一个父类可以用super().父类方法(参数1.参数2,…) 其他的依然要使用 父类名.父类方法(参数1.参数2,…) 来调用
注意 super在多继承情况下 super是代表当前类第一个父类 根据该父类的方法 super自动加载self 这个不用写 其他的参数都要写
个人推荐 子类调用父类中的方法上 如果单继承 推荐super 如果多继承 第一个父类的方法都用super执行 其他的父类则推荐 父类名.父类方法名(参数1,…) 注意这种写法严格按照实例方法的参数来写入参数 一个都不能少 不会自动省略self了
class People: def __init__(self,name): self.name = name def say(self): print("我是人,名字为:",self.name) class Animal: def __init__(self,food): self.food = food def display(self): print("我是动物,我吃",self.food) class Person(People, Animal): #自定义构造方法 def __init__(self,name,food): #调用 People 类的构造方法 super().__init__(name) #super(Person,self).__init__(name) #执行效果和上一行相同 #People.__init__(self,name)#使用未绑定方法调用 People 类构造方法 #调用其它父类的构造方法,需手动给 self 传值 Animal.__init__(self,food) per = Person("zhangsan","熟食") per.say() per.display()
我是人,名字为: zhangsan
我是动物,我吃 熟食
了解:动态的添加或者修改类 或者 类实例的属性和方法
类名.新方法名 = 函数名
类实例名.新方法名 = 函数名
但是这种动态的添加修改 类属性 类方法 实例属性 实例方法的有点危险 可以在类内规定 运行动态添加修改的属性名或者方法名 但是类的动态添加修改不在限制范围内
了解:type ()函数的进一步的用法 创建自定义类(创建一个新的类型) type(name, bases, dict)
#定义一个实例方法 def say(self): print("我要学 Python!") #使用 type() 函数创建类 CLanguage = type("CLanguage",(object,),dict(say = say, name = "C语言中文网")) #创建一个 CLanguage 实例对象 clangs = CLanguage() #调用 say() 方法和 name 属性 clangs.say() print(clangs.name)
从底层原理看 我们最常见的用class定义类 到了底层本质上就是用type来声明一个类的
1.多态发生在有继承关系的子类父类之间
2.子类重写了父类的某方法 使该方法的结果和父类不同呈现多种形态
class CLanguage: def say(self): print("调用的是 Clanguage 类的say方法") class CPython(CLanguage): def say(self): print("调用的是 CPython 类的say方法") class CLinux(CLanguage): def say(self): print("调用的是 CLinux 类的say方法") a = CLanguage() a.say() a = CPython() a.say() a = CLinux() a.say()
调用的是 Clanguage 类的say方法
调用的是 CPython 类的say方法
调用的是 CLinux 类的say方法
Python3下所有没指定父类的类默认都继承object 就是所说的新类 Python3之前的都是经典类
没继承和继承了object的区别如下
Person [‘__doc__‘, ‘__module__‘, ‘name‘] #没有继承object的普通景点类 就2个类方法 name是自己定义的类实例属性
Animal [‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘,
‘__hash__‘, ‘__init__‘, ‘__module__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘,
‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘name‘] #这个就是继承了object
object类的类属性方法的简单介绍
https://www.jb51.net/article/182040.htm
class object: """ The most base type """ # del obj.xxx或delattr(obj,‘xxx‘)时被调用,删除对象中的一个属性 def __delattr__(self, *args, **kwargs): # real signature unknown """ Implement delattr(self, name). """ pass # 对应dir(obj),返回一个列表,其中包含所有属性和方法名(包含特殊方法) def __dir__(self, *args, **kwargs): # real signature unknown """ Default dir() implementation. """ pass # 判断是否相等 equal ,在obj==other时调用。如果重写了__eq__方法,则会将__hash__方法置为None def __eq__(self, *args, **kwargs): # real signature unknown """ Return self==value. """ pass # format(obj)是调用,实现如何格式化obj对象为字符串 def __format__(self, *args, **kwargs): # real signature unknown """ Default object formatter. """ pass # getattr(obj,‘xxx‘)、obj.xxx时都会被调用,当属性存在时,返回值,不存在时报错(除非重写__getattr__方法来处理)。 # 另外,hasattr(obj,‘xxx‘)时也会被调用(估计内部执行了getattr方法) def __getattribute__(self, *args, **kwargs): # real signature unknown """ Return getattr(self, name). """ pass # 判断是否大于等于 greater than or equal,在obj>=other时调用 def __ge__(self, *args, **kwargs): # real signature unknown """ Return self>=value. """ pass # 判断是否大于 greater than,在obj>other时调用 def __gt__(self, *args, **kwargs): # real signature unknown """ Return self>value. """ pass # 调用hash(obj)获取对象的hash值时调用 def __hash__(self, *args, **kwargs): # real signature unknown """ Return hash(self). """ pass def __init_subclass__(self, *args, **kwargs): # real signature unknown """ This method is called when a class is subclassed. The default implementation does nothing. It may be overridden to extend subclasses. """ pass # object构造函数,当子类没有构造函数时,会调用object的__init__构造函数 def __init__(self): # known special case of object.__init__ """ Initialize self. See help(type(self)) for accurate signature. """ pass # 判断是否小于等于 less than or equal,在obj<=other时调用 def __le__(self, *args, **kwargs): # real signature unknown """ Return self<=value. """ pass # 判断是否小于 less than,在obj<other时调用 def __lt__(self, *args, **kwargs): # real signature unknown """ Return self<value. """ pass # 创建一个cls类的对象,并返回 @staticmethod # known case of __new__ def __new__(cls, *more): # known special case of object.__new__ """ Create and return a new object. See help(type) for accurate signature. """ pass # 判断是否不等于 not equal,在obj!=other时调用 def __ne__(self, *args, **kwargs): # real signature unknown """ Return self!=value. """ pass def __reduce_ex__(self, *args, **kwargs): # real signature unknown """ Helper for pickle. """ pass def __reduce__(self, *args, **kwargs): # real signature unknown """ Helper for pickle. """ pass # 如果不重写__str__,则__repr__负责print(obj)和交互式命令行中输出obj的信息 # 如果重写了__str__,则__repr__只负责交互式命令行中输出obj的信息 def __repr__(self, *args, **kwargs): # real signature unknown """ Return repr(self). """ pass # 使用setattr(obj,‘xxx‘,value)、obj.xxx=value是被调用(注意,构造函数初始化属性也要调用) def __setattr__(self, *args, **kwargs): # real signature unknown """ Implement setattr(self, name, value). """ pass # 获取对象内存大小 def __sizeof__(self, *args, **kwargs): # real signature unknown """ Size of object in memory, in bytes. """ pass # 设置print(obj)打印的信息,默认是对象的内存地址等信息 def __str__(self, *args, **kwargs): # real signature unknown """ Return str(self). """ pass @classmethod # known case def __subclasshook__(cls, subclass): # known special case of object.__subclasshook__ """ Abstract classes can override this to customize issubclass(). This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached). """ pass # 某个对象是由什么类创建的,如果是object,则是type类<class ‘type‘> __class__ = None # 将对象中所有的属性放入一个字典,例如{‘name‘:‘Leo‘,‘age‘:32} __dict__ = {} # 类的doc信息 __doc__ = ‘‘ # 类属于的模块,如果是在当前运行模块,则是__main__,如果是被导入,则是模块名(即py文件名去掉.py) __module__ = ‘‘
__new__ __init__ __str__ __del__的介绍
类初始化的机制的粗浅理解
首先开始初始化->__new__被触发->类本身作为参数被传入到__new__里面->使用继承自object类或者父类的__new__方法 在内存中开辟了一个空间来准备存储这个类的实例对象,并且把开辟的空间地址(也有一说是返回的一个实例对象) 自动传给__init__作为它的第一个参数并自动调用了__init__->__init__方法在__new__开辟的空间进行了进一步的初始化工作 完成整个初始化 整个初始化是__new__和__init__一起配合才完成的
__new__
初始化对象的时候触发 __new__是个类方法 参数是类本身(参数cls) 作用是创建一个类实例的空间 返回一个类实例对象自动给__init__作为第一个参数 并触发__init__继续完成初始化
__init__
承接__new__继续完成初始化工作 没有返回值 是个类实例方法
一般情况下都是在__init__里面显式对类实例属性统一的声明赋初值和进行前期处理和验证
__str__
print函数的时候触发 简单说 print(类实例名) 其实就是自动调用了 类实例.__str__ 默认情况下会输出 实例名和对应的内存地址 如果我们改写__str__那么print(类实例名) 显示的内容自然是按照我们的定义来显示的
class Student(object): def __init__(self,id,name,age): self.id=id self.name=name self.age=age def __str__(self): return "学号:{}--姓名:{}--年龄{}".format(self.id,self.name,self.age) s=Student(111,"Bob",18) print(s)
学号:111–姓名:Bob–年龄18 # 而不是 <main.Student object at 0x0362EBF0>
__del__
对象从内存删除的时候触发 比如该实例被del()了 自然会自动触发类实例.__del__() 没什么可说的
总结需求 –> 分析 -> 获取其中的各个对象 和对象具备的属性方法 –> 研究对象之间的交互 构建整个流程
项目简易分析 很简单 把需求写出来 然后提取出名词 动词 形容词 数据等等 一般情况下 名词就是该项目的一个对象 形容词很可能是某个对象的属性 动词很有可能是某个对象的方法 然后建立对象和对应的属性方法 然后尝试用对象和具备的属性方法来交互完成整个项目要求 如果存在问题再修正 不断完善
实例1:屋子放家具
1.2个名词 屋子 家具 不过按理说还有一个移动家具的 人存在 暂时是3个对象 屋子 家具 人
2 屋子没法自己把家具拉进去 家具自己也没张腿 所以 人 必须具备方法 搬动 这个搬动方法应该至少2个参数 一个是搬动什么 第二个参数是搬动到哪里去 家具存在多个 自然要增加一个 家具对象的属性 家具id和家具名字 屋子应该只有一个 不需要屋子序号 只要一个屋子名字属性即可
屋子 属性:屋子id 屋子名
人 方法:搬动
家具 属性:家具id 家具名字
3 要完成屋子放家具的动作 对象人.搬动(被搬动的家具id,搬动到哪的屋子id)
实例2:小明体重75公斤 每次跑步减少0.5 每次吃饭增加1
1。名词就一个小明 对象就小明一个对象 体重是附属于小明的自然是小明这个对象的属性 动词 跑步 吃饭 都是属于小明对象的方法
2 对象小明
属性:体重
方法: 跑步 吃饭
3 简单的概念结构
class xiaoming(object):
def __init__(self,weight):
self.weight = weight
def showweight():
print(self.weight)
def run():
self.weight –= 0.5
def eat():
self.weight += 1
设计模式很多 先来说下单例模式
简单说 无论创建多少类的实例 单例模式会让从始至终只有一开始创建的那个类实例存在
单例模式的实现主要是对 类的__new__的重写来实现的 每次要创建新的类实例 触发__new__的时候 在__new__里面都会检查下 之前记录的类实例的是否还存在 存在则返回这个已存在的实例对象的内存地址给__init__就是 如果不存在则创建下新的类实例 然后记录下这个类实例到类属性中 然后把新的类属性返回给__init__继续完成初始化的工作
一个简易的单例模式:没考虑多线程的问题 后面再说
class TestOnlyMode(object): """ 简单的一个单例模式结构 """ # 类属性 用来记录唯一的类实例对象和是否要初始化实例的各个参数 _only_record = None _is_init = False def __new__(cls, *args, **kwargs): if cls._only_record: # _only_record里面已经存储了一个类实例了 就不用创建了 print("_only_record 为真 不用创建实例了[{}]".format(cls._only_record)) pass else: # 还没创建实例呢 就现在创建1个 print("_only_record 为假 创建实例中") cls._only_record = object.__new__(cls) print("_only_record 为真 创建实例完毕[{}]".format(cls._only_record)) return cls._only_record # 返回个实例对象给init处理 def __init__(self, a, b, c): print(self._is_init) if self._is_init: # 为真表示已经实例化完毕了 不用再次连续设置初值 print("无需初始化参数") pass else: # 没实例化自然要设置初值 print("初始化参数了") self.a = a self.b = b self.c = c self._is_init = True def showit(self): print("a:{} ,b:{} ,c:{}".format(self.a, self.b, self.c)) aa = TestOnlyMode(1, 2, 3) print(aa.showit()) bb = TestOnlyMode(1, 2, 4) print(bb.showit()) cc = TestOnlyMode(2, 2, 3) print(cc.showit()) print(id(aa)) print(id(bb)) print(id(cc))
黑马python入门(5):Python基础(面向对象相关)
原文:https://www.cnblogs.com/zjl8455482/p/13658072.html