python中的类python中的类 面向对象与面向过程的本质的区别 面向对象与面向过程的本质的区别
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
可以拿生活中的实例来理解面向过程与面向对象,例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用不同的方法来实现。
如果是面向对象的设计思想来解决问题。面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。
属性用来描述具体某个对象的特征。比如小志身高180M,体重70KG,这里身高、体重都是属性。
面向对象的思想就是把一切都看成对象,而对象一般都由属性+方法组成!
属性属于对象静态的一面,用来形容对象的一些特性,方法属于对象动态的一面,咱们举一个例子,小明会跑,会说话,跑、说话这些行为就是对象的方法!所以为动态的一面, 我们把属性和方法称为这个对象的成员!
类:具有同种属性的对象称为类,是个抽象的概念。比如“人”就是一类,期中有一些人名,比如小明、小红、小玲等等这些都是对象,类就相当于一个模具,他定义了它所包含的全体对象的公共特征和功能,对象就是类的一个实例化,小明就是人的一个实例化!我们在做程序的时候,经常要将一个变量实例化,就是这个原理!我们一般在做程序的时候一般都不用类名的,比如我们在叫小明的时候,不会喊“人,你干嘛呢!”而是说的是“小明,你在干嘛呢!”
面向对象有三大特性,分别是封装性、继承性和多态性。
万物皆对象(object),在别的语言中有的数据类型可能不属于对象,但是在python里所有的数据类型都可以是对象。面向对象——在解决问题的时候,关注的是解决问题所需要的对象。
面向过程需要关心做事的每一个步骤,全部由自己来实现;而面向对象要做一件事,都是在找这件事情可以分配给哪个对象来做,对象也可以把任务继续交给下面的对象来做。面向对象做这件事情的步骤并没有减少,只不过它把不同功能的步骤划分到了某一个对象里,所以面向对象是对面向过程的封装。

面向对象编程的步骤:
列举出一个任务的具体实现步骤
试图分离这些实现步骤中的功能代码块
将这些功能代码块,划分到某一个对象中
根据这个对象以及对应的行为,抽象出对应的类 。 —设计类
类 是对某一个具体对象特征的抽象。属性是一些静态的特征值,方法是动态的动作。

张三这个具体的对象,抽象出一个类叫不良青年,这是一个抽象的概念,并不是某一个具体的人。这个不良青年的这个类,也具有一些属性,比如身高体重;也有一些行为,比如吃喝嫖赌。但是这些都是抽象的概念,并没有具体的数值。
不良青年应该有一个年龄的属性,但是不同的不良青年,比如张三李四王五,有不同的年龄。
类的作用:根据抽象的类,生产出具体的对象。

类是这些它生成的对象的模板
类的组成:类的名称、属性、方法。(类的属性和方法都是抽象的概念,没有具体的值;类在产生对象后,对象才有具体的属性值和方法实现)
对象和类的关系:对象可以抽象出一个类,类可以实例化一个对象。
创建类: class Money:#要注意类名的首字母要大写,这是规范;不要小括号。这个Money除了是个类名(类名不可修改),还是个变量名称(可以被改名,如Money=abc,但改了之后好像就不是指向Money这个类了)。视频讲解

一旦定义一个类,就会开辟一块内存给它
还可以通过type元类来创建类,比较高级的用法 教程
创建对象:
class Money:
pass
#根据这个类,实例化一个对象
one = Money() #类+()可以实例化一个对象,赋值给one变量,接下来就可以通过one这个变量
#来操作这个对象

one指向了Money实例化的对象的地址(实例化对象的时候也开辟了一块内存)

