Python之namedtuple源码分析
namedtuple()函数根据提供的参数创建一个新类,这个类会有一个类名,一些字段名和一个可选的用于定义类行为的关键字,具体实现如下
namedtuple函数源码
from keyword import iskeyword as _iskeyword
import sys as _sys import logging
logging.basicConfig(level=logging.INFO, filename="logging.txt", filemode="w+", \
format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__) _class_template = """\
from builtins import property as _property, tuple as _tuple
from operator import itemgetter as _itemgetter
from collections import OrderedDict class {typename}(tuple):
'{typename}({arg_list})' __slots__ = () _fields = {field_names!r} def __new__(_cls, {arg_list}):
'Create new instance of {typename}({arg_list})'
return _tuple.__new__(_cls, ({arg_list})) @classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new {typename} object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != {num_fields:d}:
raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result))
return result def _replace(_self, **kwds):
'Return a new {typename} object replacing specified fields with new values'
result = _self._make(map(kwds.pop, {field_names!r}, _self))
if kwds:
raise ValueError('Got unexpected field names: %r' % list(kwds))
return result def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + '({repr_fmt})' % self def _asdict(self):
'Return a new OrderedDict which maps field names to their values.'
return OrderedDict(zip(self._fields, self)) def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self) {field_defs}
""" _repr_template = '{name}=%r' _field_template = '''\
{name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}')
''' def namedtuple(typename, field_names, *, verbose=False, rename=False, module=None):
"""Returns a new subclass of tuple with named fields. >>> Point = namedtuple('Point', ['x', 'y'])
>>> Point.__doc__ # docstring for the new class
'Point(x, y)'
>>> p = Point(11, y=22) # instantiate with positional args or keywords
>>> p[0] + p[1] # indexable like a plain tuple
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> d = p._asdict() # convert to a dictionary
>>> d['x']
11
>>> Point(**d) # convert from a dictionary
Point(x=11, y=22)
>>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
Point(x=100, y=22) """ # Validate the field names. At the user's option, either generate an error
# message or automatically replace the field name with a valid name.
if isinstance(field_names, str):
field_names = field_names.replace(',', ' ').split()
field_names = list(map(str, field_names))
typename = str(typename)
logging.info("%s: %s" %(typename, field_names))
if rename:
seen = set()
for index, name in enumerate(field_names):
if (not name.isidentifier()
or _iskeyword(name)
or name.startswith('_')
or name in seen):
field_names[index] = '_%d' % index
seen.add(name)
for name in [typename] + field_names:
logging.info(name)
if type(name) is not str:
raise TypeError('Type names and field names must be strings')
#判断是否为标识符,标识符必须以字母或者“_”开头
#标识符用于作为变量,函数名、类名、方法名等
if not name.isidentifier():
raise ValueError('Type names and field names must be valid '
'identifiers: %r' % name)
#判断是否为关键字,关键字为python内部已经使用了的标识符
if _iskeyword(name):
raise ValueError('Type names and field names cannot be a '
'keyword: %r' % name)
seen = set()
for name in field_names:
if name.startswith('_') and not rename:
raise ValueError('Field names cannot start with an underscore: '
'%r' % name)
if name in seen:
raise ValueError('Encountered duplicate field name: %r' % name)
seen.add(name) # Fill-in the class template
class_definition = _class_template.format(
typename = typename,
field_names = tuple(field_names),
num_fields = len(field_names),
arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
repr_fmt = ', '.join(_repr_template.format(name=name)
for name in field_names),
field_defs = '\n'.join(_field_template.format(index=index, name=name)
for index, name in enumerate(field_names))
)
logging.info(class_definition) # Execute the template string in a temporary namespace and support
# tracing utilities by setting a value for frame.f_globals['__name__']
namespace = dict(__name__='namedtuple_%s' % typename)
exec(class_definition, namespace)
result = namespace[typename]
result._source = class_definition
if verbose:
print(result._source) # For pickling to work, the __module__ variable needs to be set to the frame
# where the named tuple is created. Bypass this step in environments where
# sys._getframe is not defined (Jython for example) or sys._getframe is not
# defined for arguments greater than 0 (IronPython), or where the user has
# specified a particular module.
if module is None:
try:
module = _sys._getframe(1).f_globals.get('__name__', '__main__')
except (AttributeError, ValueError):
pass
if module is not None:
result.__module__ = module return result
通过函数模板字符串_class_template.format()会生成我们需要的实例类:
eg: people = namedtuple("person","name,age,sex")
class person(tuple) 分析
#coding=utf-8 from builtins import property as _property, tuple as _tuple
from operator import itemgetter as _itemgetter
from collections import OrderedDict import logging
logging.basicConfig(level=logging.INFO, filename="logging.txt", filemode="w+", \
format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__) class person(tuple):
'person(name, age, sex)' __slots__ = () _fields = ('name', 'age', 'sex') def __new__(_cls, name, age, sex):
'Create new instance of person(name, age, sex)'
logger.info("__new__")
return _tuple.__new__(_cls, (name, age, sex)) @classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new person object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != 3:
raise TypeError('Expected 3 arguments, got %d' % len(result))
return result def _replace(_self, **kwds):
'Return a new person object replacing specified fields with new values' #需要深刻理解该代码的精髓
logger.info(type(_self))
for item in _self:
logger.info(item)
str = '''
how to replace dict_keyvalue
li = map({"age":99}.pop, ('name', 'age', 'sex'), ("zhanglin", "11", "man"))
'''
logger.info(str)
result = _self._make(map(kwds.pop, ('name', 'age', 'sex'), _self))
if kwds:
raise ValueError('Got unexpected field names: %r' % list(kwds))
return result def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + '(name=%r, age=%r, sex=%r)' % self def _asdict(self):
'Return a new OrderedDict which maps field names to their values.'
return OrderedDict(zip(self._fields, self)) #打包为元组列表 def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self) name = _property(_itemgetter(0), doc='Alias for field number 0') age = _property(_itemgetter(1), doc='Alias for field number 1') sex = _property(_itemgetter(2), doc='Alias for field number 2') if __name__ == "__main__": p1 = person("zhanglin", "", "man")
logger.info("{0}:{1}".format("p1", p1))
#_replace验证
p2 = p1._replace(name ="zhangsan", age=99)
logger.info(p2)
logger.info("{0}:{1}".format("p2", p2))
测试结果:
2018-03-21 15:10:46,197 - __main__ - INFO - __new__
2018-03-21 15:10:46,197 - __main__ - INFO - p1:person(name='zhanglin', age='', sex='man')
2018-03-21 15:10:46,197 - __main__ - INFO - <class '__main__.person'>
2018-03-21 15:10:46,197 - __main__ - INFO - zhanglin
2018-03-21 15:10:46,197 - __main__ - INFO - 30
2018-03-21 15:10:46,197 - __main__ - INFO - man
2018-03-21 15:10:46,197 - __main__ - INFO -
how to replace dict_keyvalue
li = map({"age":99}.pop, ('name', 'age', 'sex'), ("zhanglin", "", "man")) 2018-03-21 15:10:46,197 - __main__ - INFO - person(name='zhangsan', age=99, sex='man')
2018-03-21 15:10:46,197 - __main__ - INFO - p2:person(name='zhangsan', age=99, sex='man')
根据类的字符串模板创建类
#coding=utf-8 import logging logging.basicConfig(level=logging.INFO, filename="logging.txt", filemode="w+",\
format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__) _class_template = \
'''
class {typename}(tuple):
__slots__ = ()
_fields = {field_names!r}
def __new__(cls, *args, **dwargs):
return super().__new__(cls, *args, **dwargs)
''' def defineclass(typename, field_names):
logging.info(field_names)
class_definition = _class_template.format(typename=typename,field_names=field_names,\
#方法1
arg_list = ','.join(name for name in field_names),\
self_format = "".join("\t\tself.{name}={name}\n".format(name=name) for name in field_names))
#方法2
#arg_list = ', '.join('{name}'.format(name=name) for name in field_names))
#方法3
#arg_list = repr(tuple(field_names)).replace("'", "")[1:-1])
logging.info(class_definition) namespace = dict(__name__='defineclass_%s' % typename)
logging.info("namespce:{}".format(namespace))
exec(class_definition, namespace) result = namespace[typename]
logging.info("typename:{0}--result:{1}".format(typename, namespace[typename]))
result._source = class_definition return result if __name__ == "__main__": person = defineclass("person", ("name", "age", "sex"))
print (type(person))
p = person(("zhanglin", "", "man"))
print (p)
print (p[0])
2018-03-22 00:05:50,705 - root - INFO - ('name', 'age', 'sex')
2018-03-22 00:05:50,705 - root - INFO -
class person(tuple):
__slots__ = ()
_fields = ('name', 'age', 'sex')
def __new__(cls, *args, **dwargs):
return super().__new__(cls, *args, **dwargs)
2018-03-22 00:05:50,705 - root - INFO - namespce:{'__name__': 'defineclass_person'}
2018-03-22 00:05:50,705 - root - INFO - typename:person--result:<class 'defineclass_person.person'>
Python之namedtuple源码分析的更多相关文章
- Python 进阶之源码分析:如何将一个类方法变为多个方法?
前一篇文章<Python 中如何实现参数化测试?>中,我提到了在 Python 中实现参数化测试的几个库,并留下一个问题: 它们是如何做到把一个方法变成多个方法,并且将每个方法与相应的参数 ...
- Python之socketserver源码分析
一.socketserver简介 socketserver是一个创建服务器的框架,封装了许多功能用来处理来自客户端的请求,简化了自己写服务端代码.比如说对于基本的套接字服务器(socket-based ...
- python string.py 源码分析 三:maketrans
l = map(chr, xrange(256)) #将ascii转为字符串 _idmap = str('').join(l) del l # Construct a translation stri ...
- python string.py 源码分析 二:capwords
def capwords(s, sep=None): """capwords(s [,sep]) -> string Split the argument into ...
- python string.py 源码分析 一
# Some strings for ctype-style character classification c风格字符串 whitespace = ' \t\n\r\v\f' #空白字符 \t 制 ...
- Python之美[从菜鸟到高手]--urlparse源码分析
urlparse是用来解析url格式的,url格式如下:protocol :// hostname[:port] / path / [;parameters][?query]#fragment,其中; ...
- [python] 基于词云的关键词提取:wordcloud的使用、源码分析、中文词云生成和代码重写
1. 词云简介 词云,又称文字云.标签云,是对文本数据中出现频率较高的“关键词”在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略文本数据的主要表达意思.常见于博客.微博 ...
- Python源码分析(二) - List对象
python中的高级特性之一就是内置了list,dict等.今天就先围绕列表(List)进行源码分析. Python中的List对象(PyListObject) Python中的的PyListObje ...
- python基础-11 socket,IO多路复用,select伪造多线程,select读写分离。socketserver源码分析
Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...
随机推荐
- Java中的静态方法是什么?
静态方法是使用公共内存空间的,就是说所有对象都可以直接引用,不需要创建对象再使用该方法. 例如,我创建一个类,里面有一个静态方法: class Test{ public static int z(in ...
- jmeter之报告和分析
转载:http://www.cnblogs.com/miaomiaokaixin/p/6118081.html jmeter -n -t 脚本名字.jmx -l xxx.jtl -e -o 指定目录( ...
- Linux安全策略配置-pam_tally2身份验证模块
PAM身份验证安全配置实例 - 强制使用强密码(用户密码安全配置) - 用户SSH登录失败尝试次数超出限制后锁定账户(帐户锁定/解锁和时间设置) - 允许普通用户使用sudo而不是su(限制普通用户登 ...
- node第一个程序
var http = require('http') var url = require('url') var fs=require("fs") var router = requ ...
- session/token/cookie/socket区别
Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象 ...
- Linux系统下wget命令的使用教程
一.Linux wget简介 wget是linux上的命令行的下载工具.这是一个GPL许可证下的自由软件.Linux wget支持HTTP和FTP协议,支持代理服务器和断点续传功能,能够自动递归远程主 ...
- 【I/O】常见输入输出
缓冲输入文件.输出文件 import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; ...
- <关于并发框架>Java原生线程池原理及Guava与之的补充
原创博客,转载请联系博主! 转眼快两个月没有更新自己的博客了. 一来感觉自己要学的东西还是太多,与其花几个小时写下经验分享倒不如多看几点技术书. 二来放眼网上已经有很多成熟的中文文章介绍这些用法,自己 ...
- Which HTTP methods match up to which CRUD methods?
https://stackoverflow.com/questions/6203231/which-http-methods-match-up-to-which-crud-methods Crea ...
- 进程管理工具supervisor
1. 简介 supervisor有两个组件:supervisord和supervisorctl,组成了client/server结构. supervisord负责读入配置文件,然后supervisor ...