Python之namedtuple源码分析建议收藏

namedtuple函数源码通过函数模板字符串_class_template.format()会生成我们需要的实例类:eg:people=namedtuple("person&qu

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

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", "30", "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='30', 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", "11", "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", "31", "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'>

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120187.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • h2数据库连接mysql_H2数据库简单使用操作「建议收藏」

    h2数据库连接mysql_H2数据库简单使用操作「建议收藏」h2database官网下载客户端控制台h2databaseMaven配置com.h2databaseh21.4.1991控制台新建数据库与连接数据库1.1建库windows系统下点击h2/bin/h2.bat启动控制台应用程序鼠标右键点击桌面右下角图标Createanewdatabase…例如在k盘h2目录下新建helloForm数据库,则填写路径为k:/h2/helloForm…

  • 反射之invoke方法

    反射之invoke方法当获得类对应的Class对象后,可以通过getMethods()方法得到全部方法——返回Method数组,或者getMethod()方法来获取指定方法——Method对象。可以通过Method对象的invoke()方法来调用它对应的方法。Objectinvoke(Objectobj,Object…args):obj是执行该方法的Class对象,args是执行该方法时传入的实参。

  • numpy求特征向量_python计算矩阵

    numpy求特征向量_python计算矩阵文章目录numpy计算矩阵特征值,特征向量一、示例:二、numpy实现:numpy计算矩阵特征值,特征向量一、示例:首先借参考百度demo的来看一下矩阵的特征值和特征向量的解题过程及结果。可知矩阵A:特征值为1对应的特征向量为[-1,-2,1]T。特征值为2对应的特征向量为[0,0,1]T我们可以进一步对特征向量进行单位化,单位化之后的结果如下:特征值为1对应的特征向量为[…

    2022年10月23日
  • 设置document.cookie的使用[通俗易懂]

    设置document.cookie的使用[通俗易懂]设置cookie每个cookie都是一个名/值对,可以把下面这样一个字符串赋值给document.cookie:document.cookie=”userId=828″;如果要一次存储多个名/值对,可以使用分号加空格(;)隔开,例如:document.cookie=”userId=828;userName=hulk”;在cookie的名或值中不能使用分号(;)、逗号(,)、等号(=)以及空格。

  • UML教程_css餐厅游戏答案

    UML教程_css餐厅游戏答案 UML教程

    2022年10月24日
  • js正则截取指定字符串_java正则表达式提取字符串

    js正则截取指定字符串_java正则表达式提取字符串一、javascript正则表达式的基本知识1javascript正则对象创建和用法声明javascript正则表达式varreCat=newRegExp(“cat”);你也可以varreCat=/cat/;//Perl风格(推荐)2学习最常用的testexecmatchsearchreplacesplit6个方法1)test检查指定的字符串是否存在vardata=“123123″;varreCat=/123/gi;alert(r

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号