博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第二十七篇 类和对象相关知识
阅读量:5214 次
发布时间:2019-06-14

本文共 13158 字,大约阅读时间需要 43 分钟。

类和对象

1. 什么叫类:类是一种数据结构,就好比一个模型,该模型用来表述一类食物(食物即数据和动作的结合体),用它来生产真是的物体(实例)

2. 什么叫对象:睁开眼,你看到的一切事物都是一个个的对象,你可以把对象理解为一个具体的事物(事物即数据和动作的结合体)

(铅笔是对象,人是对象,房子是对象,狗是对象,你看到的都是类)

3.类与对象的关系:对象都是由类产生的,女娲造人,首先由一个造人的模板,这个模板就是人类,然后女娲根据类的定义来生产一个个的人

4. 什么叫实例化:由类生产对象的过程叫实例化,类实例化的结构就是一个对象,或者叫做一个实例(实例=对象)

 

实例:就是类生产的那个对象。是一个实实在在的存在。放到真实世界中,人类就是一个类,这人类是看不见,摸不着的,是人为给划分的;而人,比如,你,我,他,路人等就是一个个的实例,是真实存在,能看得见,摸得着的。

类相关的知识

  • 声明类

在Python中,声明函数和声明类很相似:

声明函数

def function(args):    '''文档字符串'''    函数体

声明类

class 类名:    '''类的文档字符串'''    类体
class Chinese:   # 声明类,类名的规范:类名的首字母要大写    '''这是一个中国人的类'''    passprint(Chinese) # 
声明类的定义示例
class Chinese:       '''这是一个中国人的类'''    pass# 实例化#实例化,对类名加括号,加括号就代表运行,运行类也有返回值,这个返回值就是一个具体的示例了p1=Chinese()print(p1)# <__main__.Chinese object at 0x00402EF0>#实例化到底干了什么?后面给你答案
类的实例化

经典类与新式类

经典类:上面的两个示例就是经典类,经典类的特点就是,类名后面直接就是冒号(Python2中)

新式类:都要在类名后面加个括号,括号里写上object

# 新式类:都要在类名后面加个括号,括号里写上object# 意思是Chinese这类继承与objectclass Chinese(object):    pass

注意,Python3中统一都是新式类,没有区别了,类名后面是否加(object),都是新式类。

  • 属性

类是用来描述一类事物的,类的对象指的是这一类事物中的一个个体。

既然是事物,那就要有属性,属性分为:

1. 数据属性:就是变量   (就是第二十五篇里讲的特征)

2. 函数属性:就是函数,在面向对象里通常称为方法  (就是第二十五篇里讲的动作)

注意:

类和对象均用点来访问自己的属性

  • 类的属性

数据属性即变量,类的定义与函数又极其类似,其实可以用函数的作用域来理解类的属性调用。

class Chinese:    '这是一个中国人的类'    # 类的数据属性    party='渣滓洞'    # 类的函数属性,就是方法    def huang_pi_fu():        print('中国人都是黄皮肤')    def cha_dui(self):        print('%s插到了前面' %self)
  • 访问类的属性(查看类属性)

要访问类的属性,你首先得知道类的属性在哪里吧?就好比你要逛亲戚,你得知道亲戚家在哪里吧,然后才能选择用什么交通工具到你亲戚家。

那要去你亲戚家,你怎么知道路呢?可以问爸妈,也可以给亲戚打电话,还可以让亲戚发定位等等。

同理,定义了类的属性,也要知道存放在哪里了?有两种方式可以查看

#第一种:dir(类名): 得到的是一个名字列表,只放了属性的名字在列表里print(dir(Chinese))# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'cha_dui', 'huang_pi_fu', 'party']# 第二种:类名.__dict__ :查出的是一个字典,key为属性名,value为属性值 __dict__: 查看类的属性字典
print(Chinese.__dict__)# {'__module__': '__main__', '__doc__': '这是一个中国人的类', 'party': '渣滓洞', 'huang_pi_fu': 
, 'cha_dui':
, '__dict__':
, '__weakref__':
}

知道了存放地点,就可以一级级查找下去,访问类的属性啦

print(Chinese.__dict__['party'])   # 渣滓洞print(Chinese.__dict__['huang_pi_fu']())  # 中国人都是黄皮肤print(Chinese.__dict__['cha_dui']('汪汪队'))  # 汪汪队插到了前面

Python提供了更简单的方法:

