面向对象编程之绑定方法、掩藏属性、装饰器

一、绑定方法

1、绑定给类的方法@classmethod

class Oracle():
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

    @classmethod  # 该方法已经变成了绑定给类的方法,而不是绑定给对象了
    def from_func(cls):
        print("from func")
        return cls('127.0.0.1', '3306')

obj = Oracle('127.0.0.1', 3306)
res = obj.from_func()
print(res)
## 结果
# from func
# <__main__.Oracle object at 0x7f7c78025668>

res = Oracle.from_func()  # from func  绑定给类的方法就有类来调用,特殊之处就是:会把类名当成第一个参数传给方法的第一个形参
print(res)

注:

from_func方法使用了@classmethod装饰器,将其转变为类方法。类方法绑定给类而不是对象,意味着你可以直接通过类来调用该方法,而不需要先创建对象。

可以通过Oracle.from_func()来调用from_func方法,而不需要创建Oracle的实例。这将输出"from func"并返回一个新创建的Oracle对象。

即使将方法转换为类方法,仍然可以通过对象来调用该方法,但此时对象将被忽略,类方法将使用类本身作为参数。因此,在你的代码中,obj.from_func()仍然可以正常执行,但是它将返回一个新的Oracle对象,而不是将其赋值给res

综上所述,即使方法绑定给类,对象仍然可以调用该方法,但是类方法将忽略对象本身并使用类作为参数进行操作。

2、绑定给对象的方法(self 关键字进行的绑定)

class Student():
    school = 'sh'

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def tell_info(self):
        print('name:%s age:%s gender:%s' % (self.name, self.age, self.gender))

stu = Student('kevin', 18, 'male')
# Student.tell_info(stu)
print(stu.tell_info())

二、非绑定方法

1、不绑定给类使用,也不绑定给对象使用

@staticmethod # 该方法已经谁都不绑定,谁都能来调用,类和对象都可以直接来调用,其实就是个普通方法

class Student:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        self.id = self.get_code(5)
        self.shengfenid = self.create_id()

    @staticmethod  # 该方法已经谁都不绑定,谁都能来调用,类和对象都可以直接来调用,其实就是个普通方法
    def create_id():
        import uuid
        return uuid.uuid4()

    """什么时候使用静态方法:一般就是方法里面既不用对象,也不用类的时候就使用静态方法"""
    @staticmethod
    def get_code(n):
        code = ''
        import random
        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_int, random_upper, random_lower])
            code += temp
        return code

# 实例化一个对象,调用id和shengfenid
stu = Student('kevin', 19, 'female')
print(stu.id)
print(stu.shengfenid)

# 类在外部调用方法
print(Student.create_id())
print(Student.get_code(5))

2、如果说方法里面既用到了对象,又用到了类,方法绑定给对象更合适

    # 绑定给对象
    def func(self):
        print(self)
        print(self.__class__)
        print(self.__class__.__name__)

stu = Student('kevin', 19, 'female')
stu.func()
# <__main__.Student object at 0x7f7a680ed438>
# <class '__main__.Student'>
# Student

三、掩藏属性 

1、为什么隐藏

在Python类中,属性可以被隐藏或封装起来,这意味着属性在类外部是不可直接访问的。

隐藏属性的目的是为了封装类的内部实现细节,提供对外部代码的界面,并增加类的灵活性和安全性。以下是隐藏属性的几个主要原因:

  • 封装实现细节:

隐藏属性允许类隐藏其内部数据和实现细节,将其视为类的私有信息。这样,类的用户只能通过提供的公共方法来与类进行交互,而不需要了解类的内部实现。隐藏属性帮助实现了类的封装特性,将数据和方法进行组织和封装。

  • 访问控制:

隐藏属性可以限制属性的访问范围,防止直接对属性进行修改或读取。通过定义公共方法(例如getter和setter方法),可以控制对属性的访问和修改方式。这提供了更精确的控制,防止无效或意外的访问,确保属性的合法操作和一致性。

  • 类的演变和维护:

