面向对象--01面向对象基本概念

OOA 面向对象分析
OOD 面向对象设计
OOP 面向对象编程

 

OO的特征
封装:对象封装 属性和方法,是一种信息隐蔽技术
继承:子类自动共享父类之间数据和方法的机制
多态:不同对象对统一方法响应不同的行动

 

面向对象(object oriented)

Python完全采用了面向对象程序设计的思想,是真正面向对象的高级动态编程语言,完全支持面向对象的基本功能,如封装、继承、多态以及对基类方法的覆盖或重写。但与其他面向对象程序设计语言不同的是,Python中对象的概念很广泛,Python中的一切内容都可以称为对象,而不一定必须是某个类的实例。例如,字符串、列表、字典、元组等内置数据类型都具有和类完全相似的语法和用法。

 

面向对象编程

一、类
类由三部分组成:
1.类名:首字母大写
2.属性:用于描述事物的特征
3.方法:用于描述事物的行为


二、根据类创建对象
语法:
对象名 = 类名()

 

三、

创建类时用变量形式表示的对象属性称为数据成员(或成员属性),用函数形式表示的对象行为称为成员函数(或成员方法),成员属性和成员方法统称为类的成员。

 

class Animal(object):  # 类对象

    age = 0  # 公有类属性
    __like = None  # 私有类属性

    def __init__(self):  # 魔法方法
        self.name = ‘haha’  # 公有实例属性
        self.__sex = ‘man’  # 私有实例属性

    def smile(self):  # 公有方法  self指向实例对象
        pass

    def __jump(self):  # 私有方法
        pass

    @classmethod
    def run(cls):  # 类方法  cls 指向类对象
        pass

    @staticmethod
    def msg():  # 静态方法,可以没有参数
        pass

 

 

四、类成员与实例成员

这里主要指数据成员,或者广义上的属性。可以说属性有两种,一种是实例属性,另一种是类属性。

实例属性一般是指在构造函数__init__()中定义的,定义和使用时必须以self作为前缀;类属性是在类中所有方法之外定义的数据成员。

在主程序中(或类的外部),实例属性属于实例(对象),只能通过对象名访问;而类属性属于类,可以通过类名或对象名访问。在类的方法中可以调用类本身的其他方法,也可以访问类属性以及对象属性。在Python中比较特殊的是,可以动态地为类和对象增加成员,这一点是和很多面向对象程序设计语言不同的,也是Python动态类型特点的一种重要体现。

 

五、私有成员与公有成员

Python并没有对私有成员提供严格的访问保护机制。在定义类的属性时,如果属性名以两个下划线“__”开头则表示是私有属性,否则是公有属性。

私有属性在类的外部不能直接访问,需要通过调用对象的公有方法来访问,或者通过Python支持的特殊方式来访问。Python提供了访问私有属性的特殊方式,可用于程序的测试和调试。私有属性是为了数据封装和保密而设的属性,一般只能在类的成员方法(类的内部)中使用访问。

公有属性是可以公开使用的,既可以在类的内部进行访问,也可以在外部程序中使用。

class A:
	def __init__(self, value1 = 0, value2 = 0):
		self._value1 = value1
		self.__value2 = value2
	def setValue(self, value1, value2):
		self._value1 = value1
		self.__value2 = value2
	def show(self):
		print(self._value1)
		print(self.__value2)

>>> a = A()
>>> a._value1
0
>>> a._A__value2    #在外部访问对象的私有数据成员
0

在IDLE环境中,在对象或类名后面加上一个圆点“.”,稍等一秒钟则会自动列出其所有公开成员,模块也具有同样的特点。

而如果在圆点“.”后面再加一个下划线,则会列出该对象或类的所有成员(包括私有成员)。

在Python中,以下划线开头的变量名和方法名有特殊的含义,尤其是在类的定义中。用下划线作为变量名和方法名前缀和后缀来表示类的特殊成员:

_xxx:这样的对象叫做保护成员,不能用'from module import *'导入,只有类对象和子类对象能访问这些成员;

__xxx__:系统定义的特殊成员;

