python—面向对象
面向对象
- 类 方法 实例
- 封装 继承 多态
类和实例
示例
1
2
3
4
5
6
7
8
9
10class 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)定义类的关键词与java一样
class
括号内为继承的父类.没有父类时,选择object
作为基类.(object
是所有类的基类)变量比较特殊,不像java中有单独字段.python 类中变量定义是在
__init__
方法方法的声明和函数类似.
def 方法名 (参数)
- 类中 第一个参数必须是
self
,意为创建的实例自身.方法中调用类中其他变量都要通过self.xxx
访问.
- 类中 第一个参数必须是
一些必须实现的属性在
__init__
方法中定义.如示例.第一个参数是self
之后是具体变量值,在方法内 使用self访问类中定义的变量.Python允许对实例变量绑定任何数据,so just do it😈
访问限制
类似java private 字段的python实现
属性的名称前加上两个下划线
__
该属性就成为了类的私有属性,只能在实例的内部访问.(self.xxx
)获取/修改,使用
get/set
获取或修改对应属性.(一般在set中可以添加类型检查)类似
__xxx__
的变量,双下划线开头,并且以双下划线结尾的,是特殊变量.特殊变量是可以直接访问的,不是private变量.也最好不要定义__xxx__
变量名以下划线开头的实例变量名,例如
_name
.可以在外部访问的,但是,约定俗成,请直接忽视.特例:
双下划线开头的实例变量不能直接访问是因为Python解释器对外把
__name
变量改成了_Student__name
.仍然可以通过_Student__name
来访问__name
变量.一个错误设置示例:
1
2
3
4
5
6
7
8'Bart Simpson', 59) bart = Student(
bart.get_name()
'Bart Simpson'
'New Name' # 设置__name变量! bart.__name =
bart.__name
'New Name'
# get_name()内部返回self.__name bart.get_name()
'Bart Simpson'如同示例,外部代码直接赋给
bart.__name
不会影响实例中原有属性,只会新增一个属性.究其原因,实例中的属性已经被解释器重命名为了bart._Student__name
.
继承和多态
- 继承和多态概念与java类似.不多语了.
- 那么重点来了:
- python本身是动态语言,体现在变量/类等各个方面,自由度极高.在继承上,亦是如此.
- java中定义一个su方法,调用model类实例实现的run方法.su方法可传入的只有 model类或其子类的实例
- 但python中 只要是定义了 run方法(别管内容/功能一样不一样)类的实例,都可以作为参数传入 su 方法.
- java中对类的类型的处理,相当于照猫🐱画虎🐯,传入的起码要是个猫科动物. python 中对类的类型处理,额头写个
王
字,哪怕传入具体对象是个猫头鹰🦉,也当作猫科处理了.
note:
判断一个变量是否是某个类型可以用isinstance()1
2isinstance(a, list)
True
获取对象信息
- 让我想起了java反射..不过能获取的信息要全多了.
type()
示例:
1
2
3
4
5
6
7
8type(123)
<class 'int'>
>>> type(a)
<class '__main__.Animal'>
>>> type(123)==type(456)
True判断对象类型
由变量指向函数或者类,也可以用type()判断
type返回对应的Class类型,可直接
== 类型
判断判断一个对象是否是函数:
1
2
3
4
5
6
7
8>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
isinstance()
示例:
1
2
3
4
5isinstance(h, Husky)
True
isinstance([1, 2, 3], (list, tuple))
True判断继承关系,一打一个准.
能用type()判断的基本类型也可以用isinstance()判断
总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。
dir()
示例:
1
2dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']获得一个对象的所有属性和方法.直接返回一个字符串list.
配合getattr()、setattr()以及hasattr(),可以直接操作一个对象的状态.
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13hasattr(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
# 获取属性'y' obj.y
19不存在的属性,会抛出AttributeError的错误,可以传入一个default参数,如果属性不存在,就返回默认值.
1
2getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404也可以获得对象的方法
1
2
3
4
5
6
7
8
9hasattr(obj, 'power') # 有属性'power'吗?
True
getattr(obj, 'power') # 获取属性'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
getattr(obj, 'power') # 获取属性'power'并赋值到变量fn fn =
# fn指向obj.power fn
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
# 调用fn()与调用obj.power()是一样的 fn()
81只有在不知道对象信息的时候,才会去获取对象信息.谨记,谨记.
实例属性和类属性
类似java类中静态变量 与 普通变量区别.
类的属性,直接在类的cclass中声明.
1
2class Student(object):
name = 'Student'访问时,类的属性会被实例的同名属性覆盖,但不会被修改,互相独立.
删除实例属性后,再使用相同的名称,访问到的将是类属性