Python_类和对象

1.对象 = 属性(变量) + 方法(函数)

属性:对象的特征;方法:对象的行为

以lzm为例写成代码

class Lzm:
    # Python中的类名约定以大写字母开头
    # 特征的描述称为属性,在代码层面来看其实就是变量
    body = 'strong'
    face = 'handsome'
    arms = 2
    legs = 2
    mouth = 'big嘴'
    ismale = True

    # 方法实际就是函数,通过调用这些函数来完成某些工作
    def walk(self):
        print('I am walking')

    def run(self):
        print('I am running')

    def eat(self):
        print("It's delicious")

    def sleep(self):
        print('lzm must go to sleep early')

以上代码定义了对象的特征(属性)和行为(方法),但还不是一个完整的对象,将定义的这些称为类(class)。需要使用类来创建一个真正的对象,这个对象就称为这个类的一个实例(instance),也叫实例对象(instance objects)。

创建一个对象,也叫类的实例化。

>>> # 先运行上述类的代码
>>> a = Lzm()
>>> a.face
'handsome'
>>> a.legs
2
>>> a.walk()
I am walking
>>> a.sleep()
lzm must go to sleep early

2.面向对象编程

       ① self是什么:由同一个类可以生成无数对象,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,那么Python就知道需要操作哪个对象的方法了。

class Ball:
    def setName(self, name):
        self.name = name
    def kick(self):
        print('我叫%s,谁在踢我' % self.name)
        

>>> a = Ball()
>>> a.setName('lzm')
>>> b = Ball()
>>> b.setName('bnu')
>>> c = Ball()
>>> c.setName('wsm')
>>> a.kick()
我叫lzm,谁在踢我
>>> b.kick()
我叫bnu,谁在踢我
>>> c.kick()
我叫wsm,谁在踢我

'''以下代码和上述代码功能完全相同'''
class Ball:
    def setName(self, n):
        self.name = n
    def kick(self):
        print('我叫%s,谁在踢我' % self.name)

        ②魔法方法:可以给类增加魔力的特殊方法,如果对象实现了这些方法中的某一个,那么这个方法就会在特殊的情况下被Python调用,而这一切都是自动发生的。

'''__init()__方法,也称为构造方法'''

class A:
    def __init__(self, n):
        self.name = n
    def kick(self):
        print('我叫%s,谁在踢我' % self.name)

>>> a  = A('lzm')
>>> a.kick()
我叫lzm,谁在踢我

        ③公有和私有:

'''默认对象的属性和方法都是公开的,可以直接通过点操作符(.)进行访问'''
>>> class Person:
	name = 'lzm'
	
>>> p = Person()
>>> p.name
'lzm'

'''Python中定义私有变量只需要在变量名或函数名前加上'__'两个下划线'''
>>> p = Person()
>>> p.__name
Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    p.__name
AttributeError: 'Person' object has no attribute '__name'

'''在外部变量名已经隐藏起来了,理论上要访问,就需要从内部进行'''
>>> class Person:
	def __init__(self, n):
		self.__name = n
	def getname(self):
		return self.__name

>>> p = Person()
Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    p = Person()
TypeError: __init__() missing 1 required positional argument: 'n'
>>> p = Person('lzm')
>>> p.__name
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    p.__name
AttributeError: 'Person' object has no attribute '__name'
>>> p.getname()
'lzm'

'''还有更简单的方法获得私有变量'''
>>> p._Person__name
'lzm'

3.继承

        被继承的类称为基类、父类或超类;继承者称为子类,一个子类可以继承它的父类的任何属性和方法

# 类继承语法
class 类名(被继承的类):
    ...


>>> class Parent:
	def hello(self):
		print('正在调用父类的方法...')

>>> class Child(Parent):
	pass

>>> p = Parent()
>>> p.hello()
正在调用父类的方法...
>>> c = Child()
>>> c.hello()
正在调用父类的方法...


'''若子类中定义与父类同名的方法或属性,则会自动覆盖父类
对应的方法或属性'''
>>> class Parent:
	def hello(self):
		print('正在调用父类的方法...')
		
>>> class Child(Parent):
	def hello(self):
		print('正在调用子类的方法...')
		
>>> c = Child()
>>> c.hello()
正在调用子类的方法...


'example'
import random as r

class Fish:
    def __init__(self):
        self.x = r.randint(0, 10)
        self.y = r.randint(0, 10)

    def move(self):
        # 这里主要演示类的继承机制,就不考虑检查场景边界和移动方向的问题
        # 假设所有的鱼都是一路向西游
        self.x -= 1
        print('我的位置是:', self.x, self.y)