类名.属性名:就可以访问到属性。(本质上就是在查询属性字典)

# 访问类的数据属性,通过点来访问print(Chinese.party)    # 渣滓洞# 访问类的函数属性,通过点来访问Chinese.huang_pi_fu()    # 中国人都是黄皮肤Chinese.cha_dui('dig')   # dig插到了前面
  • 特殊的类属性

#python为类内置的特殊属性类名.__name__# 类的名字(字符串)类名.__doc__# 类的文档字符串类名.__base__# 类的第一个父类(在讲继承时会讲)类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)类名.__dict__# 类的字典属性类名.__module__# 类定义所在的模块类名.__class__# 实例对应的类(仅新式类中)类的特殊属性(了解即可)
print(Chinese.__name__)       # Chineseprint(Chinese.__doc__)        # 这是一个中国人的类print(Chinese.__base__)       # 
print(Chinese.__bases__) # (
,)print(Chinese.__dict__) # 上面已经有了print(Chinese.__module__) #__main__print(Chinese.__class__) #

对象相关的知识

对象:是由类实例化而来的。

  • 构造初始化方法及实例化
class Chinese:    '这是一个中国人的类'    party='渣滓洞'    '''    首先,在类定义当中,要有一个初始化函数来帮我们定制每一个对象的属性    其次,类class的语法结构当中,提供了内置方法,只要你把初始化函数定义为__init__()这个名字,你在用类名()来运行你的类的时候,他就会自动的找到    __init__来帮你去运行    第三,__init__()必须要有一个self参数,然后再接着写其他数据属性(变量参数)    第四, 定义数据属性时,self.mingzi = name,代表给这个self这个实例赋予了一个mignzi属性,mingzi属性就是数据属性;name就是执行__init()函数传进来的参数    这样就把名字,年龄,性别统统都封装到了self这个实例自己里面了    最后,return返回了一个self实例,但是不用显示的return,而是class自动给你return了,最后返回的结果就是一个字典。        字典里封装了什么?封装了名字,年龄,性别这些数据属性        '''   # 1. 初始化构造方法    def __init__(self,name,age,gender):        print('我是初始化函数,我开始运行了')        # self:就是实例自己        self.mingzi=name        # 相当于 p1.mingzi=name        self.nianji=age         # 相当于 p1.nianji=age        self.xingbie=gender     # 相当于 p1.xingbie = gender        print('我结束啦')# 上面已经构造好了初始化一个实例的方法,下面就来真真的生成一个实例对象# 具体的实例化的过程:# 1. 实例化的过程,本质上就是调用并运行了一次__init__(self,name,age,gender)函数,# 2. 在调用__init__的过程中,self其实就是p1,在运行过程中,会自动的将p1传给self,然后'元昊',18,'female'分别传给name,age,gender# 3. 其实就是Chinese.__init__(p1,name,age,gender) # 2. 实例化:实际就是生成了一个真实存在的对象。 p1 = Chinese('小黄',18,'female')
# 我是初始化函数,我开始运行了 # 我结束啦
# 上面初始化构造方法里面已经讲了,初始化构造返回的实例就是一个数据字典,那我们来看看到底是不是 print(p1) # <__main__.Chinese object at 0x00C39890> print(p1.__dict__) # {'mingzi': '元昊', 'nianji': 18, 'xingbie': 'female'}
  • 实例调用属性
# 上面已经实例化了一个p1,p1就是真实存在的一个人# 就可以查看p1这个人具备哪些属性?# 首先,他具有这个类所共有的属性,还可以有他自己特有的属性print(p1.mingzi)   # 小黄# p1.mingzi,作用域在__init__里,可以调用到,很正常# 那p1.dang首先在__init__作用域里没找到,就会向外一层找,就有dang这个属性啦,所以可以调用了print(p1.dang)     # 渣滓洞# 查看p1的属性print(p1.__dict__)# {'mingzi': '元昊', 'nianji': 18, 'xingbie': 'female'}# 查看类的属性print(Chinese.__dict__)# {'__module__': '__main__', '__doc__': '这是一个中国人的类', 'dang': '渣滓洞', '__init__': 
, 'sui_di_tu_tan':
, 'cha_dui':
, 'eat_food':
, '__dict__':
, '__weakref__':
}

小总结:

1. 实例是怎么产生的?

