类的基础知识
类的基础知识
在python里呀,面向对象编程其实就是将某些物体抽象出来,基本上都是抽象出 特征和行为 ,然后将其封装在一个数据结构之中(函数或者类),有人说只有用到 class 的编程才是面向对象编程,其实这是错误的,只要是以面向对象方式设计的编程都可以叫面向对象编程,不一定得用到 class ,记住,用面向对象语言编程和以面向对象的方式编程是完全不一样的两件事
一下是面向对象方式设计的编程
def dog(name,sex,m_type): def jiao(dg): print('%s正在叫!' % dg['name']) return None def chi_shi(dg): print('%s正在吃柿' % dg['name']) return None def init(name,sex,m_type): res = { 'name':name, 'sex':sex, 'type':m_type, 'jiao':jiao, 'chishi':chi_shi } return res return init(name,sex,m_type) d1 = dog('alex','female','哈士奇') d1['jiao'](d1) d1['chishi'](d1)
//其实这也是面向对象编程,只不过没有用类数据结构而是用函数数据结构
而用类来实现的面向对象编程如下:
class Dog: def __init__(self,name,sex,m_type): self.n = name self.s = sex self.m=m_type def jiao(self): print('%s 正在叫') return None def chi_shi(self): print('%s 正在吃柿') return None Dog('alex','female','哈士奇').jiao()//已经实例化,所以调用方法jiao(self)时不需要传参数,python会自动传入你这个已经实例化的对象 Dog('alex','female','哈士奇').chi_shi() #Dog.jiao() //这个没有实例化而是直接用类来调用方法,所以调用方法jiao(self)时无法传入实例化好了的对象,所以这个参数要自己手动输入 结果 %s 正在叫 %s 正在吃柿
类的一些内置方法 ---- 有一些是只可以直接通过类来调用,实例化之后就不可以了,反正都是没啥用的,大概了解一下就ok
class Dog: def __init__(self,name,sex,m_type): self.n = name self.s = sex self.m=m_type def jiao(self): print('%s 正在叫') return None def chi_shi(self): print('%s 正在吃柿') return None print(Dog.__dict__)//将类的所有属性全部放进一个字典里然后返回 print(Dog.__dir__) print(Dog.__doc__)//返回类的说明,就是在类的开头 '' 里的内容,可是这里没有 print(Dog.__name__)//类的名字 print(Dog.__bases__)//将类的所有祖先放进字典里然后返回 print(Dog.__module__)//返回类在哪个模块 print(Dog.__class__) 结果 {'__module__': '__main__', '__init__': <function Dog.__init__ at 0x000002C95EB059D8>, 'jiao': <function Dog.jiao at 0x000002C95EB05A60>, 'chi_shi': <function Dog.chi_shi at 0x000002C95EB05AE8>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None} <method '__dir__' of 'object' objects> None Dog (<class 'object'>,) __main__ <class 'type'>
#要说有点用的估计就 __dict__了,这个要认真了解一下
class Dog: n = 'xxx' s = 'sss' m = 'bbb' def jiao(self): print('%s 正在叫') return None def chi_shi(self): print('%s 正在吃柿') return None print(Dog.__dict__) print(Dog.__dict__['n']) Dog.__dict__['jiao'](1) print(Dog.n)//这样的调用只不过是python帮你进行的包装,实际上python真正执行的还是上面的那个,通过类的 __dict__ 去查找类Dog的属性字典,然后通过属性字典来调用
Dog.jiao(1)//和上面的一样,因为是通过类来调用的,也就是没有具体的实例化,所以python无法自动传对象,所以要自己手动添加对象
结果
{'__module__': '__main__', 'n': 'xxx', 's': 'sss', 'm': 'bbb', 'jiao': <function Dog.jiao at 0x000002222E6D6730>,
'chi_shi': <function Dog.chi_shi at 0x000002222F7A59D8>, '__dict__': <attribute '__dict__' of 'Dog' objects>,
'__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}
xxx
%s 正在叫
xxx
%s 正在叫
None
类属性(包括数据属性和函数属性--->又叫伪静态属性---->可以增删改查)和对象属性的区别(仅有数据属性--->也可以进行增删改查)
这里有必要解释一下什么叫伪静态属性,因为这些个不是python中的静态属性,是相当于c++里的静态属性,而在python又没有对这类仅属于类的属性起名字,所以我就在这里起了个伪静态属性的名字
class Dog: mmd = 'mmd' //类的数据属性 又叫伪静态属性 hhh = 'hhh' def __init__(self): self.mz = 'sss' //对象属性 self.xb = 'sss' self.nj = 'fh' def jiao(self): //类的函数属性 print('%s 正在叫') return None def chi_shi(self): print('%s 正在吃柿') return None d1 = Dog() print(Dog.__dict__) print(d1.__dict__) print(d1.mz)//先在对象的属性字典里找,找到了,然后返回 print(d1.mmd) //先在对象的属性字典里找,找不到,然后去类的属性字典里找,找得到,然后返回 # print(d1.lalala) //先在对象的属性字典里找,找不到,然后去类的属性字典里找,找不到,会报错
结果
{'__module__': '__main__', 'mmd': 'mmd', 'hhh': 'hhh', '__init__': <function Dog.__init__ at 0x00000159C5D86730>,
'jiao': <function Dog.jiao at 0x00000159C6E559D8>, 'chi_shi': <function Dog.chi_shi at 0x00000159C6E55A60>, '__dict__': <attribute '__dict__' of 'Dog' objects>,
'__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None} //类属性
{'mz': 'sss', 'xb': 'sss', 'nj': 'fh'} /对象属性
sss
mmd
类得数据属性得增删改查
----------------------增---------------------------------
class Chinese: country = 'China' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat_food(self,food): print('%s正在快乐的吃%s' %(self.name,food)) def play_baskball(self,ball): print('%s正在愉快的打%s' %(self.name,ball)) p1 = Chinese('djh',18,'male') print(p1.__dict__) p1.dang = '天地会' print(p1.__dict__)
结果
{'name': 'djh', 'age': 18, 'sex': 'male'}
{'name': 'djh', 'age': 18, 'sex': 'male', 'dang': '天地会'}
自己看,是不是已经加上了添加得属性 其实添加属性和字典一样,直接添加就ojbk
-------------------------------改---------------------------------------
class Chinese: country = 'China' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat_food(self,food): print('%s正在快乐的吃%s' %(self.name,food)) def play_baskball(self,ball): print('%s正在愉快的打%s' %(self.name,ball)) p1 = Chinese('djh',18,'male') print(p1.country) Chinese.country = 'CHINA' //因为你修改得是类得属性,所以前缀用类名会更好 # p1.country = 'CHINA' //当然这样也是可以的,只是你修改的是类的属性却用对象做前缀不是很好,或者是不够专业、规范,千万不要这么做 print(p1.country)
结果
China
CHINA
看到没,结果是不是改了,修改也是和字典一样,直接改就ok
---------------------删--------------------------------
# 直接用 del 语句就欧克啦,比如 # del Chinese.country # 这样就删除了这个类属性了
---------------------查-----------------------------
# 查不就是直接调用吗,傻了咩你
类的函数属性的增删改查
--------------------------增-----------------------------------
class Chinese: country = 'China' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat_food(self,food): print('%s正在快乐的吃%s' %(self.name,food)) def play_baskball(self,ball): print('%s正在愉快的打%s' %(self.name,ball)) p1 = Chinese('djh',18,'male') print(Chinese.__dict__) def have_food(self,food): //为啥书写这个函数的参数要这种格式呢,因为你写这个函数的目的就是为了添加进类的函数属性里的,所以写的格式就按照在类里写函数时写参数的格式来写,究其根本的话就是这么
//一回事,因为当你把这个新的函数加入到类里面后,通过对象来调用这个方法时,python会自动将该对象传给self变量(在类里面的函数self变量是内置的有意义的关键字),所以
//你必须按照这个格式来写 print('%s正在开开心心的大口大口地吃%s' % (self.name,food)) Chinese.food = have_food print(Chinese.__dict__) p1.food('大米')
//有些小朋友会困惑呀,我这个变量明明是添加这个方法之前定义的,为啥我这里又可以通过对象来访问这个新添加的变量呢,python的底层是这样运作的,通过对象来调用这个新方法时,它会先去对象的属性字典里找
这个新方法,找不到,然后再去类的字典属性里找,因为已经添加了,添加之后是可以被找的,所以最后就可以通过对象来调用这个新的方法咯
结果
{'__module__': '__main__', 'country': 'China', '__init__': <function Chinese.__init__ at 0x000002CBD77C6730>,
'eat_food': <function Chinese.eat_food at 0x000002CBD88949D8>, 'play_baskball': <function Chinese.play_baskball at 0x000002CBD8894A60>,
'__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None}
{'__module__': '__main__', 'country': 'China', '__init__': <function Chinese.__init__ at 0x000002CBD77C6730>,
'eat_food': <function Chinese.eat_food at 0x000002CBD88949D8>, 'play_baskball': <function Chinese.play_baskball at 0x000002CBD8894A60>,
'__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None,
'food': <function have_food at 0x000002CBD5962EA0>}
djh正在开开心心的大口大口地吃大米
//自己看咯,是不是已经添加了,并且也可以调用,也是和字典一样,直接添加就ok,相当于添加了一个键,并且该键值的值是某个函数的函数名(函数的内存地址)
--------------------------改---------------------------------
class Chinese: country = 'China' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat_food(self,food): print('%s正在快乐的吃%s' %(self.name,food)) def play_baskball(self,ball): print('%s正在愉快的打%s' %(self.name,ball)) p1 = Chinese('djh',18,'male') p1.eat_food('大米') def have_food(self,food)://这里的参数要这么写的原因和上面一般无二 print('%s正在开开心心的大口大口地吃%s' % (self.name,food)) Chinese.eat_food = have_food //这里注意要函数名赋给函数名,因为真正赋的是赋函数的内存地址,类里的函数修改的也是函数地址,所以当再次调用这个函数时,这个函数就发生改变咯 p1.eat_food('大米')
结果
djh正在快乐的吃大米
djh正在开开心心的大口大口地吃大米
//自己看,是不是已经改变了,和字典修改一样啦
---------------------删-------------------------------
#和数据属性的删一样,直接用 del 语句便可 # del Chinese.eat_food 这样就删了这个函数了,注意,写的是函数名
-------------------查----------------------------
#妈滴,查不就是直接调用咯,傻的咩你
对象属性的数据属性的增删改查
#本质上和类的数据属性的增删改查一模一样,只不过将类名改成变量名就ok #举个例子 class Chinese: country = 'China' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat_food(self,food): print('%s正在快乐的吃%s' %(self.name,food)) def play_baskball(self,ball): print('%s正在愉快的打%s' %(self.name,ball)) p1 = Chinese('djh',18,'male') print(p1.__dict__) p1.gfriend = 'hhh' print(p1.__dict__) #p1.__dict__['gfriend'] = 'hhh' 这样来添加也是可以的,就是字典的添加属性的方 #print(p1.__dict__) 法,不过不要这么干就对了,不要直接对属性字典 # 进行操作,会有危险 结果 {'name': 'djh', 'age': 18, 'sex': 'male'} {'name': 'djh', 'age': 18, 'sex': 'male', 'gfriend': 'hhh'} //自己看咯,是不是已经添加了
对象属性的 “函数属性” --- 这里要详细的看一下
class Chinese: country = 'China' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat_food(self,food): print('%s正在快乐的吃%s' %(self.name,food)) def play_baskball(self,ball): print('%s正在愉快的打%s' %(self.name,ball)) p1 = Chinese('djh',18,'male') print(p1.__dict__) def display_name(self): print(self.name) p1.display_name = display_name p1.display_name(p1) //这里必须要自己传入一个对象,因为它不是类的函数而是对象的函数,所以python是不会自动帮你把该对象传给这个函数的,所以需要自己手动添加 #p1.disaplay_name() //如上面所说的,这样写会报错 print(p1.__dict__)
结果
{'name': 'djh', 'age': 18, 'sex': 'male'}
djh
{'name': 'djh', 'age': 18, 'sex': 'male', 'display_name': <function display_name at 0x000002167B742EA0>}
写到这里,有些人就会开始diss我,说这他妈不就是有了函数属性吗,你前面讲一堆特意强调没有是怎么回事呀,这里我解释一下,虽然语法上是没问题,但这里就有一个有没有必要这样写的问题,类是什么,类就是一类
事物的抽象呀,那这一类事物有些啥行为(函数)不都已经写到类里面了吗,为啥还要写在对象里面,比如说人,人有什么行为都已经抽象出来写在了人这个类的函数属性里面了,难不成每个人还有不一样的行为(比如
吃饭,每个人都吃吧,睡觉,拉屎)都是每个人共有的行为,不存在说哪个人有这个行为特征,另一个人就没有,难不成你有眼睛我就没了?所以存在这个语法,但不代表会去用,所以这就是对象中有只有数据属性,比如
大家都有眼睛,你的眼睛是丹凤眼,我的是杏眼,综上,你说对象有函数属性也可以,没有也可以!
对象调用的数据属性和类内函数的变量对于全局变量的区别
class test: t1 = '类数据属性' def __init__(self): self.t2 = '数据属性' def _test(self): print(x) x = 100 t = test() print(t.t2) //先在对象的属性字典里找,找得到返回 print(t.t1) //先在对象的属性字典里找,找不到,再到类的属性字典里找,找得到,返回 # print(t.x)//先在对象的属性字典里找,找不到,再到类的属性字典里找,找不到,报错,注意,只要是这种调用对象的属性的操作,都是先在自己的对象属性里找,找不到再到类的字典属性里找,还是找不到则报错
//它不会去找全局的变量,为啥呢,因为你这样加个对象前缀然后调用属性的方式是在调用对象的属性,所以它最多只会找到类属性那一层,如果连全局变量那一层都去找,那还叫类吗?,但如果是赋值
// t.x = 1 这样的话就是在对象属性里加个 x 数据属性,值为1,不会去改全局的x 因为它是通过对象来调用的,也是就是这个变量只是属性而已呀,不可能改得了全局变量的x t._test() //这个函数里面有个变量x,因为是变量,只是个变量,不是类或者对象的属性,所以它会在类内的函数那一层找,看一下有没有这个变量,没有的话会直接到上一层去找,不过就是不会去找类的那一层,
//因为类那一层的变量不只是普通的变量,还是类的属性!!(在这里,它的上一层就是主程序那一层,所以找全局变量,找得到,所以用!)
结果
数据属性
类数据属性
100
这里自己注意区分变量和属性,以及查找变量或者属性的过程
类的数据属性如果有个列表
class test: t1 = '类数据属性' t = [1,2,3] def __init__(self): self.t2 = '数据属性' ts = test() print(ts.__dict__) ts.t=['a''b'] print(ts.__dict__) print(test.t)
结果
{'t2': '数据属性'}
{'t2': '数据属性', 't': ['ab']}
[1, 2, 3]
这里也可以看出是没有对类的数据属性的列表进行修改的,而是在对象的数据属性里添加了一个列表
class test: t1 = '类数据属性' t = [1,2,3] def __init__(self): self.t2 = '数据属性' ts = test() print(ts.__dict__) ts.t.extend(['a','b']) print(ts.__dict__) print(test.t)
结果
{'t2': '数据属性'}
{'t2': '数据属性'}
[1, 2, 3, 'a', 'b']
这里这append 或者 extend 就会对类的列表数据属性进行修改 因为你是append嘛,意思就是添加元素的意思,所以找的肯定是已经存在列表的那种,对象属性里没有,类属性里有已经存在的,所以改的肯定是类的
那个呀