__xxx:类中的私有成员,只有类对象自己能访问,子类对象也不能访问到这个成员,但在对象外部可以通过“对象名._类名__xxx”这样的特殊方式来访问。Python中不存在严格意义上的私有成员。

 

另外,在IDLE交互模式下,一个下划线“_”表示解释器中最后一次显示的内容或最后一次语句正确执行的输出结果。例

>>> 3 + 5
8
>>> _ + 2
10
>>> _ * 3
30
>>> _ / 5
6
>>> 3
3
>>> _
3
>>> 1/0
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    1/0
ZeroDivisionError: integer division or modulo by zero
>>> _
3

 

下面代码演示了特殊成员定义和访问的方法:

>>> class Fruit:
        def __init__(self):
             self.__color = 'Red'
             self.price = 1
>>> apple = Fruit()
>>> apple.price #显示对象公开数据成员的值
1
>>> apple.price = 2 #修改对象公开数据成员的值
>>> apple.price
2
>>> print(apple.price, apple._Fruit__color) #显示对象私有数据成员的值
2 Red
>>> apple._Fruit__color = "Blue" #修改对象私有数据成员的值
>>> print(apple.price, apple._Fruit__color)
2 Blue
>>> print(apple.__color) #不能直接访问对象的私有数据成员,出错
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    print(apple.__color )
AttributeError: Fruit instance has no attribute '__color'
>>> peach = Fruit()
>>> print(peach.price, peach._Fruit__color)
1 Red

 

六、类属性和实例属性

类属性是类所拥有的属性,它需要在类中显式定义(位于类内部,方法的外面),它被所有类的实例对象所共有,在内存中只存在一个副本。

 
#定义Cat类
class Cat(object):
    #类属性
    num = 0
    def __init__(self):
        #实例属性
        self.age = 1

cat = Cat()
#用对象去访问类属性是可以的
print(cat.num)
#常用的方法是,使用类去访问类属性
print(Cat.num)

0
0
>>>

从程序输出的结果看出,类属性可以通过类或者类的实例访问到,尽管如此,我们通常会使用类去访问类属性。

如果类属性和实例属性的名字相同,通过对象访问属性时会获取实例属性对应的值。所以当程序要获取类属性的值的时候,通过类获取到的一定是类属性的值。

七、类的方法

在Python中,类方法和静态方法都属于类的方法

类的方法有三种,一是通过def定义的 普通的一般的,需要至少传递一个参数,一般用self,这样的方法必须通过一个类的实例去访问,类似于c++中通过对象去访问;二是在def前面加上@classmethod,这种类方法的一个特点就是可以通过类名去调用,但是也必须传递一个参数,一般用cls表示class,表示可以通过类直接调用;三是在def前面加上@staticmethod,这种类方法是静态的类方法,类似于c++的静态函数,他的一个特点是参数可以为空,同样支持类名和对象两种调用方式;

代码:

class A:  
    member = "this is a test."  
    def __init__(self):  
        pass  
 
    def print1(self):  
        print('print 1:' , self.member) 

    @classmethod  
    def print2(cls):  
        print('print 2:' , cls.member)   

    @staticmethod  
    def print3():  
        print("hello")  


(1)类方法
可以使用修饰器@classmethod来标识类方法,其语法格式如下:

class 类名:
	@classmethod
	def 类方法名(cls):
	    方法体

 

在上述格式中,类方法的第一个参数为cls,代表定义类方法的类,可以通过cls访问类的属性。
要想调用类方法,既可以通过对象名调用类方法,又可以通过类名调用类方法,这两种方法没有任何区别。

class Test(object):
    #类属性
    num=0
    #类方法
    @classmethod
    def setnum(cls,newnum):
        cls.num = newnum

 

>>> Test.setnum(300)
>>> print(Test.num)
300
>>>


需要注意的是,类方法是无法访问实例属性的,但是可以访问类属性

 

(2)静态方法
可以使用修饰器@staticmenthod来识别静态方法,其语法格式如下:

class 类名:
	@staticmenthod
	def 静态方法名():
	    方法体

 