Money类产生的对象里有一个属性值__class__,是类的地址。所以在操作one变量的时候会先找到Money类产生的对象,然后通过__class__关联到Money这个类。当我们操作one这个变量时,其实操作的是one这个变量所引用的对象。
对象属性
怎样让一个对象拥有一些属性?
方法一:直接通过对象,动态添加 语法: 对象.属性 = 值
p.__dict__ dict这个属性是python自动加的,功能是可以查看对象的所有属性和值,会返回一个字典
#定义一个类,类名首字母必须大写
class Person:
pass
#根据类,创建一个对象
p = Person()
#给p对象增加一些属性
p.age = 18
p.height = 180
#验证是否有添加成功
print(p.age)
print(p.height)
print(p.__dict__)
#p.__dict__ __dict__这个属性是python自动加的,功能是可以查看对象的所有属性和值
方法二:通过类的初始化方法(构造方法 ) __init__方法
修改对象属性
p.pets = ["小花","小黑"] p.pets = ["小花","小黑","小黄"] #新开辟一块地址,里面是["小花","小黑","小黄"] p.pets.append("小黄") #在原地址上增加一个小黄 | p.age = 10 p.age = 18 执行第二行代码时,又开辟了一块新内存放18,然后p.age去指向18,而不是在原来的地址上修改内容 |
删除对象属性
p.age = 18
del p.age
类属性
万物皆对象,类也是一个对象。
怎样让一个类拥有属性 ?
方法一:类名.类属性 =值
class Money:
pass
Money.count = 1
print(Money.count)
print(Money.__dict__) #__dict__是系统内置的属性,功能是可以查看对象的所有属性和值(类也是对象)
方法二:直接在class Money:里面添加(更常用)
class Money: # 类属性
age = 18
count = 1
num = 666
print(Money.age)
print(Money.count)
print(Money.num)
print(Money.__dict__)
怎样查询一个类的属性?
方法一:通过类名.类属性Money.age这种方式来查询
方法二:用类实例化出来的对象也可以查询类的属性,对象.类属性
class Money:
age = 18
count = 1
num = 666
one = Money()
print(one.age) #用Money实例化出来的one对象也可以查询Money类的属性
print(one.count)
print(one.num)
为什么可以通过对象访问到类属性 ?
答 :和Python对象的属性查找机制有关。优先到对象自身去查找属性,找到则结束。如果没有找到,则根据__class__找到对象对应的类,然后到这个类里面查找。

内存关系
怎样修改一个类的属性
方法一:通过类名来修改
class Money:
age = 18
count = 1
num = 666
Money.age = 22
方法二:不能通过对象来修改类的属性 (不能!)
one.age = 40 这样是不能修改Money.age的,和查询不一样,查询是可以这样来查询到Money.age的。因为one.age = 40 相当于直接给one这个对象增加了一个age属性,值是40。
怎样删除一个类的属性?
通过类名删除,del 类名.属性
不能通过对象来删除!
属性的内存存储
通过one访问属性,其实访问的是__dict__字典里的值。一般情况下,属性存储在__dict__ 的字典当中,
有些内置对象没有这个__dict__属性。
类的__dict__是只读的,不支持修改和赋值(可以通过setattr方法修改)。对象的__dict__是支持修改和赋值的。

class Money:
age = 18
count = 1
num = 666
one = Money()
one.__dict__ = {"name":"Sz","age": 20}
print(one.name) #输出是Sz
类属性被各个对象共享
类实例化了多个对象,这些对象都可以访问类属性,那么类属性只要一改,那所有对象访问的时候也都会跟着改变。
限制对象属性的添加__slots__
用了__slots__之后,类实例化出来的对象就不可以随便添加属性了,只能添加__slots__规定的属性。
class Person:
__slots__ = ['age','height']
p1 = Person()
p1.age = 18
p1.height = 180
p2 = Person()
p2.age = 18
p2.height = 180
方法
方法是在描述一个目标的行为动作,调用时必须是 目标.方法 目标可以是对象,也可以是类。