【答】实例的产生,就是执行了一个初始化方法__init__()产生的。__init__()返回的就是一个实例属性字典。实例属性字典里就是没有函数属性,并不包含函数属性

2. 函数属性是属于类的,从层级关系上也能看出来。

  • 构造函数属性
class Chinese:    '这是一个中国人的类'    dang='渣滓洞'    # 构造了初始化函数    def __init__(self,name,age,gender):        self.mingzi=name        # 相当于 p1.mingzi=name        self.nianji=age         # 相当于 p1.nianji=age        self.xingbie=gender     # 相当于 p1.xingbie = gender    # 构造函数属性    def sui_di_tu_tan(self):        print('%s 朝着墙上就是一口痰' %self.mingzi)    def cha_dui(self):        print(self)        print('%s 插到了前面' %self.mingzi)    def eat_food(self,food):        print('%s 正在吃%s' %(self.mingzi,food))
  • 实例调用函数属性
# 实例调方法的顺序# 1. 先从自己的字典里找 p1自己的字典:{'mingzi': '元昊', 'nianji': 18, 'xingbie': 'female'}# 2. 再到类的字典里面去找, 类的字典:Chinese.__dict__# 能找到就可以运行p1.sui_di_tu_tan()# 小黄 朝着墙上就是一口痰# 问题:sui_di_tu_tan(self)定义的时候有个self参数,那为什么这里运行的时候,没有传参数,也能正常运行呢?
  • 关于self的总结

1、self 就代表自己,自己就是实例化的结果p1。谁来实例化,self就是谁。

2、为什么要有self?self就是来做统一的
3、只要定义了self,一执行函数,就会自动把p1传给函数的第一个参数。
4、所以,以后只要碰到self,就要知道self就是实例本身

 

来一张图

 

 有人说,类有数据属性和函数属性,实例/对象 是由类产生的,所以实例也有数据属性和函数属性了------这是错的哇,记住啦。

因为:

实例化的过程实际就是执行__init__的过程,这个__init__函数内部只是为实例本身即self设定了一堆数据(变量),所以实例只有数据属性;它的所谓的函数属性是从类里找来的而已。

 

 还有人说,实例是类产生的,所以实例肯定能访问到类属性,然后就没有说为什么了------这也是错的哇。

因为:

1. 首先你会发现,实例化就是 类名(),然后返回的结果是一个对象,加上括号是不是跟函数运行很像,函数运行完了有返回值,很像那

2. 函数有作用域的概念,其实类也有作用域的概念,二者一样

3. 你可以吧class当做最外层的函数,是一个作用域

 

# 定义一个类,只当一个作用域用class MyData:    passx = 10y = 20MyData.x = 1MyData.y = 2print(x, y)print(MyData.x, MyData.y)print(MyData.x + MyData.y)
View Code

 

4. 实例化会自动触发__init__函数的运行,最后返回一个值即实例,我们要找的实例属性就存放在__init__函数的局部作用域里

5. 类有类的属性字典,就是类的作用域,实例有实例的属性字典,就是实例的作用域

6. 综上,一个点代表一层作用域,obj.x 先从自己的作用域找,自己找不到再去外出的类的字典中找,都找不到,就会报错

7. 在类中没有使用点的调用,代表调用全局变量。

 

所以,上面的说法犯了因果倒置的错误。不是因为实例是由类产生的,所以实例才能访问到类属性。

上面这个只是为了帮助理解,而不能真的这么说。

茅塞顿开,总结一句话就是:

类有个属性字典,实例也有个属性字典;

查的时候,实例/对象先从自己的属性字典里查,再到类的属性字典里去查

整理下上面的代码

class Chinese:    '这是一个中国人的类'    dang='渣滓洞'    def __init__(self,name,age,gender):        self.mingzi=name        # 相当于 p1.mingzi=name        self.nianji=age                 self.xingbie=gender         def sui_di_tu_tan(self):        print('%s 朝着墙上就是一口痰' %self.mingzi)    def cha_dui(self):        print(self)        print('%s 插到了前面' %self.mingzi)    def eat_food(self,food):        print('%s 正在吃%s' %(self.mingzi,food))# 实例化可以生成多个对象p1=Chinese('小黄',18,'female')# 对象调用吃的方法p1.eat_food('包子')   # 小黄 正在吃包子p2=Chinese('武sir',23,'姑娘')# 对象也可以调用吃的方法p2.eat_food('韭菜馅饼')  武sir 正在吃韭菜馅饼
  • 属性有两种:数据属性和函数属性
  • 类属性的使用----增删改查
