绑定方法与非绑定方法


类中定义的函数分为两大类:绑定方法和非绑定方法

​ 其中绑定方法又分为绑定到对象的对象方法和绑定到类的类方法。

​ 在类中正常定义的函数默认是绑定到对象的,而为某个函数加上装饰器@classmethod后,该函数就绑定到了类

绑定方法

1.绑定给对象的方法

类中直接定义的函数,默认绑定给对象,类调用有几个参数传几个参数,对象调用第一个参数就是对象自身

绑定给对象的方法:
1.定义时函数内部第一个参数写self,
2.函数内部使用对象名.属性名
3.调用时,使用对象.方法名来调用
4.特殊之处在于,对象来调用会把对象自己当成第一个参数自动传给方法的第一个形参
5.之后有几个参数传几个参数就可以了

之前学习的__init__初始化方法就是绑定给对象的方法

class Student():
    school = 'SH'  # 定义一个属性

    # 初始化方法
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        
stu = Student('kevin', 20, 'male')  

print(stu.name)
print(stu.age)
print(stu.gender) 
class Student():
    school = 'SH'  # 定义一个属性

    # 初始化方法
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    '''这种方法就是绑定给对象的方法,绑定给对象的方法就由对象来调用'''
    
    def tell_info(self):
        # self => stu
        # name:kevin, age:20, gender:male
        print('name:%s, age:%s, gender:%s' % (self.name, self.age, self.gender))
        # pass
stu = Student('kevin', 20, 'male')

'''特殊之处:在于对象来调用会把对象自己当成第一个参数自动传给方法的第一个形参。
定义函数中的形参self一定不能省略,省略后对象自己这个位置实参就没有形参来接收,会报错'''
stu.tell_info()  # stu.tell_info(stu)
stu1.tell_info() # stu1.tell_info(stu1)

打印绑定对象的方法地址

print(stu.tell_info)  # <bound method Student.tell_info of <__main__.Student object at 0x000002A9D53DD400>>

# 与函数的内存地址的区别
def index():
    pass
print(index)  # <function index at 0x000001BEA11C2400>

还可以在方法里面加入参数:

# 1.2 绑定给对象的方法,加参数
class Student():
    school = 'SH'

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    
    '''这种方法就是绑定给对象的方法,绑定给对象的方法就由对象来调用'''	
    def tell_info(self, username, password):
        # self => stu
        # self => stu1
        print('name:%s, age:%s, gender:%s, username:%s, password:%s' % (self.name, self.age, self.gender, username, password))
'''name,age,gender三个是对象的属性
username、password是函数的形参'''      

stu = Student('kevin', 20, 'male')
stu1 = Student('kevin1', 21, 'male')

# print(stu.name)
# print(stu.age)
# print(stu.gender)

stu.tell_info('kevin', 123)  
stu1.tell_info('kevin1', 1234) 

绑定给对象的方法,就直接用对象来调用。但是可不可以用类来调用呢?

可以调用
但是方法里面有几个参数就要传几个参数,包括self自己

2.绑定给类的方法

被@classmethod修饰的函数:默认绑定给类,类调用第一个参数就是类自身,对象也可以调用并且会自动将产生该对象的类当做第一个参数传入

绑定给类的方法:
1.定义函数时加一个内置装饰器:classmethod
2.函数内部第一个参数使用cls
3.调用时,用类.函数名()来调用
4.特殊之处在于,把类名当成第一个参数传给方法的第一个形参
5.之后有几个参数传几个参数就可以了
class Mysql():	
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

    @classmethod  # 内置的装饰器,from_func绑定给类了,类来调用
    def from_func(cls):
        print(cls)  # <class '__main__.Mysql'>
        return cls('127.0.0.1', 3306)

obj = Mysql('127.0.0.1', 3306)
'''绑定给类的方法,类来调用,特殊之处在于:把类名当成第一个参数传给方法的第一个形参'''
Mysql.from_func()  # Mysql.from_func(Mysql)

# obj.from_func()  # Mysql.from_func(Mysql)
# 对象也可以调用,但使用了绑定给类的方法,就不要用对象来调用了

print(Mysql.from_func)  # 绑定给类方法的内存地址
# <bound method Mysql.from_func of <class '__main__.Mysql'>>

非绑定方法

3.静态方法

为类中某个函数加上装饰器@staticmethod后,该函数就变成了非绑定方法,也称为静态方法。该方法不与类或对象绑定,类与对象都可以来调用它,但它就是一个普通函数而已,因而没有自动传值那么一说

普通方法:(即不绑定给对象,也不绑定给类)
1.定义函数时加一个内置装饰器:staticmethod
2.这样函数内部就不需要参数了(原来需要一个参数来接收对象名或者类名)
3.函数定义初始化__init__中使用self.方法名(),赋值给对象属性
class Student():
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.id = self.get_id()

    @staticmethod  # 不绑定给对象,也不绑定给类,普通方法了
    def get_id():
        import uuid
        return uuid.uuid4()

stu = Student('kevin', 20)
print(stu.id)
# 不绑定方法,谁来调用都行,内部不会传参数了
print(stu.get_id())
print(Student.get_id())

4.方法里面既用到了对象,又用到了类

方法中即用到了对象又用到了类:
1.把方法绑定给对象
2.定义函数时,第一个参数是self
3.通过对象得到类:cls = self.__class__
4.之后想要使用类属性,就通过cls.属性名
class Student():
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def index(self):
        '''如果方法里面用到了对象,又用到了类,最好绑定给对象'''
        # 如何通过对象得到这个对象的类呢
        print(self.__class__)  # <class '__main__.Student'>
        cls = self.__class__  # cls = Student
        # 后面用到类,直接使用cls就可以
        
stu = Student('kevin', 20)
stu.index()
print(Student)  # <class '__main__.Student'>  # 与上面一样

练习

我们可以写一个例子练习上述方法,比如类内部定义一个随机数

拓展生成随机数:uuid模块

import uuid
'''生成随机数,只要长度固定(128),理论上一定会存在重复的可能'''
print(uuid.uuid4())
# > 43e0afc5-70b1-4498-a94f-4c19630422dd
print(type(uuid.uuid4()))
# > <class 'uuid.UUID'>

内部定义方法

class Student():
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.id = self.get_id()

    @staticmethod  # 不绑定给对象,也不绑定给类,普通方法了
    def get_id():
        import uuid
        return uuid.uuid4()

    def get_random(self, n):  # 绑定给对象了
        import random
        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_int, random_lower, random_upper, str(self.get_id())])
            code += temp
        return code


stu = Student('kevin', 20)
code1 = stu.get_id()
code2 = Student.get_id()
print(code1)
print(code2)
rand = stu.get_random(6)
print(rand)  # 5784TM
posted @ 2023-03-25 20:06  星空看海  阅读(61)  评论(0编辑  收藏  举报