Python包构建 - 用于类定义的导入函数 [英] Python Package Building - importing function for use in class definition

查看:156
本文介绍了Python包构建 - 用于类定义的导入函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个python包,它基本上是一个包装在请求包中,旨在使对一组数据库的各种api调用更容易。



目前,我的程序包具有以下目录结构:

  package\ 
- __init__.py
- coreFunc.py
subpackage \
- __init__.py
- mod1.py
- mod2.py

包的主要功能在于 mod1.py mod2.py mod1.py 如下所示:

 导入请求为_requests 
from package.coreFunc import __func1

class DataPull:
def __init __(self,arg1):
self._url =http://www.somesite.com/信息?
self._api_param = {'argument':__ func1(arg1)}
self._pull = _requests.get(self._url,params = self._api_param)
def DataTableOne
_headers = self._pull.json()['resultSets'] [0] ['headers']
_values = self._pull.json()['resultSets'] [0] ['rowSet ']
return [dict(zip(_headers,value))for value in _values]
def DataTableTwo(self):
_headers = self._pull.json()['resultSets'] [1] ['header']
_values = self._pull.json()['resultSets'] [1] ['rowSet']
return [dict(zip(_headers,value))for value in _values]



coreFunc.py ,我有一些功能,我需要在 mod1.py mod2.py 中的特定类中使用。事实上,在Class定义的第三行,我使用在 coreFunc 中定义的函数( __ func1 修改用户输入到参数,以确保正确的值传递给api调用。



coreFunc.py看起来像这样:

  def __func1 ):
if str(x)==1999:
return1999-00
elif len(str(x))== 4:
try:
return - 。join([str(x),str(int(x)%100 + 1)])
except:
raise异常(输入四位数年份 )
else:raise Exception(输入四位数年份)

m使用这个调用的类,因为调用导致多个数据表,我使用方法来访问每个数据表。



我的问题是,当我尝试创建一个类DataPull的对象:

  newObj = DataPull(argument)



给我以下错误:

  -------------------------------------------------- ------------------------ 
NameError Traceback(最近一次调用)
< ipython-input-24-e3399cf393bd> in< module>()
----> 1 traceback.extract_stack(package.mode1.DataPull(203112))

C:\Users\Bradley\Anaconda3\lib\site-packages\test-package-py3 .4.egg \package\subpackage\mod1.py in __init __(self,arg1)
140 self._url =http://www.somesite.com/info?
- > 141 self._api_param = {Season:__ func1(arg1)}

NameError:name'_DataPull__func1'未定义

如何正确导入 __ func1 到mod1.py中以修复此错误?

解决方案

name mangling ,在类定义内的 __ 前面的任何东西都改为 _classname__attr 。引用来自docs:


表单 __ spam 的任何标识符下划线,
最多一个尾部下划线)在文本上替换为
_classname__spam ,其中classname是当前类名称
前导下划线s)剥离。这种修改不考虑
到标识符的句法位置,只要在类的定义中出现
即可。


这是在源代码级别完成的,因此您可以将类定义中要使用的函数的名称更改为其他类型,并且可以正常工作。






相关CPython代码 compile.c

  PyObject * 
_Py_Mangle privateobj,PyObject * ident)
{
/ *名称管理:__private变为_classname__private。
这与名称的使用方式无关。 * /
const char * p,* name = PyString_AsString(ident);
char * buffer;
size_t nlen,plen;
if(privateobj == NULL ||!PyString_Check(privateobj)||
name == NULL || name [0]!='_'|| name [1]!='_') {
Py_INCREF(ident);
return ident;
}
p = PyString_AsString(privateobj);
nlen = strlen(name);
/ *不要mangle __id__或带点的名称。

只有当一个带有点的名字出现时,才会出现
,我们正在编译一个import语句,它的名字是


TODO(jhylton):决定我们是否支持
模块名称的修改,例如。 __M.X。
* /
if((name [nlen-1] =='_'&&&name [nlen-2] =='_')
|| strchr(name, '。')){
Py_INCREF(ident);
return ident; / *不要mangle __whatever__ * /
}
/ *剥离类名的前导下划线* /
while(* p =='_')
p ++;
if(* p =='\0'){
Py_INCREF(ident);
return ident; / *如果类只是下划线,不要歪斜* /
}
plen = strlen(p);

if(plen + nlen> = PY_SSIZE_T_MAX - 1){
PyErr_SetString(PyExc_OverflowError,
私有标识符太大而不能被破坏);
return NULL;
}

ident = PyString_FromStringAndSize(NULL,1 + nlen + plen);
if(!ident)
return 0;
/ * ident =_+ p [:plen] + name#即1 + plen + nlen字节* /
buffer = PyString_AS_STRING
buffer [0] ='_';
strncpy(buffer + 1,p,plen);
strcpy(buffer + 1 + plen,name);
return ident;
}


