零基础学习 Python 之类的实例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013486414/article/details/84872736

写在之前

昨天写了类属性,作为不分家的小伙伴,今天当然是来说说 “实例”。我在之前的文章中说过,类是对象的定义,实例才是真实的东西。比如 “人” 是一个类,但是 “人” 终究不是具体的某个会喘气的,只有 “rocky” 才是具体的东西,但他是具有 “人” 这个类所定义的属性和方法。“rocky” 就是 “人” 这个类的实例。

创建实例

创建实例并不是很难的事情,只需要调用类就可以实现:

>>> class man():
...     sex = '男'
...
>>> rocky = man()
>>> rocky
<__main__.man instance at 0x00000000004F3688>

如果不是用很严格的说法的话,上面的这个例子就是创建了一个实例 rocky。这里有一点需要我们注意的是,调用类的方法和调用类的函数类似,如果仅仅是写 man() 的话,则是创建了一个实例:

>>> man()
<__main__.man instance at 0x0000000002577D88>

而 rocky = man() 本质上是将变量 rocky 与实例对象 man() 建立引用关系,这种关系就如同我们在刚开始的时候学的赋值语句 x = 1 是同样的效果。

那么对于一个实例来说这个建立的过程是怎么进行的呢?我们继续来看:

class Person:
  """
  具有通常类的结构的 Person 类
  """
  def __init__(self,name):
      self.name = name

  def get_name(self):
      return self.name

  def get_sex(self,sex):
      per_sex = {}
      per_sex[self.name] = sex
      return per_sex

实例我们用 boy = Person(‘rocky’) ,当然了,在这里你可以创建很多个实例,还记得那句话么:类是实例的工厂。

当我们创建完实例,接下来就是调用类,当类被调用以后,先是创建一个实例对象,然后检查是否有 init(),如果有的话就调用这个方法,并且将实例对象作为第一个参数 self 传进去,如果没有的话,就只是返回实例对象。

我之前也说过,init() 作为一个方法是比较特殊的,在它里面,一般是规定一些属性或者做一些初始化,让类具有一些基本的属性,但是它没有 return 语句,这是 init() 区别于一般方法的地方:

>>> class fun:
...    def __init__(self):
...            print('this is init()')
...            return 1
...
>>> f = fun()
this is init()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: __init__() should return None

上面的运行结果出现了异常,并且明确说明了 “init() should return None”,所以不能有 return,如果非要带上的话,只能是 return None,索性就不要写了。

由此可知对于 init() ,除了第一个参数必须是 self,还要求不能有 return 语句,其他方面和普通函数就没有什么区别了。比如参数和里面的属性,你就可以像下面这样来做:

>>> class Person:
...     def __init__(self,name,sex = '男',age = 10):
...             self.name = name
...             self.sex = sex
...             self.age = age
...

实例我们创建好了以后,我们接下来就要研究实例的内容,首先来看的是实例属性。

实例属性

和类属性相似,实例所具有的属性叫做 “实例属性”:

>>> class A:
...     x = 1
...
>>> f = A()

类已经有了一个属性 A.x = 1,那么由类所创建的实例也应当具有这个属性:

>>> f.x
1

除了 f.x 这个属性以外,实例也具有其它的属性和方法,我们依然用 dir 方法来看:

>>> dir(f)
['__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__', 'x']

实例属性和类属性最主要的不同是在于,实例属性可以随意的更改:

>>> f.x += 10
>>> f.x
11

上面就是把实例属性修改了,但是类属性并没有因为实例属性的修改而发生变化,正如我们在前几天的文章中所说的那样,类属性是与类捆绑的,不受实例的影响。

>>> A.x
1

上述的结果正好印证了这一点 – 类属性不因实例属性改变而改变。既然如此,那么 f.x += 10 又改变了什么呢?

其实就是实例 f 又重新建立了一个新的属性,但是这个新的属性和原先旧的属性是一个名字,都是 f.x,所以相当于原先旧的属性被 “掩盖”了,只能访问到新的属性,所以值是 11。

>>> f.x
11
>>> del f.x
>>> f.x
1

由上面的例子可以看出,既然新的 f.x “掩盖”了旧的 f.x,只要把新的 f.x 删除,旧的 f.x 就可以显现出来。

实例的改变不会影响到类,但是类属性可以影响到实例属性,因为实例就是通过调用类来建立的:

>>> A.x += 10
>>> A.x
11
>>> f.x
11

如果是同一个属性 x,那么实例属性跟着类属性的改变而改变,当然,这个是针对于像字符串这种不可变对象而言的,对于类中如果引用的是可变对象的数据,则情形会有所不同,因为可变对象的数据是可以原地进行修改的:

>>> class B:
...     y = [1,2,3,4]
...
>>> B.y #类属性
[1, 2, 3, 4]
>>> f = B()
>>> f.y #实例属性
[1, 2, 3, 4]
>>> B.y.append('5')
>>> B.y
[1, 2, 3, 4, '5']
>>> f.y
[1, 2, 3, 4, '5']
>>> f.y.append('66')
>>> B.y
[1, 2, 3, 4, '5', '66']
>>> f.y
[1, 2, 3, 4, '5', '66']

通过上面的代码我们可以看出,当类中的变量引用的是可变对象的时候,类属性和实例属性都能够直接修改这个对象,从而增加另一方的值。

还有一点我们已经知道了增加一个类属性,相应的实例属性也会增加,但是反过来就不成立了:

>>> B.x = 'aa'
>>> f.x
'aa'
>>> f.z = 'abcd'
>>> f.z
'abcd'
>>> B.z
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: class B has no attribute 'z'

可以看出类并没有接纳实例实例增加的属性。

写在之后

更多内容,欢迎关注公众号「Python空间」,期待和你的交流。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u013486414/article/details/84872736
今日推荐