面向对象之绑定方法与非绑定方法
一、类中函数的分类
类中定义的函数分为两大类,分别是绑定方法和非绑定方法。
二、绑定方法
1、定义:绑定给谁,谁来调用就自动将它本身当作第一个参数传入。
2、绑定到类的方法:用classmethod装饰器装饰的方法,是一种为类量身定制的方法。
使用方法:类名.boud_method(),自动将类当作第一个参数传入(对象也可调用,但类仍被当作第一个参数自动传入)
如:
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
class Func:
def __init__(self,name):
self.name = name
@classmethod # 绑定到类的方法,一般由类调用
def func1(cls):
print(cls,"类调用")
Func.func1() #输出: <class '__main__.Func'> 类调用
obj = Func.func1() # 实例化对象
obj.func1() # 对象也可调用,但是默认传的参数仍然是类
3、绑定到对象的方法:没有被任何装饰器修施的方法,为对象量身定制。
使用方法:对象.boud_method() ,自动将对象当作第一个参数传入
如:
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
class Func:
def __init__(self,name):
self.name = name
def tell(self) # 绑定到对象的方法,仅由对象来调用
print("姓名是:%s,由对象%f调用"%self.name)
func = Func('cc') # 实例化一个对象
func.tell() # 输出:姓名是cc,由对象调用
# Func.tell() # 类调用时报错,故绑定到对象的方法只能由对象来调用
三、非绑定方法
1、定义:不与类或对象绑定,类和对象都可以调用,但是没有自动传值一说,简言之,非绑定方法就是一个普通工具。
注意:要与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器修饰的,就是绑定到对象的方法,不是普通函数,能够自动传值;而staticmethod装饰的方法,任谁调用,都没有自动传值。
2、使用方法:对象/类.method(),全部参数都需要手动传入
如:
#!/usr/bin/env python3 #-*- coding:utf-8 -*- class Func: def __init__(self): self.name = name @staticmethod # 非绑定方法,类和对象均可带调用,无自动传值 def func2(a,b): print('类或对象均可',a+b)
func.func2(5,6) # 输出:11 类与对象均可
Func.func2(4,7) # 输出:11 类与对象均可
四、classmethod 和 staticmethod 的对比
# settings.py
name = 'cc'
age = 21
male = 'male'
DB_PATH = 'D:\pycharm\Test1\Thrid_module\面向对象编程
# test.py
import settings
import settings
class Introduce:
def __init__(self,name,age):
self.name = name
self.age = age
@staticmethod
def intro_yourself():
return Introduce(settings.name,settings.age)
@classmethod # 哪个类来调用,就将那个类当作第一个参数传入
def tell_others(cls):
return cls(settings.name,settings.age)
def __str__(self):
return 'Your power is not enough!'
class Test(Introduce):
def __str__(self):
return '<%s,%s>'%(self.name,self,age)
per1 = Test.intro_yourself()
print(per1) # 输出:Your power is not enough! # 原本想触发Test.__str__执行,但结果是触发了Introduce.__str__的执行。
per2 = Test.tell_others()
print(per2) # 输出: <cc,21>
五、三种方法的综合使用
class People:
def __init__(self,name,age,sex):
self.id = self.set_id()
self.name = name
self.age = age
self.sex = sex
def tell_info(self): # 绑定到对象的方法
print('姓名:%s' '年龄:%s' '性别:%s'%(self.name, self.age, self.sex))
@classmethod # 绑定到类的方法
def from_class(cls):
obj = cls(
settings.name,
settings.age,
settings.sex
)
return obj
@staticmethod # 静态方法,非绑定方法
def set_id():
m = hashlib.md5(str(time.time()).encode('utf-8'))
return m.hexdigest()
#p = People('sc',20,'male')
# 绑定到对象,就应该由对象来调用,自动将对象本身当作第一个参数传入
#p.tell_info() #姓名:sc年龄:20性别:male
# 绑定给类,就应该由类来调用,自动将类本身当作第一个参数传入
#p = People.from_class() # 等同于People.from_class(People)
#print(p.tell_info()) # 姓名:cc年龄:21性别:male
# 非绑定方法,不与类或对象绑定,谁都可以调用,没有自动传值一说
p1 = People('sc1',20,'male')
p2 = People('SC2',21,'MALE')
p3 = People('Sc3',22,'Male')
六、绑定方法与非绑定方法的练习
要求:
1.对象有id、host、port三个属性
2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一
3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化
4.为对象定制方法,save和get_obj_by_id,save能自动将对象序列化到文件中,文件路径为配置文件中DB_PATH,文件名为id号,保存之前验证对象是否已经存在,若存在则抛出异常,;get_obj_by_id方法用来从文件中反序列化出对象。
#settings.py HOST = '127.0.0.1' PORT = 3302 DB_PATH = 'D:\pycharm\Test1\Thrid_module\面向对象编程\Test\db' # test.py import settings import hashlib import time import os import pickle class Mysql: def __init__(self,host,port): self.id = self.creat_id() self.host = host self.port = port @staticmethod def creat_id(): m = hashlib.md5(str(time.time()).encode('utf-8')) return m.hexdigest() def save(self): '''自动将对象序列化到文件中,路径为DB_PATH,文件名为id号''' try: if not isinstance(self,str): with open(os.path.join(settings.DB_PATH,self.id),'wb') as f: pickle.dump(self,f) except Exception as e: print('error',e) def get_obj_by_id(self): try: if os.path.isfile(os.path.join(settings.DB_PATH,self.id)): with open(os.path.join(settings.DB_PATH,self.id),'rb') as f: data = pickle.load(self,f) return data except Exception as e: print('error',e) def bound1(self): return Mysql(self.host,self.port) @classmethod def bound2(cls): return cls(settings.Host,settings.PORT) obj1 = Mysql('127.0.0.1',6666) print(obj1) obj2 = Mysql.creat_id() print(obj2)