面向对象
类的组成
类的概念
类是由N多个对象抽取出来的“像”的属性和方法从而归纳总结出来的一种类别,假如是:小王,小花,张三,他们都有各自的姓名,都能吃饭,其中小王,小花,张三是对象,姓名是属性,吃饭是行。
创建类
使用Class关键字进行创建类,多个单词的话使用驼峰命名法(eg:AbcDef)
class Students:
pass
类属性:定义在类中,方法之外的变量
class Student():
# 类属性
school="北京XX教育"
实例属性:定义在_init_方法中
class Student():
# 类属性
school="北京XX教育"
# 实例属性
def __init__(self,name,age): # age,name是参数,局部变量参数
# 赋值操作
self.name=name
self.age=age
实例方法:定义在类中的函数
class Student():
# 类属性
school="北京XX教育"
# 实例属性
def __init__(self,name,age): # age,name是参数,局部变量参数,
self.name=name # name是局部变量,self.name是实例属性
self.age=age
# 实例方法
def show(self):
print(f'我叫:{self.name},今年{self.age}岁')
静态方法:@staticmethod
class Student():
# 类属性
school="北京XX教育"
# 实例属性
def __init__(self,name,age): # age,name是参数,局部变量参数,
self.name=name # name是局部变量,self.name是实例属性
self.age=age
# 实例方法
def show(self):
print(f'我叫:{self.name},今年{self.age}岁')
# 静态方法
@staticmethod
def sm():
print('这是一个静态方法')
类方法:@classmethod
class Student():
# 类属性
school="北京XX教育"
# 实例属性
def __init__(self,name,age): # age,name是参数,局部变量参数,
self.name=name # name是局部变量,self.name是实例属性
self.age=age
# 实例方法
def show(self):
print(f'我叫:{self.name},今年{self.age}岁')
# 静态方法
@staticmethod
def sm():
print('这是一个静态方法')
# 类方法
@classmethod
def cm(cls):
print('这是一个类方法')
类的调用
创建好之后就可以对他进行调用了
调用总结:实例的需要对象名打点(.)调用;方法的需要使用类名打点(.)调用
class Student():
# 类属性
school="北京XX教育"
# 实例属性
def __init__(self,name,age): # age,name是参数,局部变量参数,
self.name=name # name是局部变量,self.name是实例属性
self.age=age
# 实例方法
def show(self):
print(f'我叫:{self.name},今年{self.age}岁')
# 静态方法
@staticmethod
def sm():
print('这是一个静态方法')
# 类方法
@classmethod
def cm(cls):
print('这是一个类方法')
# 创建一个对象
stu=Student('ym',18)
# 实例属性(对象名打点调用)
print(stu.name)
print(stu.age)
#类属性(类名打点调用)
print(Student.school)
# 实例方法(对象名打点调用)
stu.show()
# 静态方法 (类名打点调用)
Student.sm()
# 类方法(类名打点调用)
Student.cm()
注意点
其中静态方法和类方法是不可以打点调用的,像这样
运行结果
动态绑定属性和方法
动态绑定属性
class Student():
# 类属性
school="北京XX教育"
# 实例属性、初始化方法
def __init__(self,name,age): # age,name是参数,局部变量参数,
self.name=name # name是局部变量,self.name是实例属性
self.age=age
# 实例方法 定义在类里面的函数,我们叫做方法 会自带一个参数self
def show(self):
print(f'我叫:{self.name},今年{self.age}岁')
stu=Student('ym',20)
stu1=Student('ymm',22)
print(stu.name,stu.age)
print(stu1.name,stu1.age)
print('-'*20)
像这段代码,你定义了2个对象,但是加入你想给其中一个对象添加一个属性怎么办呢,在不改变实例属性的情况下,这个时候就可以用到动态绑定属性了
class Student():
# 类属性
school="北京XX教育"
# 实例属性、初始化方法
def __init__(self,name,age): # age,name是参数,局部变量参数,
self.name=name # name是局部变量,self.name是实例属性
self.age=age
# 实例方法 定义在类里面的函数,我们叫做方法 会自带一个参数self
def show(self):
print(f'我叫:{self.name},今年{self.age}岁')
stu=Student('ym',20)
stu1=Student('ymm',22)
print(stu.name,stu.age) # ym 20
print(stu1.name,stu1.age) # ymm 22
print('-'*20)
# stu.show()
# 动态绑定属性
stu.graden='优'
print(stu.name,stu.age,stu.graden) # ym 20 优
动态绑定方法
class Student():
# 类属性
school="北京XX教育"
# 实例属性、初始化方法
def __init__(self,name,age): # age,name是参数,局部变量参数,
self.name=name # name是局部变量,self.name是实例属性
self.age=age
# 实例方法 定义在类里面的函数,我们叫做方法 会自带一个参数self
def show(self):
print(f'我叫:{self.name},今年{self.age}岁')
stu=Student('ym',20)
stu1=Student('ymm',22)
print(stu.name,stu.age)
print(stu1.name,stu1.age)
print('-'*20)
# stu.show()
# 动态绑定方法
def introduce():
print('我是一个普通的函数,我被动态绑定stu1对象的方法')
stu1.fun=introduce # 注意:introduce函数不能带上小括号,带上小括号就调用了
# fun就是stu2对象的方法
stu1.fun()
# 我是一个普通的函数,我被动态绑定stu1对象的方法
权限控制(封装)
Python中的有三种不同的权限控制:
- 单下划线:以单下划线开头的属性和方法表示protected受保护的成员,这类成员被视为内部使用,允许类本身和子类进行访问,但是实际上也可以被外部访问
- 双下划线开头:表示private私有的成员,这类成员只允许定义该属性或方法1的类本身进行访问
- 首位下划线:一般表示特殊的方法
访问属性
class Students():
# 实例属性
def __init__(self,name,age,grader):
self._name=name # 允许类本身和子类进行访问,但是实际上他是可以被外部访问的
self.__age=age # 只能定义该属性进行访问
self.grader=grader # 普通属性
stu=Students('ym',20,'男')
# 访问正常属性
print(stu.grader) # 男
# 访问受保护的属性
print(stu._name) # ym
print(stu.__age) # AttributeError: 'Students' object has no attribute '__age'.
# Did you mean: '_name'?
可以看到__age是访问不成功的,因为他是私有属性,常规方法是无法访问到的
访问方法
class Students():
# 实例属性
def __init__(self,name,age,grader):
self._name=name # 允许类本身和子类进行访问,
self.__age=age # 只能定义该属性进行访问,但是通过特殊手段可以被外部访问
self.grader=grader # 普通属性
# 实例方法
def _fun1(self):
print('子类及本身可以访问')
def __fun2(self):
return ('只有定义的类可以访问')
def show(self):
print('正常的都可以访问')
stu=Students('ym',20,'男')
# 访问正常的方法
stu.show() # 正常的都可以访问
# 访问受保护的方法
stu._fun1() # 子类及本身可以访问
stu.__fun2() # AttributeError: 'Students' object has no attribute '__fun2'.
# Did you mean: '_fun1'?
可以看到__fun2也是不可以访问的
但是私有属性和方法真的不能访问吗??
# 当我们在最后加上这样一段代码就可以访问了
print(stu._Students__age) # 20
print(stu._Students__fun2()) # 只有定义的类可以访问
# 为什么呢?我们打印一个东西(可以看到只要我们对象名点具体的参数还是可以拿到私有的数据)
print(dir(stu))
#['_Students__age', '_Students__fun2', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_fun1', '_name', 'grader', 'show']
------更新线 2004年7月3日更新----------------------------------------------------------------------------------------
但是我们这样通过上面这种方法去访问是不安全的,有什么更加安全的方法吗?有!
属性的设置
属性设置就是把方法转换成实例属性来使用?使用@property修饰
class Students():
# 实例属性
def __init__(self,name,age):
self.__name=name
self.age=age
# 实例方法
# 方法转换为属性使用
@property
def show(self):
return self.__name
stu=Students('ym',20)
# 直接调用会报错
print(stu.__name) # AttributeError: 'Students' object has no attribute '__name'
# 使用修饰符@property之后调用
print('姓名是:',stu.show) # 姓名是: ym
那假如我又需要修改他的属性值怎么办呢?使用@setter修饰符
class Students():
# 实例属性
def __init__(self,name,age):
self.__name=name
self.age=age
# 实例方法
# 方法转换为属性使用
@property
def show(self):
return self.__name
stu=Students('ym',20)
# 直接调用会报错
print(stu.__name) # AttributeError: 'Students' object has no attribute '__name'
# 使用修饰符@property之后调用
print('姓名是:',stu.show) # 姓名是: ym