面向对象
类和实例
类是抽象的模板;实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同;
定义类:class
class Student(object):
pass
类名通常开头大写,若无其他继承,则继承至object类
创建实例:类名+()
bart=Student()
为实例变量绑定属性:
bart.name=‘Bart Simpson’
(即直接定义)(直接一句完成声明、定义)
类作为模板,若需强制附带属性,可通过特殊的__init__方法
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
和普通的函数相比,在类中定义的函数只有一点不同,第一个参数永远是实例变量self,调用时,不用传递该参数,表示创建实例本身,在方法内部可以将各种属性绑定到self(有了__init__方法后,外界在创建类的实例变量时,必须传入与方法匹配的参数,在外界对其传入参数时,只需传入self后面参数即可)
方法即为和类绑定的函数,和普通函数不同,方法可访问实例的数据
和静态语言不同,python允许实例变量绑定任何数据
数据封装
将数据和逻辑封装,通过类的方法直接与外界交流,调用简单,无需知道内部是实现细节(在方便的同时可实现对内部数据的保护)
通过封装,还可以在方法内部添加参数检查工具,以保障外部数据的正确传值。
访问限制
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
如此,外部则无法通过实例变量.__name访问属性了,但python内部并非强制,需要靠用户自觉将其视为私有变量,不去访问,内部解释器只是将变量换了名字,如对外把__name变量改成了_Student__name,但可能因为版本不同而不同修改规则,一般不予访问
作为私有变量,外部要获取其值,则通过给类增加如get_name、set_score方法(内部访问,后通过方法包装,和外界交流)
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
self.__score = score
python中,变量名类似__xxx__双边双下划线的,是特殊变量,可以直接访问,不同于开头单下划线的__xxx私有(private)变量。
继承和多态
新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
子类拥有父类相同方法时,进行覆盖(继承属性了吗?)
多态:
判断一个变量是否是某个类型可以用isinstance()判断:
isinstance(a,list)
是返回True 否则返回False
但若a为list的子类(由其继承下来(继承链)),则同样属于list,此为向上;向下则不行(数据类型子类可以看做父类,反之不行)
好处:当函数接收父类的数据类型的变量的时候,传入子类时,则同一名称的方法会使用子类的方法(新增子类无需对外部调用的方法进行修改)调用方只管调用,不管细节
“开闭”原则:
对扩展开放:允许新增Animal子类;
对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
静态语言与动态语言区别:
静态语言(如java)中传入类型必须是Animal或者其子类,否则无法调用run()方法
动态语言(如python)不一定传入Animal类型,只需传入对象有run()方法就可
def run_twice(animal):
animal.run()
animal.run()
class Timer(object):
def run(self):
print('Start...')
此类型不从Animal继承,但作为实例传入可以调用run()方法
动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子
获取对象信息
type()
判断基本数据类型可以直接写int,str等
type(123)==type(456)
type(123)==int
但如果要判断一个对象是否是函数怎么办?可以使用types模块中定义的常量:
type(fn)==types.FunctionType
type(abs)==types.BuiltinFunctionType
type(lambda x: x)==types.LambdaType
type((x for x in range(10)))==types.GeneratorType
isinstance()
除类外,能用type()判断的基本类型也可以用isinstance()判断:
isinstance('a', str)
isinstance(123, int)
isinstance([1, 2, 3], (list, tuple))
dir()
如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list
__xxx__名称的属性方法在python中有特殊用途,如__len__方法返回长度,但可通过调用len()函数获取对象长度,在len()函数内部,它自动去调用该对象的__len__()方法
即:
len('ABC')
'ABC'.__len__()
两种方式等价
自己写的类,若想用len()时,可自己写一个__len__()方法:
class MyDog(object):
def __len__(self):
return 100
(__len__()不是Object继承来的?那自己定义的自己又如何知道的数据长度呢)
lower()返回小写的字符串:
>>> 'ABC'.lower()
'abc'
getattr():获取属性(包括方法)
setattr()设置属性(?包不包括方法?)
hasattr()查询属性(包括方法)
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
如果试图获取不存在的属性,会抛出AttributeError的错误:
>>> getattr(obj, 'z') # 获取属性'z'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyObject' object has no attribute 'z'
但可设置返回值,传入default参数
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404
一般只有在不知道对象信息时这样获取,平常直接操作对象就可以
实例属性和类属性
实例绑定属性通过实例变量,或self变量:(java中则是通过实例变量,或this关键字)
class Student(object):
def __init__(self, name):
self.name = name
类本身绑定属性,直接定义属性:(java中则是通过静态字段static field)(那python有没有静态方法呢?)
class Student(object):
name = 'Student'
这个属性虽然归类所有,但类的所有实例都可以访问到
,但通过实例变量更改后只是实例变量变了,类属性并未被更改(那这个类属性有啥用,作为标记?或者只能通过类、作为类属性更改)(java中会被更改)
相同名称的实例属性将屏蔽掉类属性
if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行
本文介绍了Python的面向对象编程,包括类和实例的概念,数据封装,访问限制,继承和多态。讨论了如何通过类方法访问和保护内部数据,以及如何通过继承实现代码复用和多态性。此外,还讲解了如何获取对象信息,如实例属性和类属性的区别。
632

被折叠的 条评论
为什么被折叠?