class Goldfish(Fish):
    pass

class Carp(Fish): # 鲤鱼
    pass

class Salmon(Fish): # 三文鱼
    pass

class Shark(Fish): # 鲨鱼会多一点个性
    def __init__(self):
        self.hungry = True

    def eat(self):
        if self.hungry:
            print('I want to eat fish!')
            self.hungry = False
        else:
            print('涨倒了')

>>> fish = Fish()
>>> fish.move()
我的位置是: 5 3
>>> goldfish = Goldfish()
>>> goldfish.move()
我的位置是: -1 2
>>> goldfish.move()
我的位置是: -2 2
>>> shark = Shark()
>>> shark.hungry
True
>>> shark.eat()
I want to eat fish!
>>> shark.eat()
涨倒了
>>> shark.move()
Traceback (most recent call last):
  File "<pyshell#56>", line 1, in <module>
    shark.move()
  File "<pyshell#27>", line 9, in move
    self.x -= 1
AttributeError: 'Shark' object has no attribute 'x'
'''报错原因:在Shark类中重写了魔法方法__init__,但新的__init__方法里边没有初始化
鲨鱼的x坐标和y坐标,因此调用move方法就会出错。
解决办法:在鲨鱼类中重写__init__方法的时候先调用父类Fish的__init__方法。'''

# 方法一:调用未绑定的父类方法
>>> class Shark(Fish):
	def __init__(self):
		Fish.__init__(self)
		self.hungry = True
	def eat(self):
		if self.hungry:
			print('I want to eat fish!')
			self.hungry = False
		else:
			print('涨倒了')

			
>>> shark = Shark()
>>> shark.move()
我的位置是: 5 6
>>> shark.move()
我的位置是: 4 6

# 方法二:使用super函数
>>> class Shark(Fish):
	def __init__(self):
		super().__init__()
		self.hungry = True
	def eat(self):
		if self.hungry:
			print('I want to eat fish!')
			self.hungry = False
		else:
			print('涨倒了')

			
>>> shark = Shark()
>>> shark.move()
我的位置是: -1 0
>>> shark.move()
我的位置是: -2 0
'''super函数的'超级'之处在于:不需要明确给出任何父类的名字,它会自动找出所有
父类以及对应的办法。由于不用给出基类的名字,这就意味着如果需要改变类继承关系,
只要改变class语句里的父类即可,而不必要在大量代码中去修改所有被继承的方法。'''

4.多重继承

>>> class Base1:
	def foo1(self):
		print('I am foo1, in Base1')

		
>>> class Base2:
	def foo2(self):
		print('I am foo2, in Base2')

		
>>> class C(Base1, Base2):
	pass

>>> c = C()
>>> c.foo1()
I am foo1, in Base1
>>> c.foo2()
I am foo2, in Base2
'''多重继承风险大,应谨慎使用'''

5.组合

例如:有一个乌龟类,有一个鱼类,现在要定义一个水池类,用多重继承会显得很奇怪,可以把乌龟和鱼组合成一个水池类:直接把需要的类放进去实例化就可以了。

>>> 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条

6.类、类对象和实例对象

>>> class C:
	count = 0

	
>>> a = C()
>>> b = C()
>>> c = C()
>>> print(a.count, b.count, c.count)
0 0 0
>>> c.count += 10
>>> print(a.count, b.count, c.count)
0 0 10
>>> C.count += 100 # 注意这里是对类进行改变
>>> print(a.count, b.count, c.count)
100 100 10

'''如果属性的名字与方法名相同,属性会覆盖方法'''
>>> class C:
	def x(self):
		print('X-man')
		
>>> c = C()
>>> c.x()
X-man
>>> c.x = 1
>>> c.x
1
>>> c.x()
Traceback (most recent call last):
  File "<pyshell#50>", line 1, in <module>
    c.x()
TypeError: 'int' object is not callable

7.到底什么是绑定

# Python严格要求方法(函数)要有实例才能被调用,实例即self(self只是惯常写法)
# 函数内部如果要出现属性名必须带前缀 self.
>>> 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#57>", line 1, in <module>
    bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given
'''根据类实例化后的对象根本无法调用里边的函数,因为由于Python的绑定机制,
这里自动把bb对象作为第一个参数传入,所以出现了TypeError。'''

>>> class CC:
	def setXY(self, x, y):
		self.x = x
		self.y = y
	def printXY(self):
		print(self.x, self.y)
		
