【Python】__slots__ 、@property、多重继承、定制类、枚举类、元类
【使用__slots__】
1、动态语言的一个特点就是允许给实例绑定任意的方法和变量,而静态语言(例如Java)必须事先将属性方法写进类里。
给实例绑定变量:
- >>> class Student:
- ... pass
- ...
- >>> s = Student()
- >>> s.name = 'Lily'
- >>> s.name
- 'Lily'
给实例绑定方法需要借助types模块的MethodType方法:
- >>> def setAge(self, age):
- ... self.age = age
- ...
- >>> from types import MethodType
- >>> s.setAge = MethodType(setAge, s)
- >>> s.setAge(5)
- >>> s.age
- 5
还可以给class绑定方法,使得方法对所有实例都有效:
- >>> Student.setAge = setAge
2、万一需要限制属性怎么办?即只允许类的实例添加有限个属性。
这个时候可以使用一个特殊的类变量__slots__:
- >>> class Employee(object):
- ... __slots__ = ('name', 'salary')
- ...
- >>> e = Employee()
- >>> e.name = 'Wang fang'
- >>> e.salary = 18000
- >>> e.age = 18 # age无法被添加为实例的属性!
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- AttributeError: 'Employee' object has no attribute 'age'
但是需要注意的是,__slots__对继承的子类是不起作用的!
【使用@property】
1、简而言之,@property就是一个类的方法的“装饰器”,添加在类的方法名的上一行,作用是把一个方法变成属性调用(即允许s.field这种访问方式),又能进行适当的参数检查。一个简单的例子:
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- class Movie(object):
- # 把一个getter方法变成属性
- @property
- def title(self):
- return self._title # 不能和装饰器@title.setter重名,所以使用_title
- @title.setter
- def title(self, title):
- if not isinstance(title, str):
- raise ValueError('title must be a str!')
- self._title = title
- # 类测试
- if __name__ == '__main__':
- m = Movie()
- # m.title = 123
- m.title = 'Tokyo Ghoul'
- print(m.title)
如果输入的title不是str类型,则会输出:
- Traceback (most recent call last):
- File "D:\labs\test.py", line 20, in <module>
- File "D:\labs\test.py", line 14, in title
- ValueError: title must be a str!
2、如果要将上面的title属性改为只读,只需要删去setter方法就可以了。
3、练习。
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- class Screen(object):
- @property
- def width(self):
- return self._width
- @width.setter
- def width(self, width):
- if width <= 0:
- raise ValueError('width must larger than 0')
- self._width = width
- @property
- def height(self):
- return self._height
- @height.setter
- def height(self, height):
- if height <= 0:
- raise ValueError('height must larger than 0')
- self._height = height
- @property
- def area(self):
- return self._width * self._height
测试结果:
- >>> from test import Screen
- >>> s = Screen()
- >>> s.width = 0
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "D:\labs\test.py", line 13, in width
- raise ValueError('width must larger than 0')
- ValueError: width must larger than 0
- >>> s.width = 80
- >>> s.height = 70
- >>> s.area = 10
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- AttributeError: can't set attribute
- >>> s.area
- 5600
【多重继承】
1、多重继承:类似于Java可以实现多个接口。(仅仅是类似,不等于!)
2、引用网友:第一个继承的是生父,后边的都是继父,继父的名字后面要加MixIn表明身份,如果方法有冲突,优先继承生父的。
- class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
- pass
注:第一个是主线继承,后两个是增加的功能。
【定制类】
1、__str__()、__repr__()类似于Java中的toString()。前者用于s.print(object)、后者用于直接输入s时的输出。
- def __str__(self):
- ... return 'Student object (name: %s)' % self.name
偷懒的写法:写完__str__()后,__repr__ = __str__
2、__iter__()、__next__()。简单的例子:
- #!/usr/bin/env python3
- # -*- coding: utf- -*-
- class f():
- def __init__(self):
- self.a =
- def __iter__(self):
- return self # 返回一个迭代对象给for
- def __next__(self): # 实现一个next方法给for调用
- self.a +=
- return self.a
4、__getitem__:让自定义对象表现得像list、str等类型一样。(可以进行索引、切片等操作)
- class f():
- def __getitem__(self, n):
- return n
- >>> from test import f
- >>> f()[1]
- 1
- >>> f()[3]
- 3
如果要支持切片:
- class f():
- def __getitem__(self, n):
- if isinstance(n, int):
- return n
- if isinstance(n, slice):
- start = n.start
- stop = n.stop
- if start == None: #例如[:3]默认为[0:3]
- start = 0
- L = []
- for x in range(start, stop):
- L.append(x)
- return L
- >>> f()[1:3]
- [1, 2]
5、__getattr__:attr是attribute的简写。当实例本身不具备某个属性,却又强行被调用的时候会调用该函数。
- class f():
- def __init__(self):
- self.a = 1111
- self.b = 33333
- def __getattr__(self, attr):
- return "i had not attribute " + attr + "!"
- >>> f().a
- 1111
- >>> f().b
- 33333
- >>> f().c
- 'i had not attribute c!'
当然也可以返回函数。
利用完全动态的__getattr__
,可以写出一个链式调用。。。
6、__call__。
1)判断一个变量是对象还是函数:callable()。
2)把对象变成函数的方法:重写__call__方法。
such:
- class f:
- def __call__(self, a, b):
- return a + b
- >>> sum = f()
- >>> sum(1, 2)
- 3
更多python的定制方法参考python官方文档。
【使用枚举类】
在Python中枚举类型也可以被视为一个类。
1、有两种方式可以创建这种类。
1)赋值法。
- >>> from enum import Enum
- >>> Colors = Enum('Colors', ('RED', 'YELLOW', 'BLUE'))
自然的操作,尝试打印一个Enum常量:
- >>> Colors.RED
- <Colors.RED: 1>
2)继承Enum。
- from enum import Enum, unique
@unique- class Colors(Enum):
- RED = 10086
- YELLOW = 111
- BLUE = 2222
尝试打印:
- >>> from test import Colors
- >>> Colors.RED
- <Colors.RED: 10086>
10086即是RED的value。ps:@unique装饰器可以帮助检查有没有重复值。
2、枚举类用于逻辑关系运算 & 打印枚举类型变量
- >>> myColor = Colors.BLUE
- >>> myColor == Colors.RED
- False
- >>> print(myColor)
- Colors.BLUE
【使用元类】
1、Python中的type()。
type()是用来干嘛的呢?根据字面上的意思很容易想到,可以通过type来输出Python中各种构件的类型,例如:
- >>> type(1)
- <class 'int'>
- >>> type('hi python')
- <class 'str'>
- >>> type(lambda x: x)
- <class 'function'>
尝试传入类名、对象会发现:
- >>> class MyClass(object):
- ... pass
- ...
- >>> type(MyClass)
- <class 'type'>
- >>> type(MyClass())
- <class '__main__.MyClass'>
MyClass()对象的类型是MyClass,而MyClass类的类型是type!
这就说明,MyClass本身也可以被看作是由type创建的对象,而MyClass这个对象又具备创建对象的能力。
因此,type()除了可以用于查看各种Python构件的类型外,还可以用来创建类。
实际上在Python的解释器内部创建类的工作都是自动调用type()完成的。那么如何手动调用type()呢?
只需要将传统的class创建方式映射到type()上来就可以了。
一个传统的dog:
- class Dog(object):
- def __init__(self, name, age):
- self.name = name
- self.age = age
- def run(self):
- print(self.name + ' run!\n')
- >>> from test import Dog
- >>> i = Dog('Huahua', 2)
- >>> i.run()
- Huahua run!
一个type()创建的dog类:
- # 先把组件写好
- # 构造器
- def f1(self, name, age):
- self.name = name
- self.age = age
- # run方法
- def f2(self):
- print(self.name + ' run!\n')
- # 组装成type()
- Dog = type('Dog', (object,), dict(__init__=f1, run=f2))
测试:
- >>> def f1(self, name, age):
- ... self.name = name
- ... self.age = age
- ...
- >>> def f2(self):
- ... print(self.name + ' run!\n')
- ...
- >>> Dog = type('Dog', (object,), dict(__init__=f1, run=f2))
- >>> i = Dog('Lele', 3)
- >>> i.run()
- Lele run!
为什么使用type()而不是class来创建类呢?因为type()更具动态性。
2、元类。参考博客:深刻理解Python中的元类
为什么使用metaclass?和使用type一样,为了创建基于上下文的类。
什么是metaclass?type就是Python内置的一个metaclass!
一个使用metaclass会让事情变得简单的例子:数据库的GUI。(用type做不了,非metaclass不可)
定义metaclass
用metaclass创建类
这里是FO是
【Python】__slots__ 、@property、多重继承、定制类、枚举类、元类的更多相关文章
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- python-元类和使用元类实现简单的ORM
元类 面向对象中,对象是类的实例,即对象是通过类创建出来的,在python中,一切皆对象,同样,类也是一个对象,叫做类对象,只是这个类对象拥有创建其子对象(实例对象)的能力.既然类是对象,那么类是通过 ...
- Python说文解字_详解元类
1.深入理解一切接对象: 1.1 什么是类和对象? 首先明白元类之前要明白什么叫做类.类是面向对象object oriented programming的重要概念.在面向对象中类和对象是最基本的两个概 ...
- Python内置类属性,元类研究
Python内置类属性 我觉得一切都是对象,对象和元类对象,类对象其实都是一样的,我在最后进行了证明,但是只能证明一半,最后由于元类的父类是type,他可以阻挡对object属性的访问,告终 __di ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- Python元类(metaclass)以及元类实现单例模式
这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解类也是对 ...
- Python 爬取各大代理IP网站(元类封装)
import requests from pyquery import PyQuery as pq base_headers = { 'User-Agent': 'Mozilla/5.0 (Windo ...
- 元类理解与元类编程 《Python3网络爬虫开发》中第九章代理的使用代码Crawler中代码的理解
__new__与__init__的理解 __new__()方法是在创建实例之前被调用的,它的作用是创建一个实例,然后返回该实例对象,它是一个静态方法. __init__() 当实例被创建完成之后被调用 ...
- Python面向对象 -- slots, @property、多重继承MixIn、定制类(str, iter, getitem, getattr, call, callable函数,可调用对象)、元类(type, metaclass)
面向对象设计中最基础的3个概念:数据封装.继承和多态 动态给class增加功能 正常情况下,当定义了一个class,然后创建了一个class的实例后,可以在程序运行的过程中给该实例绑定任何属性和方法, ...
随机推荐
- IOS 预览word文档的集中方式
在iPhone中可以很方便的预览文档文件,如:pdf.word等等,这篇文章将以PDF为例.介绍三种预览PDF的方式,又分别从本地pdf文档和网络上的pdf文档进行对比. 预览本地PDF文档: 1.使 ...
- Java Web项目--使用JSP生成一个页面
我们使用了servlet生成了一个网页,但是可以看到使用servlet生成网页必须将网页的内容全部嵌入到Java代码当中,不是很方便.所以有没有什么办法是将Java代码嵌入到html代码中,而不是像s ...
- SQL:CASE WHEN ELSE END用法
CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 WHEN 条件3 THEN 结果3 WHEN 条件4 THEN 结果4......... ...
- HDU1811 拓扑排序判环+并查集
HDU Rank of Tetris 题目:http://acm.hdu.edu.cn/showproblem.php?pid=1811 题意:中文问题就不解释题意了. 这道题其实就是一个拓扑排序判圈 ...
- Android项目使用Eclipse进行单元测试
Android项目如果每次都整个调试的话,要加载UI,会等很长时间.所以单元测试就显得很方便了. 要进行单元测试,首先得修改下AndroidManifest.xml文件.在Instrument标签里点 ...
- Django 框架搭建入门案例
1. 什么是 web 框架 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端; # 示例: import socket def handle_re ...
- Linux下的内核模块机制
2017-06-20 Linux的内核模块机制允许开发者动态的向内核添加功能,我们常见的文件系统.驱动程序等都可以通过模块的方式添加到内核而无需对内核重新编译,这在很大程度上减少了操作的复杂度.模块机 ...
- IT开发工程师的悲哀现状和可能前途
IT开发工程师的悲哀现状和可能前途 本文所指的开发工程师,仅指程序开发人员和以数字电路开发为主的电子工程师.当你选择计算机或者电子.自控等专业进入大学时,你本来还是有机会从事其它行业的,可你毕业时执迷 ...
- ALV tree DUMP 问题处理-20180328
Category ABAP Programming Error Runtime Errors MESSAGE_TYPE_X ABAP Program SAPLOLEA Application Comp ...
- PHPcms v9 get标签sql 语句limit无效问题的解决方法
get标签非常好用,自定义模型后get几乎变成万能的了.但是PHPCMS升级到V9后,把2008的很多功能都去掉了,比如get标签中,在后面自动添加了一个LIMIT 0,20,这样你即使写了num=' ...