面向对象编程
私有属性
私有属性: 就是对象不希望公开的属性
定义方式: 在属性名前面增加两个下划线(例如:__name)
练习
- 定义类为:"人"类
- 创建对象:rose
- 初始化对象属性:name 与 age
- 要求:age 不能在类的外部访问
class People:
def __init__(self, name, age):
self.name = name
# self.age = age
self.__age = age
def print_info(self):
print(self.__age)
def get_age(self):
return self.__age
def set_age(self, new_age):
self.__age = new_age
print(f"new_age:{self.__age}")
zs = People('zs', 19)
print(zs.name)
# print(zs.age) # 在类的外部访问私有属性报错:AttributeError: 'People' object has no attribute 'age'
# 如何才能在类的外部访问私有属性?
zs.print_info() # 1.私有属性在类的内部的方法当中时可以访问的
print(zs.get_age()) # 2.在类的内部将私有属性返回出来,进行访问
zs.set_age(50) # 3.在类的外部对私有属性进行修改
需求: 一定要在类的外部访问到对象的私有属性,如何实现?
方法:
- 可以通过类的内部的方法访问私有属性
- 通过类的内部方法将私有属性返回出去
- 在类的外部调用该方法并且接收就可
私有方法
私有方法: 就是对象不希望公开的方法
定义方式: 在方法名前面增加两个下划线(例如:__test)
注意:
在 python 中,并没有真正意义上的私有,只有伪私有。当我们在访问时,以 对象 ._ 类名 __ 私有属 性
即可访问,私有方法同理。但是不建议使用。
class Demo:
def test1(self):
print('--1--')
def __test2(self):
print('--2--')
def test3(self):
return self.__test2()
d = Demo()
d.test1()
# d.__test2() # 私有方法没有办法直接在类的外部进行访问,报错:AttributeError:
d.test3() # 通过类的内部的方法去进行调用
d._Demo__test2() # 注意:可以直接通过 对象._类名__私有方法名()去访问私有方法,但是不推荐使用
知识点
成员介绍
属性
方法
面向对象编程
成员
实例属性
实例属性
属于对象
,只能通过对象访问
定义:self. 属性名称
访问:self. 属性名称 或 对象 . 属性名称
练习: 定义一个省份类,打印输出班级每位同学所在的国家与省份。
class Procince:
def __init__(self, name):
# 实例属性 self.属性名
self.country = '中国'
self.name = name
def print_info(self):
# print(self.country, self.name) # self就是对象本身访问
# print(clara.country, clara.name) # 通过每个对象 访问 可以 但不建议使用
# print(Procince.country, Procince.name) # 报错
clara = Procince('湖南')
jx = Procince('广州')
clara.print_info()
jx.print_info()
类属性 ( 静态属性 )
类属性属于类,保存在类中。在创建时,仅创建一份,并且所有对象都共享
静态属性。执行时可以是类访问也可以是对象访问。
定义: 直接在类中定义
访问: 类名 . 属性名称 或 self. 属性名称 或 对象 . 属性名称
class Province:
country = '中国'
def __init__(self, name):
self.name = name
def print_info(self):
# print(self.country, self.name) # self就是对象本身访问 类属性
# print(clara.country, clara.name) # 通过每个对象 访问 可以 但是不建议使用
print(Province.country, self.name) # 类属性,可以直接通过类名来访问
clara = Province('湖南')
jx = Province('广州')
clara.print_info()
jx.print_info()
属性总结
在实际开发中,如果属性的值是固定的,不随对象的改变而改变。那就使用
静态属性(类属性),这样有利于节省内存的消耗。而如果属性的值随对象的
改变而改变,就使用实例属性。
实例方法
普通方法保存在类中,在实例化对象后,一般通过对象调用。第一个参数必
须为系统自建参数,默认为 self,代指对象本身。
注意 :
- 当需要在方法中使用实例属性时,通常使用实例方法
- self 仅仅是变量名。使用其它也可,但最好不要修改
class Demo:
def __init__(self):
self.name = 'hlll'
# 实例方法:通常用于需要使用实例属性
def test_one(self):
# print(self)
print(self.name)
d = Demo()
d.test_one()
类方法
类方法通过在方法上面添加@classmethod
装饰器,保存在类中;
注意 :
- 类方法不需要传入self。但有一个系统自建参数为cls,cls代指类本身;
- 类方法一般通过类调用,也可通过对象调用
静态方法
静态方法通过在方法上面添加 @staticmethod
装饰器定义,保存在类中;
注意 :
- 静态方法不需要传入self参数,即使传入了self参数也并不像普通方法那样代指对象本身,
仅仅是一个普通的形参。 - 静态方法的调用虽然可以通过对象调用,但一般由类调用。
- 静态方法的参数并不代表对象这一特点,使静态方法在类中使用起来更像一个单纯的函
数。完全可以将静态方法放在类的外部,当成函数使用。但是放在类中,便于使用与维
护。
class Demo:
def __init__(self):
self.name = 'hlll'
def test_one(self):
print(self.name)
@classmethod
def cls_md(cls, age): # 自建参数不再是self,而是cls,代指类
print(cls) # <class '__main__.Demo'>
print(age)
@staticmethod
def stat_md():
print('我是静态方法')
d = Demo()
d.test_one()
d.cls_md(18)
d.stat_md()
import time
# 获取当前的时间
def show_time():
print(time.localtime()) # 返回当前的时间,元组
print(time.strftime('%Y : %m : %d',time.localtime()))
show_time()
import time
class TimeTes:
@staticmethod
def show_time():
print(time.localtime()) # 返回当前时间,元组
# 进行时间格式化
print(time.strftime('%Y : %m : %d', time.localtime()))
t = TimeTes
t.show_time()
知识点
封装
继承
多态
面向对象编程
封装介绍
封装是面向对象编程的一大特点,将属性和方法放到类的内部,通过对象访问属性或
者方法,隐藏功能的实现细节,也可以设置访问权限。
class Student:
addr = "123"
def __init__(self, name, age):
self.name = name # 将属性封装到类的内部
self.age = age
def print_info(self):
print(self.name, self.age)
# print(self.addr)
# self.addr = "222"
# print(self.addr) # 不能通过实例去修改类属性的
# print(Student.addr)
# 在同一个类创建多个对象之间,属性是互不干扰的
xn = Student("寻你", 19)
jx = Student("九夏", 29)
xn.print_info()
jx.print_info()
继承 ( 重点 )
继承是一种创建新类的方式,如果子类需要复用父类的属性或者方法时,就可以使用
继承。当然,子类也可以提供自己的属性和方法。
注意:在 python 中,新建的类可以继承一个或多个父类
继承作用:避免重复造轮子,减少代码的冗余
新式类与经典类
在 Python2 当中类分为新式类和经典类,如果有继承父类 object 则是新式类,否则
为经典类。
但是在 Python3 当中,全部都是新式类,默认继承 object。
练习:验证 Python3 中,全部都是新式类
实现思路:比较继承与无继承两个空类的成员是否一致
拓展方法:
-
对象 .__dir__()
查看对象的属性与方法
# 但是注意,在python3当中,默认的手是新式类
class Dome: # 在python2中,经典类
pass
class Dome2(object): # 继承了object,在python2中,新式类
pass
d1 = Dome()
d2 = Dome2()
print(len(d1.__dir__()))
print(len(d2. __dir__()))
单继承
子类继承父类,则可以直接享受父类中已经封装好的方法
练习:用代码实现如下
单继承
当对象调用方法时,查找顺序先从自身类找,如果自身没找到,则去父类找,父类
无,再到父类的父类找,直到object类,若还无,则报错。这也称为深度优先机制
。
单继承
需要注意的是,当子类与父类拥有同名称的方法时,子类对象调用该方法优先执行
自身的方法。那么实际上就是子类的方法覆盖父类的方法,也称为重写
。
但是实际的开发中,遵循开放封闭原则。我们并不会完全的重写父类的方法,而是
希望同时实现父类的功能。这时,我们就需要调用父类的方法了,可以通过 super()
函数实现。
super()
super(type[, object-or-type])
函数是用于调用父类(超类)的一个方法
- type --> 类
- object-or-type --> 对象或类,一般是 self
练习: 继以上练习实现,在Son的sleep方法当中,调用父类的sleep方法。
class GrandFather(object):
def sleep(self):
print('GrandFather sleep 10')
class Father(GrandFather):
def eat(self):
print('Father')
def drink(self):
print('Father drink')
class Son(Father):
def stuy_python(self):
print('Son study python')
def sleep(self):
print('Son sleep 8') # 当子类与父类名字相同的方法时,就意味着重写了父类的方法!
# 在执行自己的方法的时候 仍然继承父类的方法
super(Son, self).sleep() # Son的对象去调用父类的sleep方法
# super().sleep() # 参数不传也可以
# GrandFather.sleep(self) # 通过 类名.方法名(self)
s = Son()
s.eat()
s.sleep()
'''
1.单继承:深度优先
2.重写:
防止执行父类当中的方法
3.self永远指的是执行该方法的调用着
4.super(当前类,self).父类的发方法(arg)
'''
注意
- init方法也会继承,同实例方法一致
- 私有属性以及私有方法没有被继承
"""
__init__方法是否会被继承?也会继承,并且同实例方法一致。深度优先
"""
class Father(object):
def __init__(self):
print('Father')
class Son(Father):
pass
s = Son()
"""
私有属性与私有方法是否被继承?
"""
class Father(object):
def __init__(self):
self.name = 'amy'
self.__age = 18
def test(self):
print('test')
def __test2(self):
print('__test2')
class Son(Father):
def get_test(self):
print(self.name)
self.test()
# 注意:私有属性不会被继承
# print(self.__age)
# 注意:私有方法也不会被继承
# self.__test2()
s = Son()
# print(s.name)
# print(s.__age)
s.get_test()
"""
ü 作业 1
玩个特别无聊的游戏 , 猜数字。
玩家输入一个数字与
计算机随机生成的数字作对比
当两个值相等时 , 则说明用户猜对了
注意 : 外部不能获取到计算机随机生成的值
"""
import random
class GuessNumber:
def j_number(self):
a = input('请输入一个数字:')
n = random.randint(0, 9)
if n == a:
print('猜对了!')
else:
print('猜错了。')
c = GuessNumber()
c.j_number()
import random
class GuessNum(object):
def __init__(self):
self.__rand_num = random.randint(1, 10)
print(f'random_number:{self.__rand_num}')
def guess_it(self):
ipt_num = int(input('请输入1-10的数'))
while True:
if self.__rand_num == ipt_num:
print('猜对了')
break
else:
ipt_num = int(input('猜的不对奥,请重新输入!'))
b = GuessNum()
b.guess_it()
"""
ü 作业 2
创建一个煎饼类 调用烹饪时长的方法累计煎饼状态
如果煎的时间在 0-3 之间则状态为生的
如果煎的时间在 3-5 之间则状态为半生不熟的
如果煎的时间在 5-8 之间则状态为全熟的
当时间超过 8 分钟状态焦了
并且还可以给煎饼添加作料
比如大葱 (hhh), 大蒜 (hhh) ? , 烤肠等等
"""
class PanCate(object):
def __init__(self):
self.cake_status = '生的'
self.cake_level = 0
self.condiments = []
def __str__(self):
return f'煎饼的状态{self.cake_status},煎的时长{self.cake_level},添加的佐料{self.condiments}'
def cook(self, cooked_time):
self.cake_level += cooked_time
if self.cake_level >= 0 and self.cake_level < 3:
self.cake_status = '生的'
elif self.cake_level >= 3 and self.cake_level < 5:
self.cake_status = '半生不熟的'
elif self.cake_level >= 5 and self.cake_level < 8:
self.cake_status = '全熟的'
elif self.cake_level >= 8:
self.cake_status = '焦了'
def add_condiments(self, food):
self.condiments.append(food)
pc = PanCate()
pc.cook(1)
pc.cook(1)
pc.add_condiments('肠')
print(pc)