class Chinese:    country='China'    def __init__(self,name):        self.name=name    # 函数属性的定义原则:动词_名词。 干什么事    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball)) # 下面的函数定义与类是同级的,与类没半毛钱关系。def say_word(self,word):    return "%s 说 %s" %(self.name, word)# 实例化一个实例p1=Chinese('alex')# print(p1.__dict__)  # {'name': 'alex'}
    •   查看类的属性
#查看类的数据属性:用点的方式查。 print(Chinese.country)  # China# 查看类的函数属性print(Chinese.play_ball)  # 
    •   增加类的属性
#增加类的数据属性Chinese.dang = 'Gong Chandang'print(Chinese.dang)    # Gong Chandang# 增加类的函数属性# 首先,要在类的外部写一个函数def say_word(self,word):    return "%s 说 %s" %(self.name, word)# 其次,增加函数属性,将上面的函数赋值给类的函数属性Say_LanguageChinese.Say_Language = say_wordprint(Chinese.__dict__)# {'__module__': '__main__', 'country': 'China', '__init__': 
, 'play_ball':
, '__dict__':
, '__weakref__':
, '__doc__': None, 'Say_Language':
}
    •    修改类的属性
#修改类的数据属性Chinese.country="新西兰"print(Chinese.country)  # 新西兰# 类属性被修改了,那实例可以使用吗?可以用的print(p1.country) # 新西兰# 修改类的函数属性# 首先要定义个要修改的目标函数def play_what(self,what):    return "%s 正在玩 %s" %(self.name, what)# 修改类的函数属性Chinese.play_ball = play_whatprint(Chinese.__dict__)# 调用类的函数属性print(p1.play_ball("钢琴"))   # alex 正在玩 钢琴
    •   删除类的属性
# 删除类的数据属性del Chinese.countryprint(p1.country)# AttributeError: 'Chinese' object has no attribute 'country'# 删除类的函数属性del Chinese.play_ballprint(Chinese.__dict__)# {'__module__': '__main__', 'country': 'China', '__init__': 
, '__dict__':
, '__weakref__':
, '__doc__': None}# 调用类函数属性p1.play_ball("足球")# AttributeError: 'Chinese' object has no attribute 'play_ball'# 因为,已经被删除掉了

 

  • 实例属性的使用----增删改查
    •   查看实例的属性
# 查看实例的数据属性  print(p1.name) # alex # 查看实例类属性(查看实例的函数属性,实际上是访问的类的函数属性)print(p1.play_ball) # 
> # 运行,函数属性后加()就变成运行了。
print(p1.play_ball('篮球'))
    •   增加实例的属性
# 增加实例的数据属性p1.age=18print(p1.__dict__)     # {'name': 'alex', 'age': 18}print(p1.age)          # 18#备注,无法增加实例的函数属性哦,因为函数属性是通过类增加的# 增加实例的函数属性(虽然可以增加,但是没有这么玩的,要知道可以增加,但要迅速忘记它,千万别这么用,纯属多余的)def shili_shuxing(self):    return "我是来自实例的函数属性"p1.Shi_Li_De_Shu_Xing = shili_shuxingprint(p1.__dict__)# {'name': 'alex', 'Shi_Li_De_Shu_Xing': 
}print(p1.Shi_Li_De_Shu_Xing(p1))# 我是来自实例的函数属性
    •   修改实例的属性
# 修改实例的数据属性p1.age=19print(p1.__dict__)print(p1.age)# 结果{
'name': 'alex', 'age': 19}19
    •    删除实例的属性
#删除实例的数据属性del p1.ageprint(p1.__dict__)

那,换个姿势,实例和类混合着玩会怎么样?

# 示例代码class Chinese:    country='China'    def __init__(self,name):        self.name=name    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1=Chinese('alex')print(p1.country)  # China     访问的是类的# 在p1里新增了一个countryp1.country='日本'print('类的--->',Chinese.country)   # Chinaprint('实例的',p1.country)          # 日本
示例代码1

 

# 作用域问题class Chinese:    def __init__(self,name):        self.name=name    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1=Chinese('alex')print(p1.country)# AttributeError: 'Chinese' object has no attribute 'country'# 原因, 因为类里没有country属性# 那如果把country定义到类外面那?country='中国'class Chinese:    def __init__(self,name):        self.name=name    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1=Chinese('alex')print(p1.country)# AttributeError: 'Chinese' object has no attribute 'country'# 原因:作用域只在类里面找,放到类外部照样找不到
示例代码2

 

