参考链接:廖雪峰的官方网站
代码示例:
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
关键字来定义类,类名通常要大写,后面的括号里面表示该类继承于哪个类,所有类最终继承于object
类,这类似于Java__init__
方法可以把必须绑定给类实例的属性填写进去,它的第一个参数永远是self
,表示创建的实例本身,在创建实例的时候,必须传入与__init__
方法匹配的参数,self
除外self
,调用时不用传递该参数 chen = Student('chen', 13)
bart = Student('bart', 81)
chen.print_score()
bart.print_score()
chen.score = 100
bart.name = 'kobe'
chen.print_score()
bart.print_score()
输出结果:
chen: 13
bart: 81
chen: 100
kobe: 81
__
把它变成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))
>>> bart = Student('Bart Simpson', 59)
>>> bart.__name
Traceback (most recent call last):
File "" , line 1, in
AttributeError: 'Student' object has no attribute '__name'
_name
外部可以访问,但是最好把它视为私有变量,不要随便访问__name
改成了_Student__name
,因此可以通过_Student__name
来访问私有的内部属性(不建议采用这种方式):>>> bart._Student__name
'Bart Simpson'
bart.__name
,会报错Student
类不含有此成员,但是bart.__name = 'New Name'
语句是不会报错的,随后再输出bart.__name
也不会再报错了:>>> bart = Student('Bart Simpson', 59)
>>> bart.get_name()
'Bart Simpson'
>>> bart.__name = 'New Name' # 设置__name变量!
>>> bart.__name
'New Name'
这是一种错误的写法,这样设置的__name
变量并不是类内部的__name
变量,相当于给bart
新增了一个变量
__xxx__
,是特殊变量而不是私有变量,可以直接访问python中继承和多态的概念与C++中类似,但python作为动态语言,有一种新的用法:
我们常利用多态来实现更方便的函数调用,如:
def run_twice(animal):
animal.run()
animal.run()
在C++或者Java中,我们如果传递的是Animal
类的子类,调用的run()
方法就会是子类的run()
方法,这样我们在新增了Animal
类的一个子类时无需修改依赖Animal
类的run_twice
函数。
在静态语言中这种用法要求我们传递的必须是Animal
类或它的子类,但在python中没有这种限制,只要传递的类中有run()
函数即可,称之为“鸭子类型”
type()
来判断对象类型,它返回对应的Class
类型。type()
来判断:>>> type(123)
<class 'int'>
>>> type(2.0)
<class 'float'>
>>> type(["sd",'s',12])
<class 'list'>
>>> type(None)
<class 'NoneType'>
type()
来判断:>>> class Person:
... pass
...
>>> def test():
... pass
...
>>> p = Person()
>>> type(p)
<class '__main__.Person'>
>>> type(test)
<class 'function'>
type
来作为if
的判断条件,当类型不是int
,str
等基本类型时,需要使用types
模块中定义的常量:>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
isinstance()
来判断对象是否是某种类型isinstance()
判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上type()
判断的基本类型也可以用isinstance()
判断:>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
>>> isinstance(b'a', bytes)
True
isinstance
不仅可以判断是否是某种类型,还可以判断是否是某些类型的一种:>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True
dir()
来获得一个对象的所有属性和方法str
的所有属性和方法:>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
getattr()
、setattr()
以及hasattr()
,我们可以直接操作一个对象,不过这几个函数是在不知道对象信息的时候使用的,在了解对象信息时没有必要使用:>>> class MyObject(object):
... def __init__(self):
... self.x = 9
... def power(self):
... return self.x * self.x
...
>>> obj = MyObject()
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
getattr()
函数,可以在传入的属性参数后面加一个默认的参数,这样在对象不含有这个属性时就会返回默认参数,而不是抛出异常了:# 获取属性'z',如果不存在,返回默认值404
>>> getattr(obj, 'z', 404)
404
getattr()
函数还可以用于获取方法,把获取的方法赋值给一个变量,那个变量就指向这个方法,调用那个变量就相当于调用了这个方法:>>> getattr(obj, 'power') # 获取属性'power'
0x10077a6a0>>
>>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
>>> fn # fn指向obj.power
0x10077a6a0>>
>>> fn() # 调用fn()与调用obj.power()是一样的
81
实例属性我们在之前就已经使用过了,我们也了解到在python中可以给一个类实例绑定任何属性,方法是在类方法中利用self
或者直接通过实例来绑定。
要给类绑定一个属性的话,可以在类中直接定义它:
class Student(object):
name = 'Student'
也可以把类属性成为类的静态成员变量,这个属性是归类所有的,所有实例可以共享它。
需要注意的是,虽然name
属性归类Student
所有,但是类的所有实例都可以访问到,并且实例属性的优先级比类属性高,所以如果实例绑定了一个与类属性同名的实例属性时,优先调用的是实例属性:
>>> class Student(object):
... name = 'Student'
...
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student