I'm working on building a python package that is basically a wrapper around the request package and designed to make a variety of api calls to a set of databases easier.

Currently, my package has the following directory structure:

package\
  - __init__.py
  - coreFunc.py
  subpackage\
    - __init__.py
    - mod1.py
    - mod2.py

The primary functionality of the package lies in mod1.py and mod2.py. mod1.py looks like this:

import requests as _requests
from package.coreFunc import __func1

class DataPull:
    def __init__(self, arg1):
      self._url = "http://www.somesite.com/info?"
      self._api_param = {'argument':__func1(arg1)}
      self._pull = _requests.get(self._url, params = self._api_param)
    def DataTableOne(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def DataTableTwo(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]

within coreFunc.py, I have a few functions that I need to use within specific classes in mod1.py and mod2.py. IN fact, in the third line of the Class definition, I'm using a function (__func1) defined in coreFunc to modify user input to the argument to ensure the correct value is passed to the api call.

coreFunc.py looks like this:

def __func1(x):
    if str(x) == "1999":
    return "1999-00"
elif len(str(x)) == 4:
    try:
        return "-".join([str(x),str(int(x) % 100 + 1)])
    except: 
        raise Exception("Enter the four-digit year")
else: raise Exception("Enter the four-digit year")

I'm using a class for this call because the call results in more than one data table and I am using methods to access each of the data tables.

My issue is that when I try and create an object of class DataPull:

newObj = DataPull(argument)

gives me the following error:

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-24-e3399cf393bd> in <module>()
----> 1 traceback.extract_stack(package.mode1.DataPull("203112"))

C:\Users\Bradley\Anaconda3\lib\site-packages\test-package-py3.4.egg\package\subpackage\mod1.py in __init__(self, arg1)
    140         self._url = "http://www.somesite.com/info?"
--> 141         self._api_param = {"Season":__func1(arg1)}

NameError: name '_DataPull__func1' is not defined

How do I properly import __func1 into mod1.py to fix this error?

解决方案

This is a case of name mangling, anything with __ in front of it within class definition is changed to _classname__attr. Quoting from docs:

Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

This is done at the source code level, so you can change the name of function that is going to be used inside the class definition to something else and it will work fine.


Related CPython code from compile.c:

PyObject *
_Py_Mangle(PyObject *privateobj, PyObject *ident)
{
    /* Name mangling: __private becomes _classname__private.
       This is independent from how the name is used. */
    const char *p, *name = PyString_AsString(ident);
    char *buffer;
    size_t nlen, plen;
    if (privateobj == NULL || !PyString_Check(privateobj) ||
        name == NULL || name[0] != '_' || name[1] != '_') {
        Py_INCREF(ident);
        return ident;
    }
    p = PyString_AsString(privateobj);
    nlen = strlen(name);
    /* Don't mangle __id__ or names with dots.

       The only time a name with a dot can occur is when
       we are compiling an import statement that has a
       package name.

       TODO(jhylton): Decide whether we want to support
       mangling of the module name, e.g. __M.X.
    */
    if ((name[nlen-1] == '_' && name[nlen-2] == '_')
        || strchr(name, '.')) {
        Py_INCREF(ident);
        return ident; /* Don't mangle __whatever__ */
    }
    /* Strip leading underscores from class name */
    while (*p == '_')
        p++;
    if (*p == '\0') {
        Py_INCREF(ident);
        return ident; /* Don't mangle if class is just underscores */
    }
    plen = strlen(p);

    if (plen + nlen >= PY_SSIZE_T_MAX - 1) {
        PyErr_SetString(PyExc_OverflowError,
                        "private identifier too large to be mangled");
        return NULL;
    }

    ident = PyString_FromStringAndSize(NULL, 1 + nlen + plen);
    if (!ident)
        return 0;
    /* ident = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */
    buffer = PyString_AS_STRING(ident);
    buffer[0] = '_';
    strncpy(buffer+1, p, plen);
    strcpy(buffer+1+plen, name);
    return ident;
}

这篇关于Python包构建 - 用于类定义的导入函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