class Chinese:    def __init__(self):     # 在实例化过程中接受输入参数        name = input("请输入用户名: ")        self.name=name    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1=Chinese()print(p1.name)# 备注:'''虽然这么做是可以的,但是千万别这么干。因为一个函数就是实现一个功能,而这么干,还实现了接受用户输入的功能。可读性差,也不利于维护'''# 可以改进成如下方式,专门写一个函数来处理接受输入和实例化的过程,代码变为:class Chinese:    def __init__(self, name):        self.name=name    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))def shi_li_hua():    name=input('>>: ')  # 接收输入    p1=Chinese(name)    # 实例化    print(p1.country)   # 调用    print(p1.name)      # 调用shi_li_hua()    # 直接调用运行
千万不要这么干

在类中没有使用点的调用,代表调用全局变量。

country='中国'class Chinese:    def __init__(self,name):        self.name=name        print('--->',country)    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1=Chinese('alex')# ---> 中国# 为什么?# 其实前面已经给了答案了。所说的在类里面找属性,是通过点这种方式才表明这个属性是需要再类里面去找的,而此时,country并没有通过点的方式,所以它就是一个普通的变量名,即使这个变量在类的外面,照样也可以使用
不通过点的方式也可以在类里使用变量
country='-------------中国-------------'class Chinese:    country='中国'    def __init__(self,name):        self.name=name        print('--->',country)    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1 = Chinese("alex")# ---> -------------中国-------------# 原因:# 遵循在类中没有使用点的调用,代表调用全局变量。
遵循在类中没有使用点的调用,代表调用全局变量。没有通过点,根本不会从类里面找的

 

class Chinese:    country='China'    def __init__(self,name):        self.name=name    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1=Chinese('alex')print(p1.country)   # Chinap1.country='Japan'   # 改的只是p1自己的国家print(Chinese.country)  # China    类的数据属性还是没有被改掉的
会改掉类的属性吗?

 

class Chinese:    country='China'    l=['a','b']    def __init__(self,name):        self.name=name    def play_ball(self,ball):        print('%s 正在打 %s' %(self.name,ball))p1=Chinese('alex')print(p1.l)    # ['a', 'b']p1.l=[1,2,3]   # 给p1新增了一个属性值,所以只会改p1自己的print(p1.l)    # [1, 2, 3]   改的仅仅是p1自己的print(Chinese.l)   # ['a', 'b']   类的属性l 是不会变的print(p1.__dict__)   # {'name': 'alex', 'l': [1, 2, 3]}# 但是,这种方式就有问题了# 首先,没有给p1新定义属性,# 其次, p1.l调的就是类的,这个l那的就是列表的引用,append操作的就是类p1.l.append('c')  print(p1.__dict__)  # {'name': 'alex', 'l': [1, 2, 3]}print(Chinese.l)  # {'name': 'alex', 'l': [1, 2, 3, 'c']}# 这其实就是通过实力引用类的属性,并直接操作了类的属性
非赋值方式通过实例修改类的属性

 

转载于:https://www.cnblogs.com/victorm/p/9310761.html

你可能感兴趣的文章
将文本文件中的\n字符串变成换行符
查看>>
如何在博客园设置自己的头像
查看>>
NIO选择器学习笔记
查看>>
Nginx配置upstream实现负载均衡1
查看>>
“ipconfig不是内部命令或外部命令”解决方法
查看>>
linux cron定时任务初级使用教程
查看>>
(C#控件)MessageBox
查看>>
Excel:写入Excel-单纯写入
查看>>
Tomcat详细用法学习(五)
查看>>
2017 icpc亚洲区域赛沈阳站
查看>>
UI基础--封装cell滑动时的动画
查看>>
2017.9.1 Java中的程序方法
查看>>
Django 框架 基础
查看>>
HDU3306 Another kind of Fibonacci 矩阵
查看>>
CSS笔记-文本缩略显示
查看>>
S7-200PLC间的PPI通信
查看>>
第三章家庭作业3.65
查看>>
javascript有哪些优秀的库,把你喜欢的都说出来吧
查看>>
Web后端 JAVA学习之路
查看>>
Arc076_E Connected?
查看>>