动静态方法 封装 隐藏 伪装 继承

发布时间 2023-06-26 22:02:02作者: Meeeoww

动静态方法

绑定方法与非绑定方法的使用:若类中需要一个功能,该功能的实现代码中需要引用对象则将其定义成对象方法,需要引用类则将其定义成类方法,无需引用类或对象则将其定义成静态方法

动态方法(绑定方法)

绑定给对象的方法

'''
类中定义的函数默认绑定给对象方法 
对象来调用,会把对象自己当成第一个参数传给方法的第一个形参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在评分