绑定与非绑定方法
# 绑定方法
绑定给谁就应该由谁来 调用.谁来调用就会将谁当作第一个参数自动传入.
精髓在于 --- 自动传值
# ☆分类 self cls
1>绑定给实例化对象的方法
在类内部定义的函数(第一个参数约定俗成写为self+没有被任何装饰器修饰),通常默认就是绑定给对象用的.
反过来理解,类中没有被装饰器绑定的函数,就是绑定给实例化对象用的,对象使用时,会自动将自己传入, 所以此函数需要有一个形参来接受, 此形参约定写成self.便于区分.
有一些__开头的函数属于特殊情况... 特殊情况特殊分析
2>绑定给类的方法
在类内部定义的函数(第一个参数约定俗成写为cls)若被装饰器@classmethod装饰器装饰,
那么则是绑定给类的,应该由类来调用,会自动将类当作第一个参数自动传入
class Foo:
@classmethod
def f1(cls):
print(cls)
def f2(self):
print(self)
obj = Foo()
# -- 绑定给类的
# ★ 了解:绑定给类的应该由类来调用,但实例化对象其实也可以使用,只不过自动传入的仍然是类.
print(Foo.f1) # <bound method Foo.f1 of <class '__main__.Foo'>>
print(obj.f1) # <bound method Foo.f1 of <class '__main__.Foo'>>
Foo.f1() # <class '__main__.Foo'>
obj.f1() # <class '__main__.Foo'>
# -- 绑定给实例化对象的
print(obj.f2) # <bound method Foo.f2 of <__main__.Foo object at 0x7f90898498e0>>
print(Foo.f2) # <function Foo.f2 at 0x7f9089848b80> 普通方法 该传多少参数就传多少参数
obj.f2() # <__main__.Foo object at 0x7f90898498e0>
Foo.f2() # 报错:f2() missing 1 required positional argument: 'self'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ☆应用
若函数体代码需要用外部传入的类, 则应该将该函数定义成绑定给类的方法.
若函数体代码需要用外部传入的实例化对象, 则应该将该函数定义成绑定给对象的方法.
默认 的实例化方式: 类名( )
新的 实例化方式: 从配置文件中读取配置完成实例化!
"""
# -- setting.py
HOST = '127.0.0.1'
PORT = 3306
"""
import settings
class MySQL:
def __init__(self, host, port):
self.host = host
self.port = port
def tell_info(self):
print(f'IP地址:{self.host},端口:{self.port}')
@classmethod
def from_conf(cls):
print(cls)
return cls(settings.HOST, settings.PORT)
# conn = MySQL('127.0.0.1',3306)
conn = MySQL.from_conf()
conn.tell_info() # IP地址:127.0.0.1,端口:3306
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 非绑定方法
类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法.
既不与类绑定,又不与对象绑定, 意味着类与对象都可以来调用 但无论谁来调用, 都 没有 任何 自动传值 的效果 .. 就是一个普通函数!!
# @staticmethod
应用: 如果函数体代码既不需要外部传入的类也不需要外部传入的对象, 则应该将该函数定义成非绑定方法.
Q: 思考 => 不加@staticmethod,直接在类中定义, def func():pass
河狸吗?
A:[不合理] 还是老生常谈的一个问题,类中不加装饰器的函数默认是绑定给实例化对象使用的.
实例化对象调用func, 发现func方法没有参数接收自动传入的对象自己.
直接报错:func() takes 0 positional arguments but 1 was given
import uuid
class A:
def __init__(self):
self.uid = self.create_id()
@staticmethod
def func1(x, y):
print('这是一个非绑定方法..')
@staticmethod
def create_id():
return uuid.uuid1()
a = A()
print(a.func1) # <function A.func1 at 0x7f806805b5e0>
print(A.func1) # <function A.func1 at 0x7f806805b5e0>
a.func1(1, 2) # 这是一个非绑定方法..
A.func1(1, 2) # 这是一个非绑定方法..
"""
UUID是128位的全局唯一标识符,通常由32字节的字符串表示.它可以保证时间和空间的唯一性.
uuid1() 基于时间戳的算法
由MAC地址、当前时间戳、随机数生成. 可以保证全球范围内的唯一性
但MAC的使用同时带来安全性问题,局域网中可以使用IP来代替MAC
UUID主要有五个算法
首先,Python中没有基于DCE的,所以uuid2可以忽略;
其次,uuid4存在概率性重复,最好不用;
再次,若在Global的分布式计算环境下,最好用uuid1;
最后,若有名字的唯一性要求,最好用uuid3或uuid5.
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 体会区别
PS: 体会classmethod与staticmethod的区别
我们的意图是想触发Mariadb.__str__
,但是结果触发了MySQL.__str__
的执行.
因为返回的m是MySQ类产生的... return MySQL(settings.HOST, settings.PORT)
import settings
class MySQL:
def __init__(self, host, port):
self.host = host
self.port = port
@staticmethod
def from_conf():
return MySQL(settings.HOST, settings.PORT)
# @classmethod #哪个类来调用,就将哪个类当做第一个参数传入
# def from_conf(cls):
# return cls(settings.HOST,settings.PORT) # 哪个类来调用,即用哪个类cls来实例化
def __str__(self):
return '就不告诉你'
class Mariadb(MySQL):
# __str__方法需要返回一个字符串当做对这个实例化对象的描写
def __str__(self):
return '<%s:%s>' % (self.host, self.port)
m = Mariadb.from_conf()
print(m) #我们的意图是想触发Mariadb.__str__,但是结果触发了MySQL.__str__的执行,打印就不告诉你:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
总结绑定方法与非绑定方法的使用:
若类中需要一个功能, 该功能的实现代码中需要引用对象则将其定义成对象方法;
需要引用类则将其定义成类方法;
无需引用类或对象则将其定义成静态方法.