class Person:
def shilifangfa(self): #self表示被调用时会接收一个实例本身,
#它也只是个形参,名字可以随便取的;其他还有参数的话写在后面就行了
print("这是一个实例方法")
@classmethod
def leifangfa(cls):
print("这是一个类方法")
@staticmethod
def jingtaifangfa():
print("这是一个静态方法")
p = Person()
p.shilifangfa() #此时实例p传给了self
p.leifangfa() #实例也可以调用类方法,只是传参数的时候会把实例对应的类传给第一个参数
Person.leifangfa() #类 调用类方法
Person.jingtaifangfa()
p.jingtaifangfa()
方法的存储问题
实例方法、类方法、静态方法都存储在类的__dict__字典里面。万物皆可对象,函数也是个对象,也可以被当成字典的value。
实例方法
标准调用法:使用实例调用实例方法,解释器会自动把调用对象本身传递给第一个参数,也就是self。除了self,其他参数加在后面就行。
class Person:
def eat(self,food):
print("早饭吃"+food)
p =Person()
p.eat('包子') #self参数不用管,会自动传进去的
#输出 早饭吃包子
其他调用(不常用):教程里讲的很清楚,有助于理解。本质就是找到函数的本身来调用,而不是以方法来调用。
类方法
类可以调用类方法;实例也可以调用类方法,只是传参数的时候会把这个实例对应的类自动传给第一个参数。
装饰器的作用:在保证原本函数不改变的前提下,直接给这个函教增加一些功能。
静态方法
类和实例都可以调用,解释器不会自动往里面传第一个参数。
不同类型的方法访问不同类型的属性
实例方法既可以访问实例属性,也可以访问类属性。因为实例本来就可以查询对应的类属性,但是类查询不了它的实例的属性。self会被传入实例,所以就是实例在访问属性。
class Person:
age = 18
def shilifangfa(self):
print(self.age)
print(self.height)
p =Person()
p.height = 188
p.shilifangfa()
元类(创建类对象的类)
万物皆可对象。
10,'abc'这些也都是实例化出来的对象,只不过它们对应的类是int和str。所以说像我们自己定义的类比如Person,它的级别和int、str其实是一样的。

int、str、Person这些类也是对象,也可以通过__class__找到它们对应的类,也就是元类type。
还可以通过type元类来创建类,比较高级的用法 教程
__init__方法
主要作用:当我们创建好一个实例对象之后,会自动的调用这个方法,来初始化这个对象,就不需要自己手动去添加一些实例属性了。
class Person:
def __init__(self):
self.age = 18 # 这样每次实例化一个对象之后都会自动调用这个实例方法,
# 然后创建一个实例属性age = 18,就不需要次次都自己手动添加了
p1 = Person()
P2 = Person()
p3 = Person()
super( ).__init__( )
super( )用来调用父类(基类)的方法,__init__( )是类的构造方法;super( ).__init__( ) 就是调用父类的init方法, 同样可以使用super( )去调用父类的其他方法。 super().__init__()_ 讲的很易懂
super().__init__() 或者 super(B,self).__init__()
分别理解super()和 __ init __()
super()

__ init __()

super(). __ init __()
如果子类B和父类A,都写了init方法,那么A的init方法就会被B覆盖。想调用A的init方法需要用super去调用。