>>> dd = CC()
>>> # 可以使用__dict__查看对象所拥有的属性:
>>> dd.__dict__
{}
>>> CC.__dict__
mappingproxy({'__module__': '__main__', 'setXY': <function CC.setXY at 0x0000028B07CF7730>, 
'printXY': <function CC.printXY at 0x0000028B07CF77B8>, 
'__dict__': <attribute '__dict__' of 'CC' objects>, 
'__weakref__': <attribute '__weakref__' of 'CC' objects>, 
'__doc__': None})
'''__dict__属性由一个字典组成,字典中仅有实例对象的属性,不显示类属性和特殊属性,
key表示的是属性名,value表示属性相应的数据值。'''

>>> dd.setXY(4, 5)
>>> dd.__dict__
{'x': 4, 'y': 5}
'''现在实例对象dd有了两个新属性,而且这两个属性仅属于实例对象'''
# 下面的暂时不明白,无法复现书上的
>>> CC.__dict__
mappingproxy({'__module__': '__main__', 'setXY': <function CC.setXY at 0x0000028B07CF7730>, 'printXY': <function CC.printXY at 0x0000028B07CF77B8>, 
'__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': 
<attribute '__weakref__' of 'CC' objects>, '__doc__': None})
>>> del CC
>>> dd.printXY()
4 5

8.一些相关的BIF

''' (1) issubclass(class, classinfo)
    如果第一个参数(class)是第二个参数(classinfo)的一个子类,
    则返回True,否则返回False。
    ①一个类被认为是其自身的子类
    ②classinfo可以是类对象组成的元组,只要class是其中任何一个候选类的子类,
     则返回True
    ③在其他情况下,会抛出一个TypeError异常'''
>>> class A:
	pass

>>> class B(A):
	pass

>>> issubclass(B, A)
True
>>> issubclass(B, B)
True 
>>> issubclass(B, object)
True
>>> class C:
	pass

>>> issubclass(B, C)
False


'''(2) isinstance(object, classinfo)
    如果第一个参数(object)是第二个参数(classinfo)的实例对象,
    则返回True,否则返回False
    ①如果object是classinfo的子类的一个实例,也符合条件
    ②如果第一个参数不是对象,则永远返回False
    ③classinfo可以是类对象组成的元组,只要object是其中任何一个
     候选类的子类,则返回True
    ④如果第二个参数不是类或者由类对象组成的元组,则会抛出TypeError异常'''
>>> class A:
	pass

>>> class B(A):
	pass

>>> class C:
	pass

>>> b1 = B()
>>> isinstance(b1, B)
True
>>> isinstance(b1, C)
False
>>> isinstance(b1, A)
True
>>> isinstance(b1, (A, B, C))
True

# Python提供了以下几个BIF用于访问对象的属性,attr是attribute(属性)的缩写
'''(3) hasattr(object, name)
    测试一个对象里是否有指定的属性,object是对象,name是属性名(属性的字符串名字)'''
>>> class C:
	def __init__(self, x=0):
		self.x = x
		
>>> c1 = C()
>>> hasattr(c1, 'x')
True


'''(4) getattr(object, name[,default])
    返回对象指定的属性值,如果指定的属性不存在,则返回default(可选参数)
    的值;若没有设置default参数,则抛出AttributeError异常'''
>>> getattr(c1, 'x')
0
>>> getattr(c1, 'y')
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    getattr(c1, 'y')
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c1, 'y', '访问的属性不存在')
'访问的属性不存在'


'''(5) setattr(object, name, value)
    如果指定的属性不存在,则会新建属性并赋值'''
>>> setattr(c1, 'y', 'lzm')
>>> c1.y
'lzm'
>>> getattr(c1, 'y')
'lzm'


'''(6) delattr(object, name)
    如果属性不存在,则会抛出AttributeError异常'''
>>> delattr(c1, 'y')
>>> getattr(c1, 'y', '不存在')
'不存在'
>>> delattr(c1, 'z')
Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    delattr(c1, 'z')
AttributeError: z


'''(7) property(fget=None, fset=None, fdel=None, doc=None)
    作用:通过属性来设置属性'''
>>> class C:
	def __init__(self, size=10):
		self.size = size
	def getSize(self):
		return self.size
	def setSize(self, value):
		self.size = value
	def delSize(self):
		del self.size
	x = property(getSize, setSize, delSize)

>>> c = C()
>>> c.x
10
>>> c.x = 12
>>> c.x
12
>>> c.size
12
>>> del c.x
>>> c.size
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    c.size
AttributeError: 'C' object has no attribute 'size'
'''property()返回一个可以设置属性的属性,如何设置属性还是需要人为来写代码。
第一个参数是获得属性的方法名,第二个参数是设置属性的方法名,第三个参数是
删除属性的方法名。'''

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值