动静态方法
绑定方法与非绑定方法的使用:若类中需要一个功能,该功能的实现代码中需要引用对象则将其定义成对象方法,需要引用类则将其定义成类方法,无需引用类或对象则将其定义成静态方法
动态方法(绑定方法)
绑定给对象的方法
'''
类中定义的函数默认绑定给对象方法
对象来调用,会把对象自己当成第一个参数传给方法的第一个形参self
类来调用绑定给对象的方法:类名来调用有几个参数填几个参数
'''
class Studen:
school_name='清华'#属性公共数据
def __init__(self,name,age,gender):# 初始化方法,当类被加括号调用的时候,会自动触发这个函数的执行
self.name=name
self.age=age
self.gender=gender
#下面函数为绑定给对象的方法
def choice_course(self):#对象调用第一个参数自动传入对象自己
print(f'学生{self.name}正在选课')
stu=Studen('jack',16,'male')
print(stu.__dict__)#{'name': 'jack', 'age': 16, 'gender': 'male'}
stu.choice_course()#学生jack正在选课#对象调用会自动将对象自己当第一个参数传入
class Student():
school_name='清华'
def choice_course(self):
print('对象的方法')
Student.choice_course(123)#对象的方法#类来调用绑定给对象的方法有几个参数填几个参数包括形参self,这里随便填个参数
绑定给类的方法
'''
被@classmethod修饰的函数默认绑定给类的方法
类调用会把类名当成第一个参数传给方法的第一个形参cls
对象调用会自动将产生该对象的类当成第一个参数传入
'''
class Student():
school_name='清华'
@classmethod#此时,该方法已经绑定给了类,而不是对象的方法
def func(cls):#cls:类名
print('猜猜猜',cls)
Student.func()#猜猜猜 <class '__main__.Student'>
#类来调用相当于把自身当成第一个参数传入func(Student)
obj=Student()
obj.func()#猜猜猜 <class '__main__.Student'>
#对象调用会自动将产生该对象的类当成第一个参数传入func(Student)
- 例
class Mysql():
port = 3306
ip = '127.0.0.1'
@classmethod
def from_func(cls):
return f'ip:{cls.ip} port:{cls.port}'
res=Mysql.from_func()#调用函数
print(res)#ip:127.0.0.1 port:3306
- 例
#settings.py:
ip=3306
port='127.0.0.1'
#run.py:
import settings
class Mysql():
def __init__(self,ip,port):
self.ip=ip
self.port=port
@classmethod
def from_func(cls):
return cls(settings.ip,settings.port)#实例化对象
res=Mysql.from_func()#调用函数
print(res)#<__main__.Mysql object at 0x000002962A9891C0>
print(res.port,res.ip)#127.0.0.1 3306
静态方法(非绑定方法)
'''
为类中某个函数加上装饰器@staticmethod后,该函数就变成了非绑定方法,也称为静态方法
,该方法不绑定给对象,也不绑定给类,无论是类还是对象调用它就是一个普通函数,因而没有自动传值,函数有几个参数则调用时就需要传对应数量的参数
'''
class Student():
def __init__(self, name, age):
self.name = name
self.age = age
self.id = self.get_id()#调用get_id函数,此时self为调用者或是对象或是类,具体看谁调用
@staticmethod#该方法为静态方法,既不绑定给对象也不绑定给类
def get_id():
import uuid
return uuid.uuid4()
stu=Student('kevin',19)
print(stu.id)#8f93dbc3-825b-4cb6-8a79-77c1220c71eb
print(stu.create_id())#4906415d-bfda-455a-8171-09e9b7195192
print(Student.create_id())#637c5403-88fe-405d-ae77-05e4b574dd0e
- 例
import random
class Users():
def __init__(self,name,password):
self.name=name
self.password=password
@staticmethod
def get_code(n):
code=''
for i in range(n):
random_int = str(random.randint(0, 9))
random_upper = chr(random.randint(65, 90))
random_lower = chr(random.randint(97, 122))
temp =random.choice([random_lower,random_upper,random_int])
code +=temp
return code
user=Users('kevin',123)
print(user.get_code(5))#KM4mR,调用被静态方法修饰的函数对象则需要传参
print(Users.get_code(4))#Rn1F,调用被静态方法修饰的函数类也需要传参
'''如果方法里面用到了对象,又用到了类,最好绑定给对象'''
# 如何通过对象得到这个对象的类:
print(self.__class__)
cls = self.__class__ # cls = Student
三大特征之封装
封装:即将某些部分隐藏起来,在程序外部看不到,其含义是其他程序无法调用
隐藏:将数据和功能隐藏起来,不让用户直接调用,而是开放一些接口间接调用,从而在接口中添加额外的操作
作用:保护数据安全性、提高代码复用性、降低耦合度等
在Python中,我们可以通过以下方式来实现封装:
1.在类定义阶段,使用__对属性或方法进行命名,以表示其为私有属性或私有方法,仅允许在类内部使用。
2.使用@property装饰器将类的方法转换为只读属性。
3.使用setter和getter函数对类的属性进行封装。
隐藏属性
将数据和功能隐藏起来,不让用户直接调用,而是开放一些接口间接调用,从而在接口中添加额外的操作
如何隐藏属性
'''
1. 在类定义阶段,名字前面有__那么该名字就被隐藏起来,无法直接访问(本质上隐藏属性发生了变形:_类名__属性名\方法名),通过类名\对象名._类名__数据功能名才能访问
2. 隐藏属性既可以隐藏类属性、类(对象)方法、对象属性
3. 隐藏对外不对内,在类的内部没有隐藏,通过正常的调用方法来调用即可
'''
class Myclass:
school_name='清华'
#python变量的命名数字、字母、下划线任意的组合
_='嘿嘿嘿'
_name='tony'
__age=18#__开头的变量名无法直接访问
def __init__(self,name,age):
self.__name=name#对象属性也可以拥有隐藏的属性
self.__age=age
def __choice_course(self):#变量名前面加两个__那么该名字就被隐藏起来
print('baby正在选课')
def get_info(self):
self.__choice_course()#在类体代码中直接可以使用隐藏的名字
print(Myclass._Myclass__age)#18 访问隐藏的数据
Myclass.__hobby='music'
print(Myclass.__hobby)#music
obj =Myclass()
obj.get_info()#baby正在选课
obj.__addr='上海'
print(obj.__addr)#上海
'''在类调用阶段给类添加属性给对象增加数据的方式,使用__是无法隐藏的,依然可以得到结果,只有在类定义阶段名字加__才能被隐藏'''
开放接口
'''
由于隐藏属性是对外不对内的,我们要在内部开放一个接口来返回类内部被隐藏的属性,可以更好的对外做限制
'''
class Person:
def __init__(self,name,age,hobby):
self.__name=name#对象也可以拥有隐藏的属性
self.__age=age
self.__hobby=hobby
def get_info(self):
#类体代码中可以直接使用隐藏的名字
print(f"""
姓名:{self.__name}
年龄:{self.__age}
爱好:{self.__hobby}
""")
#隐藏的属性让用户无法直接修改名字,这里我们可以做些额外的限制开放修改的接口。可以自定义很多功能,例如:
def set_name(self,new_name):
if len(new_name)==0:
raise ValueError('名字不能为空')
if new_name.isdigit():
raise ValueError('名字不能是数字')
self.__name=new_name
obj=Person('jason',18,'read')
obj.get_info()
#输出结果
#姓名:jason
#年龄:18
#爱好:read
obj.set_name('')#抛出异常ValueError: 名字不能为空
obj.set_name('tony')
obj.get_info()
#输出结果
#姓名:tony
#年龄:18
#爱好:read
- 例
#要求修改国名
class Student():
__country='CHN'
def __init__(self,name,age):
self.name=name
self.age=age
def set_country(self,country_name):
if not isinstance(country_name,str) or not country_name.isalpha():#isinstance判断数据类型、isalpha判断是否字母
print('格式错误')
return
Student.__country=country_name#修改属性
def get_country(self):
return self.__country
stu=Student('kevin',18)
stu.set_country('1')
print(stu.get_country())#格式错误&CHN
stu.set_country('China')
print(stu.get_country())#China
伪装property装饰器
伪装:把类里面的方法伪装成类里面的属性
如何伪装:被@property修饰的方法就变成伪装属性
@property把方法伪装成属性之后,以后再调用方法的时候,就不用加括号了,只需要对象点属性名即可
eg:
class C:
def func(self):pass
obj=C()
obj.func()#没被伪装调用方法
obj.func#经过伪装的调用方法
- 伪装方式一
'''
因被@property修饰的方法对象无法进行修改删除,若想删除修改则需要额外在删除修改的函数方法上添加以下装饰器
修改:@被伪装属性的方法名.setter
删除:@被伪装属性的方法名.deleter
'''
class Student():
__country = 'CHINA'
__city = 'Shanghai'
def __init__(self, name, age):
self.__name = name # _Student__name
self.age = age
@property # 把方法伪装成属性来使用
def country(self):
return self.__country
@country.setter # 修改的
def country(self, country_name):
if not type(country_name) is str:
return
Student.__country = country_name
@country.deleter # 删除的
def country(self):
del Student.__country
stu=Student('KEVIN',19)
print(stu.country)#CHINA,伪装后通过访问属性方式调用函数,
stu.country='china'#修改
print(stu.country)#china
del stu.country#删除成功
- 伪装方式二
"""这种方式,是有顺序要求的,必须是以获取>设置>删除为顺序"""
class Student():
__country = 'China'
__city = 'shanghai'
def __init__(self, name, age):
self.__name = name # _Student__name
self.age = age
def get_country(self):
return self.__country
def set_country(self,country_name):
if not isinstance(country_name,str) or not country_name.isalpha():
print('格式有误')
return
Student.__country=country_name
def del_country(self):
del Student.__country
print('删除成功')
country = property(get_country, set_country, del_country)#必须按照此顺序书写
stu=Student('KEVIN',18)
print(stu.country)#China
stu.country='1'
print(stu.country)#格式有误&China
del stu.country #删除成功
- 例
class Bmi():
def __init__(self, weight, height):
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / self.height ** 2
stu = Bmi(70, 1.8)
# print(stu.get_bmi())添加property前调用方法
print(stu.bmi) # 添加property后调用方法,伪装成属性访问方法
三大特征之继承
"""
1. 什么是继承?
继承就是新建类的一种方式,新建出来的类被称为子类或者派生类,被继承的类称为父类或者基类
子类可以继承父类的所有属性和方法
2. 为什么要用继承?
类:解决了对象与对象之间的代码冗余问题
继承:解决了类与类之间的代码冗余问题
子类就拥有了父类的所有数据和方法
3. 怎么使用继承?
经典类:没有继承object类的子子孙孙类都是经典类
新式类:继承了object类的子子孙孙类都是新式类
只有在python2中才区分经典类和新式类,在python3中,全部都是新式类
1. 在子类括号里面写上继承的父类名字,括号内可以写多个继承的父类
2. 子类可以遗传父类的所有属性和方法
3. 子类继承父类之后,可以使用父类的所有方法和属性,父类不能使用子类的
4. 查看继承的类
print(类名.__bases__)
5. 继承后对象属性查找顺序
对象自身>产生对象的类>产生对象的类所继承的类
"""
- 例
class Student():
school='SH'
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
def course(self):
print(f'{self.name}在选课')
class Teacher():
school='SH'
def __init__(self,name,age,gender,level):
self.name=name
self.age=age
self.gender=gender
self.level=level
def score(self):
print(f'{self.name}在评分'
# 上述代码太过冗余,继承则能解决类之间代码冗余问题
class People():#定义父类,子类相似属性代码都写到父类中,用来给子类继承;
school='SH'
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
class Student(People):
def __init__(self, name, age, gender):
People.__init__(self, name, age, gender)
def course(self):
return f'{self.name}在选课'
class Teacher(People):
def __init__(self,name,age,gender,level):
People.__init__(self, name, age, gender)
self.level=level
def score(self):
return f'{self.name}在评分'
stu=Student('KEVIN',18,'MALE')
print(stu.course())#KEVIN在选课
teacher=Teacher('tony',38,'MALE',10)
print(teacher.score())#tony在评分