类是抽象的模板;实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同;
定义类: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__'
之下的代码块不被运行