类与封装
- 类
- 类的简介
- 对象初始化
- 构造器方法
- 封装
- __(双下划线)与 _ (单下划线)
- property装饰器
- 总结
- 实战
类
类的简介
- 类也是一个对象!
- 类就是一个用来创建对象的对象!
- 类是type类型的对象,定义类实际上就是定义了一个type类型的对象
举例
a = int(10) # 创建一个int类的实例
b = str('hello') # 创建一个str类的实例
print(a, type(a)) # 10 <class 'int'>
print(b, type(b)) # hello <class 'str'>
使用类创建对象的流程
1.创建一个变量
2.在内存中创建一个新对象
3.将对象的id赋值给变量
class MyClass:
pass # pass表示资源占位符,在此处可写很多代码。
print(MyClass) # <class '__main__.MyClass'>表示当前的主对象就是MyClass,就是python的main函数。
mc1 = MyClass() # 等价于Java的 mc1=new MyClass()
mc2 = MyClass()
print(mc1) # <__main__.MyClass object at 0x0000022FA0717780>。
print(mc2) # <__main__.MyClass object at 0x0000021E61197780>。
这样创建不太好,改进方法:
result1 = isinstance(mc1, MyClass)
result2 = isinstance(mc1, str)
print(result1,result2) # True False
# result1、result2都是MyClass的实例,他们都是一类对象
# isinstance()用来检查一个对象是否是一个类的实例 和Java的this关键字功能一致
print(type(MyClass)) # <class 'type'> 类类型(类类型变量、类类方法、类类属性)
print(id(MyClass)) # 1687389264344
对象初始化
class Person1:
def say_hello(self): # 第二步定义方法 self表示至少带一个参数
"""
self表一个对象、属性、方法
表一个this关键字的作用,区分当前对象
可以进行封装继承多态
"""
print('大家好,我是%s'%self.name) # 字符串的格式化拼接
def __init__(self):
# 操作核心代码(包括封装继承多态)
pass
p1 = Person1() # 第三步创建对象
p1.name='zhangtao' # 赋值
# 调用方法
p1.say_hello()
# 以上赋值称为动态赋值
构造器方法
什么是封装? 就是对当前对象的属性方法隐藏起来,不让其他程序访问!
class Dog():
# 定义一个方法 带参数的构造器方法/初始化变量属性的方法
def __init__(self,name): # 此函数/方法可带无穷个参数
self.name = name # 标注name属性为当前对象的属性
# d=Dog() # 不带参构造器
d = Dog('黑狗') # 带参的
d.name='黑子' # 对象.属性() 调用属性的语法
print(d.name)
问题来了!如何隐藏name属性?
- 通过self.hidden_name = name隐藏,用户只知道hidden_name而不知道name
class Dog1():
def __init__(self , name):
self.hidden_name = name
def say_hello(self):
print('大家好,我是 %s'%self.hidden_name)
d = Dog1("dahuang")
d.say_hello()
接着获取name呢?
- 定义get_name方法获取
class Dog2():
def __init__(self , name):
self.hidden_name = name
def say_hello(self):
print('大家好,我是 %s'%self.hidden_name)
def get_name(self):
print('这是真的name的值 %s'%self.hidden_name)
d = Dog2("dahuang")
d.say_hello()
d.get_name()
然后除了最后赋值外还有哪种方法能赋值?
- 定义set_name方法
class Dog3():
def __init__(self , name):
self.hidden_name = name
def say_hello(self):
print('大家好,我是 %s'%self.hidden_name)
def get_name(self):
print('这是真的name的值 %s'%self.hidden_name)
def set_name(self, name):
self.hidden_name = name
# def __get__(self):
# print('这是真的name的值 %s' % self.hidden_name)
#
# def __set_name__(self, name): # set方法除了self外必须至少再带一个函数
# self.hidden_name=name
#
# def __set__(self, name):
# self.hidden_name = name
"""
set_name方法可以自定义(set_name)也可以利用底层写法(__set_name__)建议使用自定义的 不用调用底层太麻烦
"""
"""
get_namet方法只能自定义没有底层方法
"""
d = Dog3('heigou')
d.set_name('hei')
d.say_hello()
d.get_name()
封装
__(双下划线)与 _ (单下划线)
可以为对象的属性使用双下划线开头,_ _xxx
双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问。其实隐藏属性只不过是Python自动为属性改了一个名字。实际上是将名字修改为了,_类名__属性名 比如 _ _name -> Person _name
class Person:
def __init__(self,name):
self.__name = name
def get_name(self):
return self.__name
def set_name(self , name):
self.__name = name
p = Person('孙悟空')
print(p.__name) __开头的属性是隐藏属性,无法通过对象访问
p.__name = '猪八戒'
print(p._Person__name)
p._Person__name = '猪八戒'
print(p.get_name())
使用_ _开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
class Person:
def __init__(self,name):
self._name = name
def get_name(self):
return self._name
def set_name(self , name):
self._name = name
p = Person('孙悟空')
print(p._name)
property装饰器
property装饰器,用来将一个get方法,转换为对象的属性
添加为property装饰器以后,我们就可以像调用属性一样使用get方法
使用property装饰的方法,必须和属性名是一样的
class Person:
def __init__(self,name,age):
self._name = name
self._age = age
# property装饰器,用来将一个get方法,转换为对象的属性
# 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
# 使用property装饰的方法,必须和属性名是一样的
@property
def name(self):
print('get方法执行了~~~')
return self._name
# setter方法的装饰器:@属性名.setter
@name.setter
def name(self , name):
print('setter方法调用了')
self._name = name
@property
def age(self):
return self._age
@age.setter
def age(self , age):
self._age = age
p = Person('猪八戒',18)
p.name = '孙悟空'
p.age = 28
print(p.name,p.age)
总结
封装是面向对象的三大特性之一
封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法
如何隐藏一个对象中的属性?
- 将对象的属性名,修改为一个外部不知道的名字
如何获取(修改)对象中的属性?
- 需要提供一个getter和setter方法使外部可以访问到属性
- getter 获取对象中的指定属性(get_属性名)
- setter 用来设置对象的指定属性(set_属性名)
使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
1.隐藏了属性名,使调用者无法随意的修改对象中的属性
2.增加了getter和setter方法,很好的控制的属性是否是只读的
如果希望属性是只读的,则可以直接去掉setter方法
如果希望属性不能被外部访问,则可以直接去掉getter方法
3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
4.使用getter方法获取属性,使用setter方法设置属性
可以在读取属性和修改属性的同时做一些其他的处理
5.使用getter方法可以表示一些计算的属性
实战
狗
# 定义一个狗
class Dog4():
def __init__(self , name, age, gender, height):
self.hidden_name = name
self.hidden_age = age
self.hidden_gender = gender
self.hidden_height = height
def jiao(self):
print('大家好,我是 %s'%self.hidden_name)
def yao(self):
print('这是真的name的值 %s'%self.hidden_age)
def run(self):
print('这是真的name的值 %s' % self.hidden_gender)
矩形面积
# 定义矩形
class Rectangle:
'''
表示矩形的类
'''
def __init__(self,width,height):
self.hidden_width = width
self.hidden_height = height
def get_width(self):
return self.hidden_width
def get_height(self):
return self.hidden_height
def set_width(self , width):
self.hidden_width = width
def set_height(self , height):
self.hidden_height = height
def get_area(self):
return self.hidden_width * self.hidden_height
r = Rectangle(5,2)
print(r.get_area())
r.set_width(10)
r.set_height(20)
print(r.get_area())