面向过程 VS 面向对象
- 面向过程
面向过程的程序设计思想是过程,也就是流程式编程思想.C语言就是面向过程的,它就像是精心设计好的一条流水线,已经事先考虑好了什么时候处理什么问题.
优点:
简化了代码的复杂度,只要顺着程序的流程顺序书写即可.
缺点:
不利于改变和维护,以及代码的重复利用.因为面向过程的编程,一旦一个环节需要修改,则整个程序就可能受到很大的影响.
- 面向对象
面向对象的核心思想是对象,把一切都当成对象来看待.把具有相似特征和功能的事物抽象为类,然后用类封装一些属性和方法.然后程序的完成,通过对象和对象之间的交互来完成.面向对象的编程思想我们主要考虑的是某个类应该具有什么属性,这个类可以提供什么样的功能.
优点:
程序具有高度的扩展性.对于一个对象的单独修改,会反映到整个程序.并且把程序的创建更加的模块化了.
Python得面向对象
Python并不是完全的面向对象语言,它只是提供了支持.Python是同时支持函数式编程(面向过程)以及面向对象编程的语言.
类 对象 实例 实例化
- 类:
具有相同特征的一类事物的高度抽象(如:人,狗,猫)
- 实例/对象
属于某类事物的具体的某个一个事物(如:小黑)
- 实例化
类 ==> 床架对象/实例 的过程就叫实例化.
初识类和对象
python中一切皆为对象,类型的本质就是类,所以,不管你信不信,你已经使用了很长时间的类了
>>> dict #类型dict就是类dict
<class 'dict'>
>>> d=dict(name='eva') #实例化
>>> d.pop('name') #向d发一条消息,执行d的方法pop
'eva'
在Python中,用变量表示特征,用函数表示技能,因而具有相同特征和技能的一类事物就是'类',对象则是这一类事物中的具体的一个
类的相关知识
类属性和实例属性
属性就是属于一个对象的数据或者函数,我们可以通过句点(.)来访问属性,同时Python还支持在运作中添加和修改属性.
类属性就是类对象所拥有的属性,它被所有的类对象的实例化对象所共有,在内存中只有一个副本.类似于C++/java中的静态成员变量.通过类名/或者实例对象名都可以访问.而实例属性,是某个类特有的属性,可以在init中声明创建,也可以在类的外部实例化一个类进行创建赋值.
实例属性示例
# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/21 15:59'
# 类属性
class People:
name = "Tom" # 公有的类属性
__age = 18 # 私有的类属性
p = People()
print(p.name) # 实例对象调用
print(People.name) # 类对象调用
# print(People.__age)
# print(p.__age) 不能在类外部访问私有的类属性.
类属性示例
# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/21 15:59'
# 实例属性
class People:
name = 'tom' # 类属性
def __init__(self):
self.age = 18 # 实例属性
p = People()
p.sex = "男" # 外部添加实例属性
print(p.name) # 类属性
print(p.age) # init方式创建的实例属性
print(p.sex) # 外部创建的实例属性
print(People.name) # 类可以访问类属性
print(People.age) # 出错,类不可访问实例属性
Python中类的方法也叫动态属性
类的两种作用: 类属性引用和实例化
属性引用
class Person(object):
role = 'person' #类属性
def walk(self): # 这里的方法也是类属性,可以通过Person直接调用.
print('people is walking...')
print(Person.role) # 查看人的role属性
print(Person.walk) # 引用人的走路方法,注意这里不是调用
实例化:
类名加括号就是实例化,会自动触发init函数的运行,可以用它来为每个实例定制自己的特征
# 使用__init__()实例属性定制自己的特征
class Person: # 定义一个人类
role = 'person' # 人的角色属性都是人
def __init__(self,name):
self.name = name # 每个角色都有自己的昵称
def walk(self):
print("Person {} is walking".format(self.name))
print(Person.role)
print(Person.walk)
p = Person("小黄")
p1 = Person("小红")
p.walk()
p1.walk()
# Person 小黄 is walking
# Person 小红 is walking
类属性的补充
问题? 我们定义的类的属性到底保存到哪里去了?
dir(类名): 查出的是一个名字列表,包括该类的属性列表.
类名.dict: 查出的是一个字典,key为属性名,value为属性值.
特殊的类属性
实例方法,类方法,静态方法的使用和区别
实例方法
定义:
第一个参数必须是实例对象,一般命名为'self',通过它来传递实例属性和方法(也可以传递类属性和方法)
调用:
只能由实例对象或者在类内调用
class Person: # 定义一个人类
role = 'person' # 人的角色属性都是人
def __init__(self,name):
self.name = name # 每个角色都有自己的昵称
def walk(self): # 实例方法
print("Person {} is walking".format(self.name))
print(Person.role)
print(Person.walk)
p = Person("小黄")
p1 = Person("小红")
p.walk()
p1.walk()
# Person.walk()# 报错,实例方法只能通过实例对象调用
# Person 小黄 is walking
# Person 小红 is walking
类方法
定义:
使用装饰器@classmethod.第一个参数必须是当前类对象,一般用cls来表示,通过它来传递类的属性和方法(不能传递实例的属性和方法)
调用:
实例对象和类都可以调用
# 类方法
class People:
country = 'china'
# 但是用实例可以调用,在用实例调用的时候,相当于是在用实例
# 隶属的类在调用.
@classmethod # 类方法,属于类,而不属于具体的实例.
def getCountry(cls): # 只能传递和操作类属性和方法
return cls.country
p = People()
print(p.getCountry()) #实例对象调用类方法
print(People.getCountry()) #类对象调用类方法
静态方法
定义:
使用装饰器@staticmethod.参数随意,没有self和cls参数,但是方法体中不能使用类或者实例的属性和方法.它主要用来创建一个方法,和类以及实例没有任何的关联的.
调用:
实例对象和类都可以调用.它相当于是一个全局方法.
静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护.
譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。
import time
__author__ = 'Fioman'
__date__ = '2018/11/21 15:59'
class TimeTest(object):
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second
@staticmethod
def showTime():
return time.strftime("%H:%M:%S", time.localtime())
print(TimeTest.showTime())
t = TimeTest(2, 10, 10)
nowTime = t.showTime()
print(nowTime)
如上,使用了静态方法(函数),然而方法体中并没使用(也不能使用)类或实例的属性(或方法)。若要获得当前时间的字符串时,并不一定需要实例化对象,此时对于静态方法而言,所在类更像是一种名称空间。
其实,我们也可以在类外面写一个同样的函数来做这些事,但是这样做就打乱了逻辑关系,也会导致以后代码维护困难
Python的面向对象的三大特性
封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式.
好处:
提高复用性和数据的安全性
原则:
- 将不需要对外提供的内容隐藏起来
- 把属性都隐藏,提供公共的访问对其访问.
私有变量和私有方法
在Python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/21 19:47'
# 其实这只是一种变形操作
# 类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
class A:
__N = 0 #类的数据属性就应该是共享的,但是语法上是可以把类的数量属性设置成为私有的
# 如__N,会变形为_A__N
def __init__(self):
self.__X = 10 # 变形为self._A__X
def __foo(self): # 会变形为_A__foo
print('from A')
def bar(self):
self.__foo() # 只有在类内部才可以通过__foo的形式访问到
# A._A__N是可以放到的,即这种操作并不是严格意义上的显示外部访问,仅仅只是一种语法意义上的变形
这种变形的特点
1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
3.在子类定义的__x不会覆盖在父类定义的_x,因为子类中变形成了:子类名_x,而父类中变形成了:父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
需要注意的问题是:
1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:类名_属性,然后就可以访问了,如a._A__N
2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形
网友评论