隐藏属性提供了类的灵活性,允许在不破坏外部代码的情况下修改类的内部实现。如果类的内部实现发生了变化,例如属性名称或数据结构的改变,隐藏属性可以使这些变化局限在类内部,而不影响外部代码。这种封装性有助于保持类的稳定性和可维护性。

  • 安全性:

隐藏属性可以增加类的安全性,防止对属性的未经授权的修改或读取。通过将属性限制为私有,外部代码无法直接访问和修改属性,只能通过类提供的公共方法来进行操作。这提供了一种控制和保护类数据的机制,减少了意外错误和滥用的风险。

⚠️:

1. 隐藏属性在类的定义阶段,发生了变形,_类名__属性名
2. 不但可以隐藏类属性、方法、对象的属性都可以隐藏
3. 隐藏属性对外不对内,对类的外部是隐藏的,而对类的内部是开放的

2、通过➕ '__' 进行掩藏

class Student():
    # '_Student__school': 'SH' _类名__属性名: 'SH'
    # school = 'SH'  # 把school属性已经隐藏了,隐藏的意思是,在类外部不能使用了
    __country = 'China'

    def __init__(self, name, age, gender):
        self.__name = name  # _Student__name
        self.age = age
        self.gender = gender

    def __func(self):  # _Student__func  _类名__函数名
        print('from func')

    def get_country(self):
        return self.__country

    def set_country(self, v):
        if type(v) is not str:
            return
        Student.__country = v

stu = Student('kevin', 19, 'male')

通过查看类的名称空间可以发现掩藏后的属性、方法改为 _类名__属性名的形式

# 查看类的名称空间
print(Student.__dict__)

由于隐藏属性是对外不对内的,所以,我们要想在类的外部使用,就需要在类的内部开放一个接口,返回隐藏属性的值,以便更好的对外做限制

如下:

def get_country(self):
    return self.__country

def set_country(self, v):
    if type(v) is not str:
        return
    Student.__country = v

四、property装饰器

作用:就是把方法伪装成属性来使用!

class Student:
    __country = 'China'
    __city = 'shanghai'

    def __init__(self, name, age, gender):
        self.__name = name  # _Student__name
        self.age = age
        self.gender = gender

    @property  # 装饰器将方法伪装成属性
    def country(self):
        return self.__country

    @country.setter    # 修改功能装饰器,.setter前的名字要与property下的函数同名
    def country(self, v):
        if type(v) is not str:  # 类型判断
            return
        Student.__country = v

    @country.deleter  # 删除功能装饰器,.deleter前的名字要与property下的函数同名
    def country(self):
        print("可以删除了")
        del Student.__country

    @property
    def city(self):
        return self.__city

    @city.setter
    def city(self, v):
        Student.__city = v

    @city.deleter
    def city(self):
        print("可以删除了")
        del Student.__city

stu = Student("kevin", 20, 'female')

# print(stu.get_country())
print(stu.country)  # 使用装饰器后,直接像调用属性一样调用方法
# stu.set_country('Japan')
stu.country = '澳大利亚'
print(stu.country)
# del Student.country
# del stu.country

另一种写法:

class Student():
    __country = 'China'
    __city = 'shanghai'

    def __init__(self, name, age, gender):
        self.__name = name  # _Student__name
        self.age = age
        self.gender = gender

    def get_country(self):
        return self.__country

    def set_country(self, v):
        if type(v) is not str:
            return
        Student.__country = v

    def del_country(self):
        print("可以删除了")
        del Student.__country
    """这种方式,是有顺序要求的"""
    country = property(get_country, set_country, del_country)

stu = Student("kevin", 19, 'male')
print(stu.country)
#
stu.country = 'Japan'
# print(stu.a)
#
del stu.country

小应用:求bmi指数

class Bmi():
    def __init__(self, weight, height):
        self.weight = weight
        self.height = height

    @property  # 装饰器伪装以后,函数可当作属性调用
    def bmi(self):
        return self.weight / (self.height ** 2)

my_bmi = Bmi(70, 1.82)
print(my_bmi.bmi)

 

 

 

  

 

posted @ 2023-06-26 15:34  凡人半睁眼  阅读(44)  评论(0编辑  收藏  举报