在上述格式中,静态方法的参数列表中没有任何参数。由于静态方法没有self参数,所以它无法访问类的实例属性:静态方法也没有cls参数,所以它也无法访问类属性。静态方法跟定义它的类没有直接的关系,只是起到类似与函数的作用。


要想调用静态方法,既可以通过对象名调用,也可以通过类名调用静态方法,这两种方法没有任何区别。

class Test(object):
    @staticmethod
    def printTest():
        print('我是静态方法')
Test.printTest()
test = Test()
test.printTest()

 

我是静态方法
我是静态方法
>>>

 


类的对象可以访问实例方法、类方法和静态方法;使用类可以访问类方法和静态方法。那么,实例方法、类方法和静态方法有什么区别呢?
如果要修改实例属性的值,就直接使用实例方法;如果要修改类属性的值,就直接使用类方法;如果是辅助功能,如打印菜单,这时可以考虑使用静态方法,可以在不创建对象的前提下使用。

注意:使用类名不能访问实例属性或者实例方法。

 

 

八、self
当一个对象的方法被调用的时候,对象会将自身作为第一个参数传给self参数
python严格要求方法需要有实例才能被调用,这种限制其实就是‘绑定’概念

类的所有实例方法都必须至少有一个名为“self”的参数,并且必须是方法的第一个形参(如果有多个形参的话),“self”参数代表将来要创建的对象本身。在类的实例方法中访问实例属性时需要以“self”为前缀,但在外部通过对象名调用对象方法时并不需要传递这个参数,如果在外部通过类名调用对象方法则需要显式为self参数传值。
在Python中,在类中定义实例方法时将第一个参数定义为“self”只是一个习惯,而实际上类的实例方法中第一个参数的名字是可以变化的,而不必须使用“self”这个名字。

 

  

class CC:
	def setxy(self,x,y):
		self.x = x
		self.y = y
	def printxy(self):
		print(self.x,self.y)

>>> SAY.printsay()
no zuo no die
>>> bb = SAY()
>>> bb.printsay()
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    bb.printsay()
TypeError: printsay() takes 0 positional arguments but 1 was given


#self与实例化对象绑定, 实例化对象.方法() 的过程中会将实例化对象作为第一个参数传入,方法中需要有self参数接受。

 

用.__dict__查看对象所拥有的属性,以下为IDLE环境的演示

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 0x000001ABEE81A840>, 'printxy': <function CC.printxy at 0x000001ABEE81AA60>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None})
>>> dd.setxy(7,8)
>>> dd.__dict__
{'x': 7, 'y': 8}
>>> CC.__dict__
mappingproxy({'__module__': '__main__', 'setxy': <function CC.setxy at 0x000001ABEE81A840>, 'printxy': <function CC.printxy at 0x000001ABEE81AA60>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None})

 

可见,传入的x=7 y=8属性仅属于实例对象dd的


>>> del CC
>>> dd.x
7


>>> dd.printxy()
7 8

 

类中定义的属性和方法是静态变量,就算类对象被删除,它们依然存放在内存中

 

 

九、属性名、方法名覆盖及只读
如果属性名和方法名相同,属性名会将方法名覆盖

>>> class C:
	def x(self):
		print('x-man')

 

>>> c = C()
>>> c.x
<bound method C.x of <__main__.C object at 0x000001ABEE774BA8>>
>>> c.x()
x-man
>>> c.x = 1
>>> c.x
1
>>> c.x()
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    c.x()
TypeError: 'int' object is not callable
>>>


在Python 3.x中,属性得到了较为完整的实现,支持更加全面的保护机制。例如下面的代码所示,如果设置属性为只读,则无法修改其值,也无法为对象增加与属性同名的新成员,同时,也无法删除对象属性。

class Test:
	def __init__(self, value):
		self.__value = value
	@property
	def value(self): #只读,无法修改和删除
		return self.__value



>>> t = Test(3)
>>> t.value
3
>>> t.value = 5 #只读属性不允许修改值
出错信息(略)
AttributeError: can't set attribute
>>> t.v=5 #动态增加新成员
>>> t.v
5
>>> del t.v #动态删除成员
>>> del t.value #试图删除对象属性,失败
出错信息(略)
AttributeError: can't delete attribute
>>> t.value
3

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值