
类和实例
类的定义和实例化
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板而实例是根据类创建出来的一个个具体的“对象”。
在Python中,定义类是通过class关键字:class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。
class Student(object):
pass
根据Student类创建出Student的实例,创建实例是通过类名+()实现的:
bart = Student()
可以在创建类的时候,通过定义一个特殊的init方法,把一些公共的属性写进去。
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))
创建实例时,参数必须与公共属性相对应(不传self),调用类方法时也不需要传self
bart = Student('Bart Simpson', 59)
bart.print_score()
也可以在实例上定义属性和属性方法
def set_age(self, age): # 定义一个函数作为实例方法
self.age = age
from types import MethodType
bart .set_age = MethodType(set_age, bart ) # 给实例绑定一个方法
bar.gender = '男' #绑定属性
类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
私有变量
在属性名称前面加__,则该属性就是类的私有变量,只可以在类的内部被访问
- 当你看到一个下划线开头的实例变量名,如_name这样的是里外不是可以访问得到的,但按照约定俗成的规定,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
- 双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量:(但是不同版本的Python解释器可能会把__name改成不同的变量名,有可能换个解释器你用_Student__name就访问不到了。)
实例属性和类属性
给实例绑定属性的方法是通过实例变量,或者通过self变量:
如果Student类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student类所有:
class Student(object):
name = 'Student'
当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。
类的三大特点
封装
面向对象编程的特点之一就是封装,尽量将可以封装的数据封装在类里面,也包括引用这些数据的函数。
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))
继承
当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def eat(self):
print('Eating meat...')
dog = Dog()
dog.run()
判断某个实例是否是某个类的实例
>>> isinstance(dog , Dog)
True
>>> isinstance(dog , Animal)
True
super() 函数是用于调用父类(超类)的一个方法。
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
多态
当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),这就叫多态。
class Dog(Animal):
def run(self):
print('Dog is running...')
上面给Dog子类也添加了run方法,这样子类Dog里的方法则会取代父类的;
获取对象信息
当我们拿到一个对象的引用时,如何知道这个对象是什么类型、有哪些方法呢?
type()
print(type(dog)) #<class '__main__.Dog'>
判断基本数据类型可以直接写int,str
但如果要判断一个对象是否是函数怎么办?可以使用types模块中定义的常量:
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
isinstance()
isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。
>>> isinstance(dog , Dog)
True
>>> isinstance(dog , Animal)
True
并且还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是list或者tuple:
>>> isinstance([1, 2, 3], (list, tuple))
True
dir()
如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:
配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:
hasattr(dog, 'run') # 有属性'run'吗?#不可以用 in 代替
True
>>> setattr(dog, 'y', 19) # 设置一个属性'y'
>>> hasattr(dog, 'y') # 有属性'y'吗?
True
>>> getattr(dog, 'y') # 获取属性'y' ,获取不存在的参数就会抛出错误
19
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息。
网友评论