面向对象三要素
封装
组装:将一组数据结构和操作这些数据结构的方法组装到一起
隐藏数据:对外只暴露一些接口,通过接口访问对象。就像开车一样,你不知道车的组成原理,但是知道车辆驱动的方式就行了
继承
多复用:子类能够继承父类或以上的类的方法,这样来自继承类的方法就可以不用自己再编写代码。使代码更加精简。
多继承少修改:能够继承大部分特性,再通过重写的方式来增加一些特色
多态
不同的子类继承父类的同一方法,然后通过重写或者覆盖的方式来增加子类的特色,从而实现多态
类的定义
1.使用关键字class
2.类名建议使用大驼峰方式,本质上是个标识符
3.类定义完成后,会生成一个类对象,绑定到了类名上
class School:
"""这是个学校类"""
a = 123
x = 'abc'
def __init__(self, name, level):
self.name = name
self.level = level
def show_propertites(self):
return 'name is {}, level is {}'.format(self.name, self.level)
school1 = School('school_a', 'grade_one') #类的实例化
print(school1.show_propertites()) #调用类方法,会有绑定效果
print(school1.a) #访问类属性,公共属性
print(school1.__class__.a) #同上
print(school1.__class__.__dict__['a']) #通过类的字典来访问类属性
a
和x
是类变量,也是类属性。类中的方法,变量,还有__doc__都是类的属性,可以通过类或类字典来访问
1.__init__方法用来进行实例的初始化,第一个位置参数必须是self,也可以是其他能标识符,不过self是默认的标识符
2.init(self, name, grade),括号中包含的是实例的属性,在初始化时必须附带实参,除非这些形参有了默认值
注意
__init__()方法不能有返回值,或者说是返回None
方法绑定
实例在调用类方法的时候,会将实例名以第一位置参数传入,即实例会代替类方法中的self形参
属性
1.类属性是公有的属性,实例可以通过类、类字典来访问类属性。或者直接通过实例来调用属性,此方式会递归向上去查找
2.实例属性是实例私有的,其他实例和类都不能访问实例的属性
类方法和静态方法
类方法
class Person:
@classmethod
def class_method(cls):
print('类方法')
print("{0}'s name is {0.__name__}".format(cls))
tom = Person()
Person.class_method()
Person().class_method()
类方法应用
from time import time,sleep,localtime
class Clock(object): #所有类都继承自基类
"""定义一个时钟,每秒输出一次"""
def __init__(self, hour=0, minute=0, second=0):
self._hour = hour
self._minute = minute
self._second = second
@classmethod
def now(cls):
current_time = localtime(time())
return cls(current_time.tm_hour, current_time.tm_min, current_time.tm_sec)
def run(self):
"""走字"""
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24:
self._hour = 0
def showclock(self):
"""显示时钟"""
return '现在时间:{}:{}:{}'.format(self._hour, self._minute, self._second)
def main():
"""通过类方法获取时间对象"""
clock = Clock.now()
while True:
print(clock.showclock())
sleep(1)
clock.run()
if __name__ == '__main__':
main()
其实通过类访问类方法或者实例访问类方法,效果都是一样的
1.在类定义中,使用classmethod修饰的方法就叫类方法
2.类方法至少需要一个参数,且第一参数必须是cls
3.通过cls可以直接操作类的属性
静态方法
class Person:
HEIGHT = 180
@staticmethod
def static_method():
print('静态方法')
print(Person.HEIGHT)
静态方法运用
class Triangle(object):
"""
静态方法:staticmethod
1.在类中定义的方法不一定都是对象方法(供对象使用的方法)。
2.比如在创建一个三角形类时,通过传入三边来构造三角形,然后计算周长和面积
但是传入的三边不一定能够构成三角形对象,因此在构建三角形对象之前,可以先
写一个方法来判断能否构成三角形,因此这个判断方法就不是对象方法,因为这个方法
是在对象创建之前就被调用。所以这个方法是属于三角形类而不属于三角形对象。
"""
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
@staticmethod
def is_triangle(a, b, c):
if a + b > c and a + c > b and b + c > a:
return True
def premiter(self):
l = self.a + self.b + self.c
return l
def area(self): #海伦公式计算三角形面积
p = (self.a + self.b + self.c)/2
area = (p * (p - self.a)*(p - self.b)*(p - self.c))**0.5
return area
def main():
a, b, c = 3, 4, 5
if Triangle.is_triangle(a, b, c): #在此调用类的静态方法,注意要传实参
t1 = Triangle(a, b, c) #判断成功后进行实例化
print('周长为:{}'.format(t1.premiter()))
print('面积为:{}'.format(t1.area()))
else:
print('不能构成三角形')
if __name__ == '__main__':
main()
1.使用staticmethod修饰
2.调用时,不会隐式传入参数
3.通过类和实例都可以调用静态方法
访问控制
私有成员(Private)
class Person:
def __init__(self, name, age=18):
self.__name = name
self.__age = age
def __showage(self):
print(self.__age)
tom = Person('tom')
print(tom.__name) #报错
print(tom.__showage()) #报错
以双下划线开头的属性不能直接访问,因为python会隐式地改名,因此直接访问时会报错(没有这个属性),对于这些属性会在前面加上_Person这个前缀,比如,__name属性会变成_Person__name),因此若要强制访问这些属性,需要访问改名后的名称,不过不建议这样访问,因为他们是保护成员,原则上在类外部是不能直接访问的,这样就失去了封装的意义。
保护成员
class Person:
def __init__(self, name, age=18):
self._name = name
self._age = age
def _showage(self):
print(self._age)
print(Person.__dict__)
tom = Person('Tom')
print(tom.__dict__)
tom._showage() # 可以访问
print(tom._name, tom._age) # 可以访问
保护成员不是python定义的,是程序员之间约定俗成的法则,意义是让外部不要轻易访问这些成员,更不能去修改它们,这样就失去了类的初衷