python面向对象案例_python面向对象

(34) 2024-09-21 12:01:01

面向对象

类和实例

类是抽象的模板;实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同;
定义类: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_nameset_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()
判断基本数据类型可以直接写intstr

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__'之下的代码块不被运行

THE END

发表回复