有人可能会误解“覆盖”的意思,认为“覆盖”了就是没有,为什么还能通过super调用?
覆盖了并不是没有了,A的方法终都还在,但需要在B内部用super调用。
__setitem__,__getitem__,__delitem__方法
是一种索引方法,把对象当成像列表或者字典一样来索引,例如p[1]=666, p['name']="ysy"。对应中括号
class Person:
def __setitem__(self, key, value):
print("setitem",key,value)
def __getitem__(self, item):
print("getitem",item)
def __delitem__(self, key):
print("delitem",key)
p = Person()
p[1] = 255
p["name"] = 'ysy'
输出:
setitem 1 255
setitem name ysy
p[1] = 255,p["name"] = 'ysy' 当我们这么写语句的时候,它会自动调用__setitem__方法,[ ]里的是key,等于号后面的是value。是一种自动触发的方法。触发之后具体要实现什么就可以写在def的函数里了。
class Person:
def __setitem__(self, key, value):
print("setitem",key,value)
def __getitem__(self, item):
print("getitem",item)
def __delitem__(self, key):
print("delitem",key)
p = Person()
a = p['name']
输出:
setitem 1 255
setitem name ysy
getitem name
只要尝试去通过列表或者字典的形式去索引,就会自动触发__getitem__方法。
综合运用:
class Person:
def __init__(self):
self.cache = {}
def __setitem__(self, key, value):
print("__setitem__被调用了")
self.cache[key] = value
def __getitem__(self, item):
print("__getitem__被调用了")
return self.cache[item]
def __delitem__(self, key):
print("__delitem__被调用了")
del self.cache[key]
p = Person()
p[1] = 255
p["name"] = 'ysy'
print(p['name'])
del p[1]
输出:
__setitem__被调用了
__setitem__被调用了
__getitem__被调用了
ysy
__delitem__被调用了
__len__方法
class UseLen(object):
def __init__(self, age):
self.age = age
self.li = ['a', 'v', 's']
def __len__(self):
return len(self.li)
U = UseLen(12)
print(len(U))
__call__方法
可以让实例像函数一样调用,比如p是个实例对象,本来p( )这么写是不行的,更别说( )还有参数了。但现在有了__call__方法,就可以这么做,一旦调用,自动触发__call__方法。对应圆括号。
class Person:
def __call__(self, *args, **kwargs):
print("哈哈", args, kwargs)
p = Person()
p(1, 2, 3, name = "ysy", a = 1)
输出:哈哈 (1, 2, 3) {'name': 'ysy', 'a': 1}
class Person:
def __call__(self, name):
print("call", name)
def hello(self, name):
print("hello", name)
p = Person()
p("zhangsan") # 其实等价于p.__call__("zhangsan")
p.hello("lisi")
staticmethod静态方法的用法
在开发的时候, 可以使用类对方法进行封装,如果某一个方法需要访问到对象的实例属性,可以把这个方法封装成一个实例方法。如果某一个方法不需要访问对象的实例属性,但是需要访问到类的类属性,这个时候就可以考虑把这个方法封装成一个类方法。一个实例方法, 一个类方法,这是两种方法类型,但是在开发中还有一种情况,如果要封装的某一个方法,既不需要访问到对象的实例属性,也不需要访问类的类属性,这个时候就可以考虑把这个方法封装成一个静态方法。 静态方法staticmethod用法
在开发中,如果类中的某个方法既不需要访问实例属性或者调用实例方法,同时也不需要访问类属性或者调用类方法,这个时候就可以把这个方法封装成静态方法。需要在def关键字上方增加一个静态方法的修饰符,@staticmethod。
静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls )。
静态方法能够通过实例对象和类对象去访问。取消了不需要的参数传递 ,有利于减少不必要的内存占存和性能消耗。
class Dog(object):
@staticmethod
def info_print():
print('这是⼀个狗类,⽤于创建狗实例....')
wangcai = Dog()
# 静态⽅法既可以使⽤对象访问⼜可以使⽤类访问
wangcai.info_print()
Dog.info_print()
class Static(object):
@staticmethod
def test_static():
print('I am staticmethod')
def test_def(self):
print('I am not staticmethod')
# 调用静态方法
Static.test_static()
# 实例化调用静态方法
obj = Static()
obj.test_static()
这套教程我看到这里就没再往下看了。标记点
私有化属性
公有属性:

全部可以访问
私有属性_y

只加一个下划线的私有属性,除了最后一个在其他python文件中用from module import *这种形式导入并且没有用__all__指明对应变量外,其他情况都可以被调用,只不过有可能警告,但是还是能调用。
如果用__all__指明对应变量,那就可以被其他模块用from所调用。 __all__ = [ "_y"]
私有属性__z

在跨模块访问时,__z和_z的效果一样。
不管是_y还是__y这种私有属性,都必须写在类的内部才有用,写在外面(包括写在实例里)都是没用的(不能被实例对象调用)。因为写在类内部,解释器会自动改名成_类_y和_类__y,假如你在实例中这么写p1.__age = -1,其实根本没有修改对应的私有属性__age,因为人家已经被改名成了_Person__age,你这么写只会新增一条__age实例属性。
所以想访问或者修改__age私有属性,只能在类里面写方法来访问或者修改。
继承
class Animal:
pass
class Dog(Animal):
pass