python之路_面向对象相关知识点
1、方法与函数的区别?
''' class Foo(object): def __init__(self): self.name = 'alex' def func(self): print(self.name) from types import FunctionType,MethodType obj = Foo() print(isinstance(obj.func,FunctionType)) # False print(isinstance(obj.func,MethodType)) # True print(isinstance(Foo.func,FunctionType)) # True print(isinstance(Foo.func,MethodType)) # False 注意: 方法,无需传入self参数;函数,必须手动传入self参数 '''
2、models对象相关查询
''' 例:model.UserInfo为models类 ''' #(1)获取models类所在app名:model.UserInfo._meta.app_label #(2)获取models类的类名小写:model.UserInfo._meta.model_name #(3)获取models类中的字段内容:model.UserInfo._meta.get_field('username') #(4)获models类中字段的verbose_name:model.UserInfo._meta.get_field('username').verbose_name
3、用type创建类的实现
'''type创建TestModelForm类,参数分别为类名,继承类,类中属性'''
meta = type('Meta',(object,),{'model':self.model_class,'fields':'__all__'}) TestModelForm = type('TestModelForm',(ModelForm,),{'Meta':meta}) #等价于 class TestModelForm(ModelForm): class Meta: model = self.model_class fields = "__all__"
4、反向生成url
#示例如下:namespace为名称空间,name为url别名
reverse("namespace:name")
5、instance与type区别
有这样一个错误说法:isinstance用于判断,对象是否是指定类的实例,具体情况见下实例:
class Foo(object): pass class Bar(Foo): pass obj = Bar() print(isinstance(obj,Foo)) #True print(isinstance(obj,Bar)) #True
所以结论是:isinstance用于判断对象是否是指定类或其派生类的实例,如果需要排除派生类的情况,我们就不能用instance进行实例判断,为了实现这种,就需要使用type进行判断了。示例如下:
print(type(obj) == Bar) #True print(type(obj) == Foo) #False
6、面向对象中的反射相关
在django中,配置文件中中间件的配置方式如下,其实配置的就是不同中间模块的路径。我们可能好奇,这样的字符串形式的配置,内部是如何读取到相应模块中的内容的呢?
通过源码我们发现,其主要也是通过反射实现的,见如下实例:
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
有这样一个setting.py文件,配置了某类的路径:
DB_PATH = "db.sqlserver.SqlServerHelper"
获得SqlServerHelper类,并执行其中相关方法:
from settings import DB_PATH def func(): # DB_PATH = "db.mysql.MySQLHelper" module_path,cls_name = DB_PATH.rsplit('.',maxsplit=1) # 以字符串的形式导入模块 import importlib module_obj = importlib.import_module(module_path) # 去模块中导入类 cls = getattr(module_obj,cls_name) # 类实例化 obj = cls() obj.fetchone() if __name__ == '__main__': func()
还有这样一个实例:根据方法名,去实例对象中获得该方法。
class Foo(object): def func(self): pass obj = Foo() name = "func" fc = getattr(obj,name) fc()
7、面向对象封装数据相关
有这样一个应用,我们需要将models对象中相应的部分字段信息传给后端,我们相当的数据类型可能是:[{},{},{}.....],其中字典中为每个字段的相应信息。这样做没有问题,但是当我们需要的数据不但不含字段的直接信息,还要包含根据字段获得其他间接数据。这样的话,上述方式就比较难做到。此时我们就可以借助面向对象的封装特性,将数据封装到类中,间接数据的获得可以在类中的方法实现,最终只需将实例化的类对象发给后端就可以。具体实例如下:
#封装数据的类 class FilterOption(object): def __init__(self,field_name,multi=False,condition=None,is_choice=False): """ :param field_name: 字段 :param multi: 是否多选 :param condition: 显示数据的筛选条件 :param is_choice: 是否是choice """ self.field_name = field_name self.multi = multi self.is_choice = is_choice self.condition = condition def get_queryset(self,_field): if self.condition: return _field.rel.to.objects.filter(**self.condition) return _field.rel.to.objects.all() def get_choices(self,_field): return _field.choices
#发送的数据形式: comb_filter = [ FilterOption('gender',is_choice=True), FilterOption('depart',condition={'id__gt':3}), FilterOption('roles',True), ]
如上,通过循环列表,通过实例对象就可以获得封装到类中的所有数据。
8、两个对象相加(__add__)
class Foo(object): def __init__(self,age): self.age = age def __add__(self, other): return self.age + other.age # return Foo(self.age + other.age) obj1 = Foo(19) obj2 = Foo(18) obj3 = obj1 + obj2 print(obj3)
9、类中的方法约束
有这样的情况,我们需要规定多个类中,每一个类中都要一个相同的方法。如何实现这样的约束呢?有两种方式,如下。说明:如下实例要求所有写的类中必须要有send方法,如果没有该方法时,实例化对象调用该方法时会报错。
方式一:抽象类、抽象方法实现
如下实例,我们定义了一个基类BaseMessage,继承抽象类,通过使用@abstractmethod装饰方法send,send方法成为抽象方法,所有继承BaseMessage基类的类中必须要有send方法,否则执行此类时会报错。
from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=ABCMeta): @abstractmethod def send(self,subject,body,to,name): pass ######################################3 class WeChat(BaseMessage): def __init__(self): pass print("xxx") def send(self,subject,body,to,name): print('微信发送成功')
方法二:自定义基类方式实现
如下,自定义基类BaseMessage,在基类中定义一个send方法,方法内抛出没有该方法的异常NotImplementedError。WeChat类继承基类,实例化后调用send方法时,如果此类中没有定义该方法,则会去基类中找。从而会抛出异常。
class BaseMessage(object): def send(self, subject, body, to, name): raise NotImplementedError('未实现send方法') class WeChat(BaseMessage): def __init__(self): pass print("xxx") def send(self,subject,body,to,name): print('微信发送成功')
总结,以上两种方法均在基类中进行特定方法限制,所有继承此基类的类中必须要有此方法。不同的是,方法一中要求所有继承基类的类中必须有抽象方法规定的方法,否则类在实例化的时候就会报错。但是方法二中不同的是,若自定义的类中没有实现send方法时候,在类的实例化过程中不会报错,实例对象可以正常调用类中有的方法和属性,只有实例对象在调用send方法时候会报错。