《零基础入门学习Python》(39)类和对象:拾遗(组合)

知识点

  • 在前面有乌龟类和鱼类,现在要求定义一个类,叫水池,水池里要有乌龟和鱼,但是仔细想想我们如果用继承的话就把鱼和乌龟当成一个物种,这样就显得太乱了。那要怎么才能将它们组合成一个和谐的类喃,下面我们就要介绍组合

组合其实很简单,下面我们直接上代码:

class Turtle:
    def __init__(self,x):
        self.num = x


class Fish:
    def __init__(self,x):
        self.num = x

class Pool:
    def __init__(self,x,y):
        self.turtle = Turtle(x)#把需要的类直接实例化放进去,就是组合了(将没有直接关联的类直接组合直接在一起)
        self.fish = Fish(y)

    def print_num(self):
        print('乌龟%d,小鱼%d'%(self.turtle.num,self.fish.num))
=======================================================================================      
>>> pool = Pool(1,10)
>>> pool.print_num()
乌龟1,小鱼10
  • 类、类对象、类事例对象

>>> class C:
	count = 0

	
>>> a=C()
>>> b=C()
>>> c=C()
>>> a.count
0
>>> b.count
0
>>> c.count += 10#相当于生成了以count覆盖了类对象的count,所以造成了下面c.count不会变
>>> c.count
10
>>> a.count
0
>>> b.count
0
>>> C.count
0
>>> C.count += 100
>>> a.count
100
>>> b.count
100
>>> c.count
10

实例对象的改变不会影响类对象或者其他实例对象。

  • 当属性和方法的名称相同

当我们建立一个与方法同名的属性的时候,那个同名的方法却不能再次使用,属性就会覆盖方法

>>> class C:
	def x(self):
		print("X-man!")

		
>>> c=C()
>>> c.x()
X-man!
>>> c.x=1#Pyhton中的变量不用定义,所以这样相当于建立一个与方法同名的x
>>> c.x
1
>>> c.x()
Traceback (most recent call last):
  File "<pyshell#126>", line 1, in <module>
    c.x()
TypeError: 'int' object is not callable

那么为避免名字上的冲突,大家应该遵循一些规则:

  • 不要试图在一个类里面定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展
  • 用不同的词性命,如属性名用名词,方法名用动词

到底什么是绑定?

Python严格要求方法需要有事例才能被调用,这种限制其实就是Python所谓的绑定概念

那部分人会这样想,用类对象直接调用也可以调用类中的方法

>>> class BB:
	def printBB():#这里少了一个self
		print('no zuo no die')

		
>>> BB.printBB()
no zuo no die

但是这样我们实例化一个变量去调用这个类的方法,我们是调用不到的

>>> bb = BB()
>>> bb.printBB()
Traceback (most recent call last):
  File "<pyshell#133>", line 1, in <module>
    bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given

那我们再讲一个例子

>>> class cc:
	def setXY(self,x,y):
		self.x = x
		self.y = y
	def printXY(self):
		print(self.x,self.y)

		
>>> dd = cc()
>>> dd.__dict__#查看他的属性
{}
>>> cc.__dict__#查看类对象的属性
mappingproxy({'__module__': '__main__', 'setXY': <function cc.setXY at 0x03FCAE40>, 'printXY': <function cc.printXY at 0x03FCAE88>, '__dict__': <attribute '__dict__' of 'cc' objects>, '__weakref__': <attribute '__weakref__' of 'cc' objects>, '__doc__': None})

接下来我们来调用dd.setXY()

>>> dd.setXY(4,5)
>>> dd.__dict__
{'x': 4, 'y': 5}

现在发现dd的属性发生了改变,你也会发现这个属性只属于dd

>>> cc.__dict__
mappingproxy({'__module__': '__main__', 'setXY': <function cc.setXY at 0x03FCAE40>, 'printXY': <function cc.printXY at 0x03FCAE88>, '__dict__': <attribute '__dict__' of 'cc' objects>, '__weakref__': <attribute '__weakref__' of 'cc' objects>, '__doc__': None})

为什么会是这样喃,这跟绑定完全分不开。当dd调用setXY的时候,他是传递的dd.setXY(dd,4,5),所以你在赋值的时候self就是dd,相当于dd.x=x(4),dd.y=y(5),这个数据存放的位置是实例对象中一个位置,所以这个属性只属于实例对象。

现在我们将类对象删除

>>> del cc
>>> ee = cc()
Traceback (most recent call last):
  File "<pyshell#155>", line 1, in <module>
    ee = cc()
NameError: name 'cc' is not defined
>>> dd.setXY(4,5)
>>> dd
<__main__.cc object at 0x03FCF2D0>
>>> dd.printXY()
4 5

我们将类对象删除之后,dd仍然可以使用原cc中的方法,这是因为类对象中定义的属性和方法是静态的,所以尽管类对象被删除之后,他们依然存在。

知识点

0.什么是组合(组成)?

答:Python基础机制很有用,但容易吧代码复杂化以及依赖隐含继承。因此,经常的时候,我们可以使用组合来代替。在Python李组合其实很简单,直接再类定义中吧需要的类放进去实例化就可以了。(前面有相关的例子)

1.什么时候用组合,什么时候用继承?

答:根据实际应用场景确定。简单来说,组合用于“有一个”的场景(关联性较弱的时候),继承用于“是一个”的场景(关联性比较强)

2.类对象是在什么时候产生的?

答:当你这个类定义完的时候,类定义就变成对象,可以直接通过‘类名.属性’或者‘类名.方法名()’引用或使用相关的属性和方法。

3.如果对象的属性跟方法同名,会怎样?

答:如果对象的属性跟方法名相同,属性会覆盖方法。

4.请问以下类定义中那些是类属性,那些是实例属性?

答:num和count是类属性(静态变量),x和y是实例属性。大多数情况下,你应该考虑使用实例属性,而不是类属性(类属性通常仅用来跟踪与类相关的值)

5.请问下面的代码,bb对象为什么要调用printBB()方法失败?

答;因为Python严格要求方法需要有实例才能被调用,这种限制其实就是Python所谓绑定的概念。所以Python会自动把bb对象作为第一个参数传入,所以才会出现错误。

动动手

0.思考这一讲我学习的内容,请动手在一个类中定义一个变量,用于跟踪该类有多少个实例被创建(当实例化一个对象,这个对象变量+1,当删除一个对象,这个变量自动-1)

>>> class C:
	count = 0
	def __init__(self):
		C.count += 1

		
>>> class C:
	count = 0
	def __init__(self):
		C.count += 1
	def __del__(self):
		C.count -= 1

		
>>> a=C()
>>> b=C()
>>> c=C()
>>> C.count
3
>>> del a
>>> C.count
2

1.定义一个栈类,用于模拟一种具有后进先出特性的数据结构,至少需要有以下的方法

class Stack:
    def __init__(self,start=[]):
        self.stack = []
        for x in start:
            self.push(x)

    def isEmpty(self):
        return not self.stack

    def push(self,obj):
        self.stack.append(obj)

    def pop(self):
        if not self.stack:
            print('警告:栈为空!')
        else:
            return self.stack.pop()

    def top(self):
        if not self.stack:
            print('警告:栈为空!')
        else:
            return self.stack[-1]

    def bottom(self):
        if not self.stack:
            print('警告:栈为空!')
        else:
            return self.stack[0]
======================== RESTART: D:/python/Stack.py ========================
>>> bb = Stack('asdasdasdafadfas')
>>> bb.pop()
's'
        

 

猜你喜欢

转载自blog.csdn.net/qq_38721302/article/details/83544924
今日推荐