标签归档:Python

用Python注释函数的正确方法是什么?

问题:用Python注释函数的正确方法是什么?

有没有一种普遍接受的方法来注释Python中的函数?可以接受以下内容吗?

#########################################################
# Create a new user
#########################################################
def add(self):

Is there a generally accepted way to comment functions in Python? Is the following acceptable?

#########################################################
# Create a new user
#########################################################
def add(self):

回答 0

正确的方法是提供文档字符串。这样,help(add)还将吐出您的评论。

def add(self):
    """Create a new user.
    Line 2 of comment...
    And so on... 
    """

那是三个双引号来打开评论,另外三个双引号来结束它。您也可以使用任何有效的Python字符串。它不必是多行的,双引号可以替换为单引号。

请参阅:PEP 257

The correct way to do it is to provide a docstring. That way, help(add) will also spit out your comment.

def add(self):
    """Create a new user.
    Line 2 of comment...
    And so on... 
    """

That’s three double quotes to open the comment and another three double quotes to end it. You can also use any valid Python string. It doesn’t need to be multiline and double quotes can be replaced by single quotes.

See: PEP 257


回答 1

使用其他人已经写过的文档字符串。

您甚至可以更进一步,并在文档字符串中添加一个文档测试,从而使对功能的自动测试变得轻而易举

Use a docstring, as others have already written.

You can even go one step further and add a doctest to your docstring, making automated testing of your functions a snap.


回答 2

使用文档字符串

作为模块,函数,类或方法定义中的第一条语句出现的字符串文字。这样的文档字符串成为该__doc__对象的特殊属性。

通常,所有模块都应具有文档字符串,并且模块导出的所有函数和类也应具有文档字符串。公共方法(包括__init__构造函数)也应具有文档字符串。包可以记录在__init__.py包目录中文件的模块文档字符串中。

Python代码其他地方出现的字符串文字也可以用作文档。它们无法被Python字节码编译器识别,并且不能作为运行时对象属性(即未分配给__doc__)进行访问,但是软件工具可以提取两种类型的额外docstring:

  1. 在模块,类或__init__方法的顶级进行简单分配后立即出现的字符串文字称为“属性文档字符串”。
  2. 在另一个文档字符串之后立即出现的字符串文字称为“其他文档字符串”。

有关属性和附加文档字符串的详细说明,请参见PEP 258,“ Docutils设计规范” [2]

Use a docstring:

A string literal that occurs as the first statement in a module, function, class, or method definition. Such a docstring becomes the __doc__ special attribute of that object.

All modules should normally have docstrings, and all functions and classes exported by a module should also have docstrings. Public methods (including the __init__ constructor) should also have docstrings. A package may be documented in the module docstring of the __init__.py file in the package directory.

String literals occurring elsewhere in Python code may also act as documentation. They are not recognized by the Python bytecode compiler and are not accessible as runtime object attributes (i.e. not assigned to __doc__ ), but two types of extra docstrings may be extracted by software tools:

  1. String literals occurring immediately after a simple assignment at the top level of a module, class, or __init__ method are called “attribute docstrings”.
  2. String literals occurring immediately after another docstring are called “additional docstrings”.

Please see PEP 258 , “Docutils Design Specification” [2] , for a detailed description of attribute and additional docstrings…


回答 3

良好评论的原则是相当主观的,但是这里有一些准则:

  • 函数注释应描述函数的意图,而不是实现
  • 概述您的功能对系统状态所做的任何假设。如果它使用任何全局变量(tsk,tsk),请列出它们。
  • 提防过多的ASCII艺术。散列很长的字符串似乎使注释更易于阅读,但是当注释更改时,它们可能很烦人
  • 利用提供“自动文档”的语言功能,例如,Python中的文档字符串,Perl中的POD和Java中的Javadoc

The principles of good commenting are fairly subjective, but here are some guidelines:

  • Function comments should describe the intent of a function, not the implementation
  • Outline any assumptions that your function makes with regards to system state. If it uses any global variables (tsk, tsk), list those.
  • Watch out for excessive ASCII art. Having long strings of hashes may seem to make the comments easier to read, but they can be annoying to deal with when comments change
  • Take advantage of language features that provide ‘auto documentation’, i.e., docstrings in Python, POD in Perl, and Javadoc in Java

回答 4

阅读有关在Python代码中使用文档字符串的信息

按照Python docstring约定

函数或方法的文档字符串应总结其行为,并记录其参数,返回值,副作用,引发的异常以及何时可以调用它的限制(所有这些均适用)。应该指出可选参数。应该记录关键字参数是否是接口的一部分。

没有黄金法则,而是提供评论,这对于您团队中的其他开发人员(如果有的话)或对您自己意味着意义的评论,如果您在六个月后再回到它的话。

Read about using docstrings in your Python code.

As per the Python docstring conventions:

The docstring for a function or method should summarize its behavior and document its arguments, return value(s), side effects, exceptions raised, and restrictions on when it can be called (all if applicable). Optional arguments should be indicated. It should be documented whether keyword arguments are part of the interface.

There will be no golden rule, but rather provide comments that mean something to the other developers on your team (if you have one) or even to yourself when you come back to it six months down the road.


回答 5

我会去进行与Sphinx等文档工具集成的文档实践。

第一步是使用docstring

def add(self):
 """ Method which adds stuff
 """

I would go for a documentation practice that integrates with a documentation tool such as Sphinx.

The first step is to use a docstring:

def add(self):
 """ Method which adds stuff
 """

回答 6

除了说“使用文档字符串”外,我将走得更远。选择一个文档生成工具,例如pydoc或epydoc(我在pyparsing中使用epydoc),然后使用该工具可以识别的标记语法。在进行开发时经常运行该工具,以发现文档中的漏洞。实际上,您甚至可以从实现类之前为类的成员编写文档字符串中受益。

I would go a step further than just saying “use a docstring”. Pick a documentation generation tool, such as pydoc or epydoc (I use epydoc in pyparsing), and use the markup syntax recognized by that tool. Run that tool often while you are doing your development, to identify holes in your documentation. In fact, you might even benefit from writing the docstrings for the members of a class before implementing the class.


回答 7

docstrings

这是PyCharm中针对功能描述注释的内置建议约定:

def test_function(p1, p2, p3):
    """
    my function does blah blah blah

    :param p1: 
    :param p2: 
    :param p3: 
    :return: 
    """

Use docstrings.

This is the built-in suggested convention in PyCharm for describing function using docstring comments:

def test_function(p1, p2, p3):
    """
    test_function does blah blah blah.

    :param p1: describe about parameter p1
    :param p2: describe about parameter p2
    :param p3: describe about parameter p3
    :return: describe what it returns
    """ 
    pass

回答 8

虽然我同意这不应该是评论,但应该是大多数(所有?)答案都建议的文档字符串,但我想添加numpydoc(文档字符串样式指南)

如果这样做,您可以(1)自动生成文档,并且(2)人们可以识别出这一点,并且可以更轻松地读取代码。

While I agree that this should not be a comment, but a docstring as most (all?) answers suggest, I want to add numpydoc (a docstring style guide).

If you do it like this, you can (1) automatically generate documentation and (2) people recognize this and have an easier time to read your code.


回答 9

您可以使用三个引号来做到这一点。

您可以使用单引号:

def myfunction(para1,para2):
  '''
  The stuff inside the function
  '''

或双引号:

def myfunction(para1,para2):
  """
  The stuff inside the function
  """

You can use three quotes to do it.

You can use single quotes:

def myfunction(para1,para2):
  '''
  The stuff inside the function
  '''

Or double quotes:

def myfunction(para1,para2):
  """
  The stuff inside the function
  """

什么时候应使用Flask.g?

问题:什么时候应使用Flask.g?

g将请求上下文移动到应用程序上下文瓶0.10,这让我感到困惑的预期用途g

我的理解(对于Flask 0.9)是:

  • g 驻留在请求上下文中,即在请求开始时重新创建,直到结束时可用
  • g旨在用作“请求黑板”,在这里我可以放置与请求持续时间相关的内容(即,在请求的开始处设置一个标志,并在结束时(可能从before_request/ after_request对开始)进行处理)
  • 除了保持请求级别状态外,g还可以并且应该用于资源管理,即保持数据库连接等。

在Flask 0.10中,以下哪句话不再适用?有人可以指点我讨论这种变化原因的资源吗?在Flask 0.10中,我应该将什么用作“请求黑板”?我应该创建自己的应用程序/扩展特定于线程的本地代理并将其推送到上下文堆栈before_request吗?如果我的应用程序生存时间很长(不像请求),因此资源从未被释放,那么在应用程序上下文中资源管理的意义何在?

I saw that g will move from the request context to the app context in Flask 0.10, which made me confused about the intended use of g.

My understanding (for Flask 0.9) is that:

  • g lives in the request context, i.e., created afresh when the requests starts, and available until it ends
  • g is intended to be used as a “request blackboard”, where I can put stuff relevant for the duration of the request (i.e., set a flag at the beginning of the request and handle it at the end, possibly from a before_request/after_request pair)
  • in addition to holding request-level-state, g can and should be used for resource management, i.e., holding database connections, etc.

Which of these sentences are no longer true in Flask 0.10? Can someone point me to a resource discussing the reasons for the change? What should I use as a “request blackboard” in Flask 0.10 – should I create my own app/extension specific thread-local proxy and push it to the context stack before_request? What’s the point of resource management at the application context, if my application lives for a long while (not like a request) and thus the resources are never freed?


回答 0

高级瓶模式,如由马库斯联系,解释了一些变化到g0.10:

  • g 现在位于应用程序上下文中。
  • 每个请求都会推送一个新的应用程序上下文,从而清除旧的应用程序上下文,因此g仍可以用于按请求设置标志,而无需更改代码。
  • 调用 弹出应用程序上下文teardown_request。(Armin的演示文稿解释了这是因为创建数据库连接之类的事情是为请求设置环境的任务,不应在before_request和中处理after_request

Advanced Flask Patterns, as linked by Markus, explains some of the changes to g in 0.10:

  • g now lives in the application context.
  • Every request pushes a new application context, wiping the old one, so g can still be used to set flags per-request without change to code.
  • The application context is popped after teardown_request is called. (Armin’s presentation explains this is because things like creating DB connections are tasks which setup the environment for the request, and should not be handled inside before_request and after_request)

回答 1

作为该线程中信息的附录:我也flask.g对它的行为感到困惑,但是一些快速测试帮助我弄清了它。这是我尝试过的方法:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in first request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to xyz')
        g.foo = 'xyz'
        print('g.foo should be xyz, is: {0}'.format(g.foo))

    print('in app context, after first request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in second request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to pqr')
        g.foo = 'pqr'
        print('g.foo should be pqr, is: {0}'.format(g.foo))

    print('in app context, after second request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

这是它提供的输出:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be abc, is: abc
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in app context, after first request context
g.foo should be abc, is: xyz  

in second request context
g.foo should be abc, is: xyz
setting g.foo to pqr
g.foo should be pqr, is: pqr  

in app context, after second request context
g.foo should be abc, is: pqr

正如Y4Kman所说的那样,“每个请求都推送一个新的应用程序上下文”。而随着烧瓶文档说,应用程序上下文“将不被请求之间共享”。现在,尚未明确说明的内容(尽管我猜想这是这些语句的隐含内容),而我的测试清楚地表明,您永远不应明确创建嵌套在一个应用程序上下文中的多个请求上下文,因为flask.g(和co)没有它具有任何神奇的功能,使其可以在上下文的两个不同“级别”中起作用,并且在应用程序和请求级别独立存在不同的状态。

现实情况是,“应用程序上下文”可能app.app_context() 一个颇具误导性的名称,因为每个请求上下文,与“请求上下文”完全相同。将其视为“请求上下文精简版”,仅在需要一些通常需要请求上下文的变量但不需要访问任何请求对象的情况下才需要(例如,在数据库中运行批处理DB操作时)外壳脚本)。如果您尝试将应用程序上下文扩展为包含多个请求上下文,那么您将遇到麻烦。因此,您应该在Flask的上下文中编写如下代码,而不是上面的测试:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in first request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to xyz')
    g.foo = 'xyz'
    print('g.foo should be xyz, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in second request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to pqr')
    g.foo = 'pqr'
    print('g.foo should be pqr, is: {0}'.format(g.foo))

这将产生预期的结果:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be None, is: None
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in second request context
g.foo should be None, is: None
setting g.foo to pqr
g.foo should be pqr, is: pqr

As an addendum to the information in this thread: I’ve been a bit confused by the behavior of flask.g too, but some quick testing has helped me to clarify it. Here’s what I tried out:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in first request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to xyz')
        g.foo = 'xyz'
        print('g.foo should be xyz, is: {0}'.format(g.foo))

    print('in app context, after first request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in second request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to pqr')
        g.foo = 'pqr'
        print('g.foo should be pqr, is: {0}'.format(g.foo))

    print('in app context, after second request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

And here’s the output that it gives:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be abc, is: abc
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in app context, after first request context
g.foo should be abc, is: xyz  

in second request context
g.foo should be abc, is: xyz
setting g.foo to pqr
g.foo should be pqr, is: pqr  

in app context, after second request context
g.foo should be abc, is: pqr

As theY4Kman said above, “Every request pushes a new application context”. And as the Flask docs say, the application context “will not be shared between requests”. Now, what hasn’t been explicitly stated (although I guess it’s implied from these statements), and what my testing clearly shows, is that you should never explicitly create multiple request contexts nested inside one application context, because flask.g (and co) doesn’t have any magic whereby it functions in the two different “levels” of context, with different states existing independently at the application and request levels.

The reality is that “application context” is potentially quite a misleading name, because app.app_context() is a per-request context, exactly the same as the “request context”. Think of it as a “request context lite”, only required in the case where you need some of the variables that normally require a request context, but you don’t need access to any request object (e.g. when running batch DB operations in a shell script). If you try and extend the application context to encompass more than one request context, you’re asking for trouble. So, rather than my test above, you should instead write code like this with Flask’s contexts:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in first request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to xyz')
    g.foo = 'xyz'
    print('g.foo should be xyz, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in second request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to pqr')
    g.foo = 'pqr'
    print('g.foo should be pqr, is: {0}'.format(g.foo))

Which will give the expected results:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be None, is: None
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in second request context
g.foo should be None, is: None
setting g.foo to pqr
g.foo should be pqr, is: pqr

不区分大小写的替换

问题:不区分大小写的替换

在Python中执行不区分大小写的字符串替换的最简单方法是什么?

What’s the easiest way to do a case-insensitive string replacement in Python?


回答 0

string类型不支持此功能。您最好使用带有re.IGNORECASE选项的正则表达式子方法

>>> import re
>>> insensitive_hippo = re.compile(re.escape('hippo'), re.IGNORECASE)
>>> insensitive_hippo.sub('giraffe', 'I want a hIPpo for my birthday')
'I want a giraffe for my birthday'

The string type doesn’t support this. You’re probably best off using the regular expression sub method with the re.IGNORECASE option.

>>> import re
>>> insensitive_hippo = re.compile(re.escape('hippo'), re.IGNORECASE)
>>> insensitive_hippo.sub('giraffe', 'I want a hIPpo for my birthday')
'I want a giraffe for my birthday'

回答 1

import re
pattern = re.compile("hello", re.IGNORECASE)
pattern.sub("bye", "hello HeLLo HELLO")
# 'bye bye bye'
import re
pattern = re.compile("hello", re.IGNORECASE)
pattern.sub("bye", "hello HeLLo HELLO")
# 'bye bye bye'

回答 2

在一行中:

import re
re.sub("(?i)hello","bye", "hello HeLLo HELLO") #'bye bye bye'
re.sub("(?i)he\.llo","bye", "he.llo He.LLo HE.LLO") #'bye bye bye'

或者,使用可选的“标志”参数:

import re
re.sub("hello", "bye", "hello HeLLo HELLO", flags=re.I) #'bye bye bye'
re.sub("he\.llo", "bye", "he.llo He.LLo HE.LLO", flags=re.I) #'bye bye bye'

In a single line:

import re
re.sub("(?i)hello","bye", "hello HeLLo HELLO") #'bye bye bye'
re.sub("(?i)he\.llo","bye", "he.llo He.LLo HE.LLO") #'bye bye bye'

Or, use the optional “flags” argument:

import re
re.sub("hello", "bye", "hello HeLLo HELLO", flags=re.I) #'bye bye bye'
re.sub("he\.llo", "bye", "he.llo He.LLo HE.LLO", flags=re.I) #'bye bye bye'

回答 3

继续bFloch的回答,此功能将不改变任何一种,而是将所有旧出现的内容更改为新内容-以不区分大小写的方式。

def ireplace(old, new, text):
    idx = 0
    while idx < len(text):
        index_l = text.lower().find(old.lower(), idx)
        if index_l == -1:
            return text
        text = text[:index_l] + new + text[index_l + len(old):]
        idx = index_l + len(new) 
    return text

Continuing on bFloch’s answer, this function will change not one, but all occurrences of old with new – in a case insensitive fashion.

def ireplace(old, new, text):
    idx = 0
    while idx < len(text):
        index_l = text.lower().find(old.lower(), idx)
        if index_l == -1:
            return text
        text = text[:index_l] + new + text[index_l + len(old):]
        idx = index_l + len(new) 
    return text

回答 4

就像布莱尔·康拉德(Blair Conrad)所说的那样,string.replace不支持这一点。

使用regex re.sub,但请记住先转义替换字符串。请注意,在2.6中没有for的flags-option re.sub,因此您必须使用Embedded修饰符'(?i)'(或RE对象,请参阅Blair Conrad的答案)。另外,另一个陷阱是,如果给出了字符串,sub将在替换文本中处理反斜杠转义。为了避免这种情况,可以传入lambda。

这是一个函数:

import re
def ireplace(old, repl, text):
    return re.sub('(?i)'+re.escape(old), lambda m: repl, text)

>>> ireplace('hippo?', 'giraffe!?', 'You want a hiPPO?')
'You want a giraffe!?'
>>> ireplace(r'[binfolder]', r'C:\Temp\bin', r'[BinFolder]\test.exe')
'C:\\Temp\\bin\\test.exe'

Like Blair Conrad says string.replace doesn’t support this.

Use the regex re.sub, but remember to escape the replacement string first. Note that there’s no flags-option in 2.6 for re.sub, so you’ll have to use the embedded modifier '(?i)' (or a RE-object, see Blair Conrad’s answer). Also, another pitfall is that sub will process backslash escapes in the replacement text, if a string is given. To avoid this one can instead pass in a lambda.

Here’s a function:

import re
def ireplace(old, repl, text):
    return re.sub('(?i)'+re.escape(old), lambda m: repl, text)

>>> ireplace('hippo?', 'giraffe!?', 'You want a hiPPO?')
'You want a giraffe!?'
>>> ireplace(r'[binfolder]', r'C:\Temp\bin', r'[BinFolder]\test.exe')
'C:\\Temp\\bin\\test.exe'

回答 5

此函数同时使用str.replace()re.findall()函数。它将以不区分大小写的方式替换patternin中所有出现的情况。stringrepl

def replace_all(pattern, repl, string) -> str:
   occurences = re.findall(pattern, string, re.IGNORECASE)
   for occurence in occurences:
       string = string.replace(occurence, repl)
       return string

This function uses both the str.replace() and re.findall() functions. It will replace all occurences of pattern in string with repl in a case-insensitive way.

def replace_all(pattern, repl, string) -> str:
   occurences = re.findall(pattern, string, re.IGNORECASE)
   for occurence in occurences:
       string = string.replace(occurence, repl)
       return string

回答 6

这不需要RegularExp

def ireplace(old, new, text):
    """ 
    Replace case insensitive
    Raises ValueError if string not found
    """
    index_l = text.lower().index(old.lower())
    return text[:index_l] + new + text[index_l + len(old):] 

This doesn’t require RegularExp

def ireplace(old, new, text):
    """ 
    Replace case insensitive
    Raises ValueError if string not found
    """
    index_l = text.lower().index(old.lower())
    return text[:index_l] + new + text[index_l + len(old):] 

回答 7

关于语法细节和选项的有趣观察:

在Win32上的Python 3.7.2(tags / v3.7.2:9a3ffc0492,2018年12月23日,23:09:28)[MSC v.1916 64位(AMD64)]

import re
old = "TREEROOT treeroot TREerOot"
re.sub(r'(?i)treeroot', 'grassroot', old)

‘草根草根草根’

re.sub(r'treeroot', 'grassroot', old)

‘TREEROOT草根TREerOot’

re.sub(r'treeroot', 'grassroot', old, flags=re.I)

‘草根草根草根’

re.sub(r'treeroot', 'grassroot', old, re.I)

‘TREEROOT草根TREerOot’

因此,match表达式中的(?i)前缀或添加“ flags = re.I”作为第四个参数将导致不区分大小写的匹配。但是,仅使用“ re.I”作为第四个参数不会导致不区分大小写的匹配。

为了比较,

re.findall(r'treeroot', old, re.I)

[‘TREEROOT’,’treeroot’,’TREerOot’]

re.findall(r'treeroot', old)

[‘treeroot’]

An interesting observation about syntax details and options:

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32

import re
old = "TREEROOT treeroot TREerOot"
re.sub(r'(?i)treeroot', 'grassroot', old)

‘grassroot grassroot grassroot’

re.sub(r'treeroot', 'grassroot', old)

‘TREEROOT grassroot TREerOot’

re.sub(r'treeroot', 'grassroot', old, flags=re.I)

‘grassroot grassroot grassroot’

re.sub(r'treeroot', 'grassroot', old, re.I)

‘TREEROOT grassroot TREerOot’

So the (?i) prefix in the match expression or adding “flags=re.I” as a fourth argument will result in a case-insensitive match. BUT, using just “re.I” as the fourth argument does not result in case-insensitive match.

For comparison,

re.findall(r'treeroot', old, re.I)

[‘TREEROOT’, ‘treeroot’, ‘TREerOot’]

re.findall(r'treeroot', old)

[‘treeroot’]


回答 8

我正在将\ t转换为转义序列(向下滚动),因此我注意到re.sub将反斜杠的转义字符转换为转义序列。

为了防止这种情况,我写了以下内容:

替换不区分大小写。

import re
    def ireplace(findtxt, replacetxt, data):
        return replacetxt.join(  re.compile(findtxt, flags=re.I).split(data)  )

另外,如果您希望将其替换为转义字符,例如此处的其他答案,这些特殊含义是将bashslash字符转换为转义序列,则只需对您的查找和解码,或替换字符串即可。在Python 3中,可能必须执行类似.decode(“ unicode_escape”)#python3的操作

findtxt = findtxt.decode('string_escape') # python2
replacetxt = replacetxt.decode('string_escape') # python2
data = ireplace(findtxt, replacetxt, data)

在Python 2.7.8中测试

希望有帮助。

I was having \t being converted to the escape sequences (scroll a bit down), so I noted that re.sub converts backslashed escaped characters to escape sequences.

To prevent that I wrote the following:

Replace case insensitive.

import re
    def ireplace(findtxt, replacetxt, data):
        return replacetxt.join(  re.compile(findtxt, flags=re.I).split(data)  )

Also, if you want it to replace with the escape characters, like the other answers here that are getting the special meaning bashslash characters converted to escape sequences, just decode your find and, or replace string. In Python 3, might have to do something like .decode(“unicode_escape”) # python3

findtxt = findtxt.decode('string_escape') # python2
replacetxt = replacetxt.decode('string_escape') # python2
data = ireplace(findtxt, replacetxt, data)

Tested in Python 2.7.8

Hope that helps.


回答 9

之前从未发布过答案,并且该线程确实很旧,但是我想出了另一种解决方案,并认为我可以得到您的回应,我在Python编程中经验不足,因此,如果它有明显的缺点,请指出来,因为它的良好学习是: )

i='I want a hIPpo for my birthday'
key='hippo'
swp='giraffe'

o=(i.lower().split(key))
c=0
p=0
for w in o:
    o[c]=i[p:p+len(w)]
    p=p+len(key+w)
    c+=1
print(swp.join(o))

never posted an answer before and this thread is really old but i came up with another sollution and figured i could get your respons, Im not seasoned in Python programming so if there are appearant drawbacks to it, please point them out since its good learning :)

i='I want a hIPpo for my birthday'
key='hippo'
swp='giraffe'

o=(i.lower().split(key))
c=0
p=0
for w in o:
    o[c]=i[p:p+len(w)]
    p=p+len(key+w)
    c+=1
print(swp.join(o))

如何在Django中过滤DateTimeField的日期?

问题:如何在Django中过滤DateTimeField的日期?

我试图过滤DateTimeField与日期比较。我的意思是:

MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))

我得到一个空的查询集列表作为答案,因为(我认为)我不在考虑时间,但我希望“任何时间”。

Django中有一种简单的方法吗?

我在datetime中设置了时间,但不是00:00

I am trying to filter a DateTimeField comparing with a date. I mean:

MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))

I get an empty queryset list as an answer because (I think) I am not considering time, but I want “any time”.

Is there an easy way in Django for doing this?

I have the time in the datetime setted, it is not 00:00.


回答 0

此类查询的实现django.views.generic.date_based方式如下:

{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
                            datetime.datetime.combine(date, datetime.time.max))} 

因为它很冗长,所以有计划使用__date运算符来改进语法。有关更多详细信息,请检查“ #9596将DateTimeField与日期比较太难 ”。

Such lookups are implemented in django.views.generic.date_based as follows:

{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
                            datetime.datetime.combine(date, datetime.time.max))} 

Because it is quite verbose there are plans to improve the syntax using __date operator. Check “#9596 Comparing a DateTimeField to a date is too hard” for more details.


回答 1

YourModel.objects.filter(datetime_published__year='2008', 
                         datetime_published__month='03', 
                         datetime_published__day='27')

//在评论后编辑

YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))

不起作用,因为它创建了一个时间值设置为0的datetime对象,因此数据库中的时间不匹配。

YourModel.objects.filter(datetime_published__year='2008', 
                         datetime_published__month='03', 
                         datetime_published__day='27')

// edit after comments

YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))

doest not work because it creates a datetime object with time values set to 0, so the time in database doesn’t match.


回答 2

这是我使用ipython的timeit函数得到的结果:

from datetime import date
today = date.today()

timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop

timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop

timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop

timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop

包含似乎更快。

Here are the results I got with ipython’s timeit function:

from datetime import date
today = date.today()

timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop

timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop

timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop

timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop

contains seems to be faster.


回答 3

现在,Django具有__date queryset过滤器,可以针对开发版本中的日期查询datetime对象。因此,它将很快在1.9中可用。

Now Django has __date queryset filter to query datetime objects against dates in development version. Thus, it will be available in 1.9 soon.


回答 4

Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

以上是我用过的。它不仅有效,而且还具有一些固有的逻辑支持。

Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

the above is what I’ve used. Not only does it work, it also has some inherent logical backing.


回答 5

从Django 1.9开始,执行此操作的方法是__date在datetime对象上使用。

例如: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))

As of Django 1.9, the way to do this is by using __date on a datetime object.

For example: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


回答 6

这产生与使用__year,__ month和__day相同的结果,并且似乎对我有用:

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))

This produces the same results as using __year, __month, and __day and seems to work for me:

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))

回答 7

假设active_on是一个日期对象,将其增加1天,然后进行范围调整

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )

assuming active_on is a date object, increment it by 1 day then do range

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )

回答 8

这是一种有趣的技术-我利用在Django上在MySQL上实现的startswith过程来实现只在日期中查找日期时间的结果。基本上,当Django在数据库中进行查找时,它必须对DATETIME MySQL存储对象进行字符串转换,因此您可以对此进行过滤,而忽略日期的时间戳部分-这样%LIKE%仅与日期匹配对象,您将获得给定日期的每个时间戳。

datetime_filter = datetime(2009, 8, 22) 
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())

这将执行以下查询:

SELECT (values) FROM myapp_my_object \ 
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%

在这种情况下,无论时间戳如何,LIKE BINARY都将匹配日期中的所有内容。包括以下值:

+---------------------+
| datetime_attr       |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+

希望这对所有人都有帮助,直到Django提出解决方案为止!

Here is an interesting technique– I leveraged the startswith procedure as implemented with Django on MySQL to achieve the result of only looking up a datetime through only the date. Basically, when Django does the lookup in the database it has to do a string conversion for the DATETIME MySQL storage object, so you can filter on that, leaving out the timestamp portion of the date– that way %LIKE% matches only the date object and you’ll get every timestamp for the given date.

datetime_filter = datetime(2009, 8, 22) 
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())

This will perform the following query:

SELECT (values) FROM myapp_my_object \ 
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%

The LIKE BINARY in this case will match everything for the date, no matter the timestamp. Including values like:

+---------------------+
| datetime_attr       |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+

Hopefully this helps everyone until Django comes out with a solution!


回答 9

这里有一篇很棒的博客文章:在Django ORM中比较日期和日期时间

为Django> 1.7,<1.9发布的最佳解决方案是注册一个转换:

from django.db import models

class MySQLDatetimeDate(models.Transform):
    """
    This implements a custom SQL lookup when using `__date` with datetimes.
    To enable filtering on datetimes that fall on a given date, import
    this transform and register it with the DateTimeField.
    """
    lookup_name = 'date'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return 'DATE({})'.format(lhs), params

    @property
    def output_field(self):
        return models.DateField()

然后可以在过滤器中使用它,如下所示:

Foo.objects.filter(created_on__date=date)

编辑

此解决方案绝对取决于后端。从文章:

当然,此实现依赖于具有DATE()函数的SQL的特定风格。MySQL确实如此。SQLite也是如此。另一方面,我还没有亲自使用PostgreSQL,但是通过谷歌搜索使我相信它没有DATE()函数。因此,这种简单的实现似乎必然与后端有关。

There’s a fantastic blogpost that covers this here: Comparing Dates and Datetimes in the Django ORM

The best solution posted for Django>1.7,<1.9 is to register a transform:

from django.db import models

class MySQLDatetimeDate(models.Transform):
    """
    This implements a custom SQL lookup when using `__date` with datetimes.
    To enable filtering on datetimes that fall on a given date, import
    this transform and register it with the DateTimeField.
    """
    lookup_name = 'date'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return 'DATE({})'.format(lhs), params

    @property
    def output_field(self):
        return models.DateField()

Then you can use it in your filters like this:

Foo.objects.filter(created_on__date=date)

EDIT

This solution is definitely back end dependent. From the article:

Of course, this implementation relies on your particular flavor of SQL having a DATE() function. MySQL does. So does SQLite. On the other hand, I haven’t worked with PostgreSQL personally, but some googling leads me to believe that it does not have a DATE() function. So an implementation this simple seems like it will necessarily be somewhat backend-dependent.


回答 10

嗯..我的解决方案正在工作:

Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))

Hm.. My solution is working:

Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))

回答 11

Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)

回答 12

在Django 1.7.6中工作:

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))

In Django 1.7.6 works:

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))

回答 13

请参阅文章Django文档

ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))

See the article Django Documentation

ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))

在类方法上使用property()

问题:在类方法上使用property()

我有一个带有两个类方法的类(使用classmethod()函数),用于获取和设置本质上是静态变量的东西。我试图将property()函数与这些函数一起使用,但是会导致错误。我能够在解释器中使用以下代码重现该错误:

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

我可以演示类方法,但是它们不能用作属性:

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

是否可以将property()函数与装饰有类方法的函数一起使用?

I have a class with two class methods (using the classmethod() function) for getting and setting what is essentially a static variable. I tried to use the property() function with these, but it results in an error. I was able to reproduce the error with the following in the interpreter:

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

I can demonstrate the class methods, but they don’t work as properties:

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

Is it possible to use the property() function with classmethod decorated functions?


回答 0

属性是在类上创建的,但会影响实例。因此,如果要使用classmethod属性,请在元类上创建该属性。

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

但是由于无论如何都使用元类,所以只要将类方法移入其中,它就会更好看。

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

或者,使用Python 3的metaclass=...语法,在foo类主体外部定义的元类,以及负责设置初始值的元类_var

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

A property is created on a class but affects an instance. So if you want a classmethod property, create the property on the metaclass.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

But since you’re using a metaclass anyway, it will read better if you just move the classmethods in there.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

or, using Python 3’s metaclass=... syntax, and the metaclass defined outside of the foo class body, and the metaclass responsible for setting the initial value of _var:

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

回答 1

阅读Python 2.2发行说明,我发现以下内容。

当作为类属性(Cx)而不是实例属性(C()。x)访问该属性时,将不会调用[属性的] get方法。如果要在用作类属性时覆盖属性的__get__操作,则可以子类化属性-它本身是一种新型类型-扩展其__get__方法,或者可以通过创建新的属性来从头定义描述符类型风格的类,它定义__get __,__ set__和__delete__方法。

注意:以下方法实际上不适用于setter方法,仅适用于getter方法。

因此,我相信规定的解决方案是创建一个ClassProperty作为属性的子类。

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

但是,设置员实际上不起作用:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var 保持不变,您只需用新值覆盖属性即可。

您还可以ClassProperty用作装饰器:

class foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5

Reading the Python 2.2 release notes, I find the following.

The get method [of a property] won’t be called when the property is accessed as a class attribute (C.x) instead of as an instance attribute (C().x). If you want to override the __get__ operation for properties when used as a class attribute, you can subclass property – it is a new-style type itself – to extend its __get__ method, or you can define a descriptor type from scratch by creating a new-style class that defines __get__, __set__ and __delete__ methods.

NOTE: The below method doesn’t actually work for setters, only getters.

Therefore, I believe the prescribed solution is to create a ClassProperty as a subclass of property.

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

However, the setters don’t actually work:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var is unchanged, you’ve simply overwritten the property with a new value.

You can also use ClassProperty as a decorator:

class foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5

回答 2

我希望这个简单的只读@classproperty装饰器可以帮助寻找类属性的人。

class classproperty(object):

    def __init__(self, fget):
        self.fget = fget

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class C(object):

    @classproperty
    def x(cls):
        return 1

assert C.x == 1
assert C().x == 1

I hope this dead-simple read-only @classproperty decorator would help somebody looking for classproperties.

class classproperty(object):

    def __init__(self, fget):
        self.fget = fget

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class C(object):

    @classproperty
    def x(cls):
        return 1

assert C.x == 1
assert C().x == 1

回答 3

是否可以将property()函数与装饰有类方法的函数一起使用?

没有。

但是,类方法只是从类的实例可访问的类上的绑定方法(部分函数)。

由于实例是类的函数,并且您可以从实例派生该类,因此您可以使用property

class Example(object):
    _class_property = None
    @property
    def class_property(self):
        return self._class_property
    @class_property.setter
    def class_property(self, value):
        type(self)._class_property = value
    @class_property.deleter
    def class_property(self):
        del type(self)._class_property

此代码可用于测试-它应该通过而不会引起任何错误:

ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')

请注意,我们根本不需要元类-而且您也不会直接通过其类的实例直接访问元类。

写一个@classproperty装饰

实际上,您可以classproperty通过子类化在几行代码中创建一个装饰器property(它是用C实现的,但是您可以在此处看到等效的Python ):

class classproperty(property):
    def __get__(self, obj, objtype=None):
        return super(classproperty, self).__get__(objtype)
    def __set__(self, obj, value):
        super(classproperty, self).__set__(type(obj), value)
    def __delete__(self, obj):
        super(classproperty, self).__delete__(type(obj))

然后,将装饰器视为结合了属性的类方法:

class Foo(object):
    _bar = 5
    @classproperty
    def bar(cls):
        """this is the bar attribute - each subclass of Foo gets its own.
        Lookups should follow the method resolution order.
        """
        return cls._bar
    @bar.setter
    def bar(cls, value):
        cls._bar = value
    @bar.deleter
    def bar(cls):
        del cls._bar

这段代码应该可以正常工作:

def main():
    f = Foo()
    print(f.bar)
    f.bar = 4
    print(f.bar)
    del f.bar
    try:
        f.bar
    except AttributeError:
        pass
    else:
        raise RuntimeError('f.bar must have worked - inconceivable!')
    help(f)  # includes the Foo.bar help.
    f.bar = 5

    class Bar(Foo):
        "a subclass of Foo, nothing more"
    help(Bar) # includes the Foo.bar help!
    b = Bar()
    b.bar = 'baz'
    print(b.bar) # prints baz
    del b.bar
    print(b.bar) # prints 5 - looked up from Foo!

    
if __name__ == '__main__':
    main()

但是我不确定这将是多么明智。旧的邮件列表文章建议它不起作用。

使该属性在类上起作用:

上面的缺点是无法从类中访问“类属性”,因为它只会覆盖类中的数据描述符__dict__

但是,我们可以使用metaclass中定义的属性来覆盖它__dict__。例如:

class MetaWithFooClassProperty(type):
    @property
    def foo(cls):
        """The foo property is a function of the class -
        in this case, the trivial case of the identity function.
        """
        return cls

然后,元类的类实例可以具有一个属性,该属性使用前面部分中已经说明的原理来访问类的属性:

class FooClassProperty(metaclass=MetaWithFooClassProperty):
    @property
    def foo(self):
        """access the class's property"""
        return type(self).foo

现在我们看到两个实例

>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>

和Class

>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>

有权访问class属性。

Is it possible to use the property() function with classmethod decorated functions?

No.

However, a classmethod is simply a bound method (a partial function) on a class accessible from instances of that class.

Since the instance is a function of the class and you can derive the class from the instance, you can can get whatever desired behavior you might want from a class-property with property:

class Example(object):
    _class_property = None
    @property
    def class_property(self):
        return self._class_property
    @class_property.setter
    def class_property(self, value):
        type(self)._class_property = value
    @class_property.deleter
    def class_property(self):
        del type(self)._class_property

This code can be used to test – it should pass without raising any errors:

ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')

And note that we didn’t need metaclasses at all – and you don’t directly access a metaclass through its classes’ instances anyways.

writing a @classproperty decorator

You can actually create a classproperty decorator in just a few lines of code by subclassing property (it’s implemented in C, but you can see equivalent Python here):

class classproperty(property):
    def __get__(self, obj, objtype=None):
        return super(classproperty, self).__get__(objtype)
    def __set__(self, obj, value):
        super(classproperty, self).__set__(type(obj), value)
    def __delete__(self, obj):
        super(classproperty, self).__delete__(type(obj))

Then treat the decorator as if it were a classmethod combined with property:

class Foo(object):
    _bar = 5
    @classproperty
    def bar(cls):
        """this is the bar attribute - each subclass of Foo gets its own.
        Lookups should follow the method resolution order.
        """
        return cls._bar
    @bar.setter
    def bar(cls, value):
        cls._bar = value
    @bar.deleter
    def bar(cls):
        del cls._bar

And this code should work without errors:

def main():
    f = Foo()
    print(f.bar)
    f.bar = 4
    print(f.bar)
    del f.bar
    try:
        f.bar
    except AttributeError:
        pass
    else:
        raise RuntimeError('f.bar must have worked - inconceivable!')
    help(f)  # includes the Foo.bar help.
    f.bar = 5

    class Bar(Foo):
        "a subclass of Foo, nothing more"
    help(Bar) # includes the Foo.bar help!
    b = Bar()
    b.bar = 'baz'
    print(b.bar) # prints baz
    del b.bar
    print(b.bar) # prints 5 - looked up from Foo!

    
if __name__ == '__main__':
    main()

But I’m not sure how well-advised this would be. An old mailing list article suggests it shouldn’t work.

Getting the property to work on the class:

The downside of the above is that the “class property” isn’t accessible from the class, because it would simply overwrite the data descriptor from the class __dict__.

However, we can override this with a property defined in the metaclass __dict__. For example:

class MetaWithFooClassProperty(type):
    @property
    def foo(cls):
        """The foo property is a function of the class -
        in this case, the trivial case of the identity function.
        """
        return cls

And then a class instance of the metaclass could have a property that accesses the class’s property using the principle already demonstrated in the prior sections:

class FooClassProperty(metaclass=MetaWithFooClassProperty):
    @property
    def foo(self):
        """access the class's property"""
        return type(self).foo

And now we see both the instance

>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>

and the class

>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>

have access to the class property.


回答 4

Python 3!

老问题,很多观点,迫切需要一种真正的Python 3方法。

幸运的是,使用metaclasskwarg 很容易:

class FooProperties(type):

    @property
    def var(cls):
        return cls._var

class Foo(object, metaclass=FooProperties):
    _var = 'FOO!'

然后, >>> Foo.var

“ F!”

Python 3!

Old question, lots of views, sorely in need of a one-true Python 3 way.

Luckily, it’s easy with the metaclass kwarg:

class FooProperties(type):

    @property
    def var(cls):
        return cls._var

class Foo(object, metaclass=FooProperties):
    _var = 'FOO!'

Then, >>> Foo.var

‘FOO!’


回答 5

没有合理的方法可以使此“类属性”系统在Python中运行。

这是使其工作的一种不合理的方法。当然,您可以通过增加大量的元类魔术来使其变得更加无缝。

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

问题的根源在于属性是Python所谓的“描述符”。没有简单快捷的方法来解释这种元编程的工作原理,因此我必须将您指向描述符howto

如果您要实现相当高级的框架,则只需要了解这种情况即可。就像透明的对象持久性或RPC系统,或一种特定于域的语言。

但是,在对上一个答案的评论中,您说

需要修改一个属性,该属性可以被类的所有实例看到,并且在调用这些类方法的范围内,该属性不具有对该类所有实例的引用。

在我看来,您真正想要的是观察者设计模式。

There is no reasonable way to make this “class property” system to work in Python.

Here is one unreasonable way to make it work. You can certainly make it more seamless with increasing amounts of metaclass magic.

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

The knot of the issue is that properties are what Python calls “descriptors”. There is no short and easy way to explain how this sort of metaprogramming works, so I must point you to the descriptor howto.

You only ever need to understand this sort of things if you are implementing a fairly advanced framework. Like a transparent object persistence or RPC system, or a kind of domain-specific language.

However, in a comment to a previous answer, you say that you

need to modify an attribute that in such a way that is seen by all instances of a class, and in the scope from which these class methods are called does not have references to all instances of the class.

It seems to me, what you really want is an Observer design pattern.


回答 6

如果您想通过实例化的对象访问class属性,则仅在meta类上设置它无济于事,在这种情况下,您还需要在该对象上安装一个常规属性(该属性将分派到class属性)。我认为以下内容更加清楚:

#!/usr/bin/python

class classproperty(property):
    def __get__(self, obj, type_):
        return self.fget.__get__(None, type_)()

    def __set__(self, obj, value):
        cls = type(obj)
        return self.fset.__get__(None, cls)(value)

class A (object):

    _foo = 1

    @classproperty
    @classmethod
    def foo(cls):
        return cls._foo

    @foo.setter
    @classmethod
    def foo(cls, value):
        cls.foo = value

a = A()

print a.foo

b = A()

print b.foo

b.foo = 5

print a.foo

A.foo = 10

print b.foo

print A.foo

Setting it only on the meta class doesn’t help if you want to access the class property via an instantiated object, in this case you need to install a normal property on the object as well (which dispatches to the class property). I think the following is a bit more clear:

#!/usr/bin/python

class classproperty(property):
    def __get__(self, obj, type_):
        return self.fget.__get__(None, type_)()

    def __set__(self, obj, value):
        cls = type(obj)
        return self.fset.__get__(None, cls)(value)

class A (object):

    _foo = 1

    @classproperty
    @classmethod
    def foo(cls):
        return cls._foo

    @foo.setter
    @classmethod
    def foo(cls, value):
        cls.foo = value

a = A()

print a.foo

b = A()

print b.foo

b.foo = 5

print a.foo

A.foo = 10

print b.foo

print A.foo

回答 7

半个解决方案,在类上__set__仍然无效。解决方案是实现属性和静态方法的自定义属性类

class ClassProperty(object):
    def __init__(self, fget, fset):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        return self.fget()

    def __set__(self, instance, value):
        self.fset(value)

class Foo(object):
    _bar = 1
    def get_bar():
        print 'getting'
        return Foo._bar

    def set_bar(value):
        print 'setting'
        Foo._bar = value

    bar = ClassProperty(get_bar, set_bar)

f = Foo()
#__get__ works
f.bar
Foo.bar

f.bar = 2
Foo.bar = 3 #__set__ does not

Half a solution, __set__ on the class does not work, still. The solution is a custom property class implementing both a property and a staticmethod

class ClassProperty(object):
    def __init__(self, fget, fset):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        return self.fget()

    def __set__(self, instance, value):
        self.fset(value)

class Foo(object):
    _bar = 1
    def get_bar():
        print 'getting'
        return Foo._bar

    def set_bar(value):
        print 'setting'
        Foo._bar = value

    bar = ClassProperty(get_bar, set_bar)

f = Foo()
#__get__ works
f.bar
Foo.bar

f.bar = 2
Foo.bar = 3 #__set__ does not

回答 8

因为我需要修改一个属性,使得该属性可以被类的所有实例看到,并且在调用这些类方法的范围内,不能引用该类的所有实例。

您是否有权访问该类的至少一个实例?我可以想到一种方法:

class MyClass (object):
    __var = None

    def _set_var (self, value):
        type (self).__var = value

    def _get_var (self):
        return self.__var

    var = property (_get_var, _set_var)

a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var

Because I need to modify an attribute that in such a way that is seen by all instances of a class, and in the scope from which these class methods are called does not have references to all instances of the class.

Do you have access to at least one instance of the class? I can think of a way to do it then:

class MyClass (object):
    __var = None

    def _set_var (self, value):
        type (self).__var = value

    def _get_var (self):
        return self.__var

    var = property (_get_var, _set_var)

a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var

回答 9

试试看,无需更改/添加大量现有代码即可完成工作。

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

property函数需要两个callable参数。给他们lambda包装器(它将实例作为第一个参数传递),一切都很好。

Give this a try, it gets the job done without having to change/add a lot of existing code.

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

The property function needs two callable arguments. give them lambda wrappers (which it passes the instance as its first argument) and all is well.


回答 10

这是一个既可以通过类访问又可以通过使用元类的实例访问的解决方案。

In [1]: class ClassPropertyMeta(type):
   ...:     @property
   ...:     def prop(cls):
   ...:         return cls._prop
   ...:     def __new__(cls, name, parents, dct):
   ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
   ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
   ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
   ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
   ...:

In [2]: class ClassProperty(object):
   ...:     __metaclass__ = ClassPropertyMeta
   ...:     _prop = 42
   ...:     def __getattr__(self, attr):
   ...:         raise Exception('Never gets called')
   ...:

In [3]: ClassProperty.prop
Out[3]: 42

In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1

AttributeError: can't set attribute

In [5]: cp = ClassProperty()

In [6]: cp.prop
Out[6]: 42

In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1

<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
      6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
      7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
      9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)

AttributeError: can't set attribute

这也适用于在元类中定义的设置器。

Here’s a solution which should work for both access via the class and access via an instance which uses a metaclass.

In [1]: class ClassPropertyMeta(type):
   ...:     @property
   ...:     def prop(cls):
   ...:         return cls._prop
   ...:     def __new__(cls, name, parents, dct):
   ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
   ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
   ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
   ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
   ...:

In [2]: class ClassProperty(object):
   ...:     __metaclass__ = ClassPropertyMeta
   ...:     _prop = 42
   ...:     def __getattr__(self, attr):
   ...:         raise Exception('Never gets called')
   ...:

In [3]: ClassProperty.prop
Out[3]: 42

In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1

AttributeError: can't set attribute

In [5]: cp = ClassProperty()

In [6]: cp.prop
Out[6]: 42

In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1

<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
      6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
      7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
      9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)

AttributeError: can't set attribute

This also works with a setter defined in the metaclass.


回答 11

在搜索了不同的位置后,我找到了一种方法,该方法定义一个在Python 2和3中有效的类属性。

from future.utils import with_metaclass

class BuilderMetaClass(type):
    @property
    def load_namespaces(self):
        return (self.__sourcepath__)

class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
    __sourcepath__ = 'sp'        

print(BuilderMixin.load_namespaces)

希望这可以帮助某人:)

After searching different places, I found a method to define a classproperty valid with Python 2 and 3.

from future.utils import with_metaclass

class BuilderMetaClass(type):
    @property
    def load_namespaces(self):
        return (self.__sourcepath__)

class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
    __sourcepath__ = 'sp'        

print(BuilderMixin.load_namespaces)

Hope this can help somebody :)


回答 12

这是我的建议。不要使用类方法。

说真的

在这种情况下使用类方法的原因是什么?为什么不具有普通类的普通对象?


如果您只是想更改值,那么属性不是真的很有帮助吗?只需设置属性值并完成操作即可。

仅在需要隐藏某些内容时才使用属性-在将来的实现中可能会更改的内容。

也许您的示例被精简了,但您还没有进行一些令人毛骨悚然的计算。但是,该属性看起来并没有带来明显的价值。

受Java影响的“隐私”技术(在Python中,以_开头的属性名称)并不是很有帮助。私人来自谁?当您拥有源代码时(就像在Python中一样),私有点有点模糊。

Java风格的EJB风格的getter和setter(通常在Python中作为属性完成)在那里可以促进Java的原始自省以及将静态语言编译器传递到集合。所有这些getter和setter在Python中都没有帮助。

Here’s my suggestion. Don’t use class methods.

Seriously.

What’s the reason for using class methods in this case? Why not have an ordinary object of an ordinary class?


If you simply want to change the value, a property isn’t really very helpful is it? Just set the attribute value and be done with it.

A property should only be used if there’s something to conceal — something that might change in a future implementation.

Maybe your example is way stripped down, and there is some hellish calculation you’ve left off. But it doesn’t look like the property adds significant value.

The Java-influenced “privacy” techniques (in Python, attribute names that begin with _) aren’t really very helpful. Private from whom? The point of private is a little nebulous when you have the source (as you do in Python.)

The Java-influenced EJB-style getters and setters (often done as properties in Python) are there to facilitate Java’s primitive introspection as well as to pass muster with the static language compiler. All those getters and setters aren’t as helpful in Python.


Python中的’@ =’符号是什么?

问题:Python中的’@ =’符号是什么?

我知道@是给装饰器用的,但是@=Python有什么用呢?只是保留一些未来的想法吗?

这只是我阅读时遇到的许多问题之一tokenizer.py

I know @ is for decorators, but what is @= for in Python? Is it just reservation for some future idea?

This is just one of my many questions while reading tokenizer.py.


回答 0

文档

@(在)操作者意图被用于矩阵乘法。没有内置的Python类型实现此运算符。

@运算符是在Python 3.5中引入的。@=正如您所期望的那样,是矩阵乘法,后跟赋值。它们映射到__matmul____rmatmul____imatmul__类似于如何++=映射__add____radd____iadd__

PEP 465中详细讨论了操作员及其背后的原理。

From the documentation:

The @ (at) operator is intended to be used for matrix multiplication. No builtin Python types implement this operator.

The @ operator was introduced in Python 3.5. @= is matrix multiplication followed by assignment, as you would expect. They map to __matmul__, __rmatmul__ or __imatmul__ similar to how + and += map to __add__, __radd__ or __iadd__.

The operator and the rationale behind it are discussed in detail in PEP 465.


回答 1

@=@是Python 3.5中引入的用于执行矩阵乘法的新运算符。它们的目的是澄清迄今为止​​与运算符之间存在的混淆,该运算符*根据该特定库/代码中采用的约定用于元素方式乘法或矩阵乘法。结果,将来,运营商*只能用于按元素乘法。

PEP0465中所述,引入了两个运算符:

  • 一个新的二进制运算符A @ B,与A * B
  • 就地版本A @= B,与A *= B

矩阵乘法与按元素乘法

为了快速突出区别,对于两个矩阵:

A = [[1, 2],    B = [[11, 12],
     [3, 4]]         [13, 14]]
  • 逐元素乘法将生成:

    A * B = [[1 * 11,   2 * 12], 
             [3 * 13,   4 * 14]]
  • 矩阵乘法将生成:

    A @ B  =  [[1 * 11 + 2 * 13,   1 * 12 + 2 * 14],
               [3 * 11 + 4 * 13,   3 * 12 + 4 * 14]]

在Numpy中使用

到目前为止,Numpy使用以下约定:

@运算符的引入使涉及矩阵乘法的代码更易于阅读。PEP0465举了一个例子:

# Current implementation of matrix multiplications using dot function
S = np.dot((np.dot(H, beta) - r).T,
            np.dot(inv(np.dot(np.dot(H, V), H.T)), np.dot(H, beta) - r))

# Current implementation of matrix multiplications using dot method
S = (H.dot(beta) - r).T.dot(inv(H.dot(V).dot(H.T))).dot(H.dot(beta) - r)

# Using the @ operator instead
S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r)

显然,最后一种实现更易于阅读和解释为等式。

@= and @ are new operators introduced in Python 3.5 performing matrix multiplication. They are meant to clarify the confusion which existed so far with the operator * which was used either for element-wise multiplication or matrix multiplication depending on the convention employed in that particular library/code. As a result, in the future, the operator * is meant to be used for element-wise multiplication only.

As explained in PEP0465, two operators were introduced:

  • A new binary operator A @ B, used similarly as A * B
  • An in-place version A @= B, used similarly as A *= B

Matrix Multiplication vs Element-wise Multiplication

To quickly highlight the difference, for two matrices:

A = [[1, 2],    B = [[11, 12],
     [3, 4]]         [13, 14]]
  • Element-wise multiplication will yield:

    A * B = [[1 * 11,   2 * 12], 
             [3 * 13,   4 * 14]]
    
  • Matrix multiplication will yield:

    A @ B  =  [[1 * 11 + 2 * 13,   1 * 12 + 2 * 14],
               [3 * 11 + 4 * 13,   3 * 12 + 4 * 14]]
    

Usage in Numpy

So far, Numpy used the following convention:

Introduction of the @ operator makes the code involving matrix multiplications much easier to read. PEP0465 gives us an example:

# Current implementation of matrix multiplications using dot function
S = np.dot((np.dot(H, beta) - r).T,
            np.dot(inv(np.dot(np.dot(H, V), H.T)), np.dot(H, beta) - r))

# Current implementation of matrix multiplications using dot method
S = (H.dot(beta) - r).T.dot(inv(H.dot(V).dot(H.T))).dot(H.dot(beta) - r)

# Using the @ operator instead
S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r)

Clearly, the last implementation is much easier to read and interpret as an equation.


回答 2

@是Python3.5中新增的矩阵乘法运算符

参考:https : //docs.python.org/3/whatsnew/3.5.html#whatsnew-pep-465

C = A @ B

@ is the new operator for Matrix Multiplication added in Python3.5

Reference: https://docs.python.org/3/whatsnew/3.5.html#whatsnew-pep-465

Example

C = A @ B

为什么在导入模块时Python运行我的模块,以及如何停止它?

问题:为什么在导入模块时Python运行我的模块,以及如何停止它?

我有一个正在构建的Python程序,可以通过以下两种方式之一运行:第一种是调用“ python main.py”,它以友好的方式提示用户输入,然后通过该程序运行用户输入。另一种方法是调用“ python batch.py -file- ”,它将遍历所有友好的输入集合,并通过该程序一次运行整个文件的输入值。

问题是,当我运行“ batch.py​​”时,它会从“ main.py”中导入一些变量/方法/等,并在运行此代码时:

import main

在程序的第一行,它立即错误,因为它试图运行“ main.py”中的代码。

如何阻止Python运行要导入的“主”模块中包含的代码?

I have a Python program I’m building that can be run in either of 2 ways: the first is to call “python main.py” which prompts the user for input in a friendly manner and then runs the user input through the program. The other way is to call “python batch.py -file-” which will pass over all the friendly input gathering and run an entire file’s worth of input through the program in a single go.

The problem is that when I run “batch.py” it imports some variables/methods/etc from “main.py”, and when it runs this code:

import main

at the first line of the program, it immediately errors because it tries to run the code in “main.py”.

How can I stop Python from running the code contained in the “main” module which I’m importing?


回答 0

因为这就是Python的工作方式,诸如classand之def类的关键字不是声明。相反,它们是执行的真实实时语句。如果未执行,则您的模块将为..空:-)

无论如何,惯用的方法是:

# stuff to run always here such as class/def
def main():
    pass

if __name__ == "__main__":
   # stuff only to run when not called via 'import' here
   main()

请参阅目的是什么if __name__ == "__main__"

但是,它确实需要对要import编辑的模块进行源代码控制。

快乐的编码。

Because this is just how Python works – keywords such as class and def are not declarations. Instead, they are real live statements which are executed. If they were not executed your module would be .. empty :-)

Anyway, the idiomatic approach is:

# stuff to run always here such as class/def
def main():
    pass

if __name__ == "__main__":
   # stuff only to run when not called via 'import' here
   main()

See What is if __name__ == "__main__" for?

It does require source control over the module being imported, however.

Happy coding.


回答 1

由于Python的工作方式,在导入模块时必须运行模块。

为了防止模块中的代码在导入时被执行,而只能在直接运行时执行,可以使用以下方法进行保护if

if __name__ == "__main__":
    # this won't be run when imported

您可能需要将此代码放入main()方法中,以便可以直接执行文件,或导入模块并调用main()。例如,假设它在file中foo.py

def main():
    print "Hello World"

if __name__ == "__main__":
    main()

该程序可以通过运行python foo.py或从另一个Python脚本运行:

import foo

...

foo.main()

Due to the way Python works, it is necessary for it to run your modules when it imports them.

To prevent code in the module from being executed when imported, but only when run directly, you can guard it with this if:

if __name__ == "__main__":
    # this won't be run when imported

You may want to put this code in a main() method, so that you can either execute the file directly, or import the module and call the main(). For example, assume this is in the file foo.py.

def main():
    print "Hello World"

if __name__ == "__main__":
    main()

This program can be run either by going python foo.py, or from another Python script:

import foo

...

foo.main()

回答 2

使用if __name__ == '__main__'惯用语- __name__是一个特殊变量,其值是'__main__'模块是否作为脚本运行时的值,模块名称(如果已导入)。所以你会做类似的事情

# imports
# class/function definitions
if __name__ == '__main__':
    # code here will only run when you invoke 'python main.py'

Use the if __name__ == '__main__' idiom — __name__ is a special variable whose value is '__main__' if the module is being run as a script, and the module name if it’s imported. So you’d do something like

# imports
# class/function definitions
if __name__ == '__main__':
    # code here will only run when you invoke 'python main.py'

回答 3

不幸的是,您没有。这是导入语法工作方式的一部分,并且重要的是,请记住这一点-记住def实际上是已执行某项操作,如果Python不执行导入,那么您将被困在没有函数的情况下。

但是,由于您可能可以访问该文件,因此您可以查看并查看导致该错误的原因。可能有可能修改您的环境以防止发生错误。

Unfortunately, you don’t. That is part of how the import syntax works and it is important that it does so — remember def is actually something executed, if Python did not execute the import, you’d be, well, stuck without functions.

Since you probably have access to the file, though, you might be able to look and see what causes the error. It might be possible to modify your environment to prevent the error from happening.


回答 4

将代码放入函数中,直到调用该函数,该代码才会运行。您应该在其中具有主要功能main.py。带有以下语句:

if __name__ == '__main__':
  main()

然后,如果调用python main.pymain()函数将运行。如果导入main.py,则不会。另外,main.py为清楚起见,您可能应该重命名为其他名称。

Put the code inside a function and it won’t run until you call the function. You should have a main function in your main.py. with the statement:

if __name__ == '__main__':
  main()

Then, if you call python main.py the main() function will run. If you import main.py, it will not. Also, you should probably rename main.py to something else for clarity’s sake.


回答 5

有一个Python增强建议PEP 299,旨在用替换if __name__ == '__main__':成语def __main__:,但遭到拒绝。了解使用时要记住的内容仍然是一本好书if __name__ = '__main__':

There was a Python enhancement proposal PEP 299 which aimed to replace if __name__ == '__main__': idiom with def __main__:, but it was rejected. It’s still a good read to know what to keep in mind when using if __name__ = '__main__':.


回答 6

您可以这样编写“ main.py”:

#!/usr/bin/env python

__all__=["somevar", "do_something"]

somevar=""

def do_something():
    pass #blahblah

if __name__=="__main__":
    do_something()

You may write your “main.py” like this:

#!/usr/bin/env python

__all__=["somevar", "do_something"]

somevar=""

def do_something():
    pass #blahblah

if __name__=="__main__":
    do_something()

回答 7

尽管import不运行代码就无法使用;您可以通过很快速的方式输入变量;通过使用numpy.savez,将变量作为numpy数组存储在.npz文件中。之后,您可以使用加载变量numpy.load

查看scipy文档中的完整描述

请注意,这仅适用于变量和变量数组,而不适用于方法等。

Although you cannot use import without running the code; there is quite a swift way in which you can input your variables; by using numpy.savez, which stores variables as numpy arrays in a .npz file. Afterwards you can load the variables using numpy.load.

See a full description in the scipy documentation

Please note this is only the case for variables and arrays of variable, and not for methods, etc.


回答 8

尝试仅从main.py导入所需的功能?所以,

from main import SomeFunction

可能是因为您在batch.py​​中命名的函数与main.py中的命名相同,并且在导入main.py时,程序将运行main.py函数而不是batch.py​​函数;执行以上操作可以解决该问题。我希望。

Try just importing the functions needed from main.py? So,

from main import SomeFunction

It could be that you’ve named a function in batch.py the same as one in main.py, and when you import main.py the program runs the main.py function instead of the batch.py function; doing the above should fix that. I hope.


如何捕获像异常一样的numpy警告(不仅用于测试)?

问题:如何捕获像异常一样的numpy警告(不仅用于测试)?

我必须在Python中为正在执行的项目制作Lagrange多项式。我正在做一个重心样式,以避免使用显式的for循环,而不是牛顿的分差样式。我的问题是我需要用零除,但是Python(或者也许是numpy)只是将其警告而不是正常异常。

因此,我需要知道的是如何捕获此警告,就像它是一个exceptions一样。我在本网站上发现的与此相关的问题并未按照我需要的方式回答。这是我的代码:

import numpy as np
import matplotlib.pyplot as plt
import warnings

class Lagrange:
    def __init__(self, xPts, yPts):
        self.xPts = np.array(xPts)
        self.yPts = np.array(yPts)
        self.degree = len(xPts)-1 
        self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])

    def __call__(self, x):
        warnings.filterwarnings("error")
        try:
            bigNumerator = np.product(x - self.xPts)
            numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
            return sum(numerators/self.weights*self.yPts) 
        except Exception, e: # Catch division by 0. Only possible in 'numerators' array
            return yPts[np.where(xPts == x)[0][0]]

L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2

L(1) # This should catch an error, then return 1. 

执行此代码后,我得到的输出是:

Warning: divide by zero encountered in int_scalars

那是我要抓住的警告。它应该出现在列表理解中。

I have to make a Lagrange polynomial in Python for a project I’m doing. I’m doing a barycentric style one to avoid using an explicit for-loop as opposed to a Newton’s divided difference style one. The problem I have is that I need to catch a division by zero, but Python (or maybe numpy) just makes it a warning instead of a normal exception.

So, what I need to know how to do is to catch this warning as if it were an exception. The related questions to this I found on this site were answered not in the way I needed. Here’s my code:

import numpy as np
import matplotlib.pyplot as plt
import warnings

class Lagrange:
    def __init__(self, xPts, yPts):
        self.xPts = np.array(xPts)
        self.yPts = np.array(yPts)
        self.degree = len(xPts)-1 
        self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])

    def __call__(self, x):
        warnings.filterwarnings("error")
        try:
            bigNumerator = np.product(x - self.xPts)
            numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
            return sum(numerators/self.weights*self.yPts) 
        except Exception, e: # Catch division by 0. Only possible in 'numerators' array
            return yPts[np.where(xPts == x)[0][0]]

L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2

L(1) # This should catch an error, then return 1. 

When this code is executed, the output I get is:

Warning: divide by zero encountered in int_scalars

That’s the warning I want to catch. It should occur inside the list comprehension.


回答 0

看来您的配置正在使用print选项numpy.seterr

>>> import numpy as np
>>> np.array([1])/0   #'warn' mode
__main__:1: RuntimeWarning: divide by zero encountered in divide
array([0])
>>> np.seterr(all='print')
{'over': 'warn', 'divide': 'warn', 'invalid': 'warn', 'under': 'ignore'}
>>> np.array([1])/0   #'print' mode
Warning: divide by zero encountered in divide
array([0])

这意味着您看到的警告不是真正的警告,而只是打印了一些字符stdout(请参阅文档以获取信息seterr)。如果您想抓住它,可以:

  1. 使用numpy.seterr(all='raise')它将直接引发异常。但是,这会更改所有操作的行为,因此,这是行为上的很大变化。
  2. 使用numpy.seterr(all='warn'),可以将打印的警告转换为真实的警告,您将可以使用上述解决方案来本地化此行为更改。

实际warnings收到警告后,您可以使用该模块来控制警告的处理方式:

>>> import warnings
>>> 
>>> warnings.filterwarnings('error')
>>> 
>>> try:
...     warnings.warn(Warning())
... except Warning:
...     print 'Warning was raised as an exception!'
... 
Warning was raised as an exception!

请仔细阅读文档,filterwarnings因为它可以使您仅过滤所需的警告并具有其他选项。我还要考虑看看catch_warnings哪个是上下文管理器,它会自动重置原始filterwarnings功能:

>>> import warnings
>>> with warnings.catch_warnings():
...     warnings.filterwarnings('error')
...     try:
...         warnings.warn(Warning())
...     except Warning: print 'Raised!'
... 
Raised!
>>> try:
...     warnings.warn(Warning())
... except Warning: print 'Not raised!'
... 
__main__:2: Warning: 

It seems that your configuration is using the print option for numpy.seterr:

>>> import numpy as np
>>> np.array([1])/0   #'warn' mode
__main__:1: RuntimeWarning: divide by zero encountered in divide
array([0])
>>> np.seterr(all='print')
{'over': 'warn', 'divide': 'warn', 'invalid': 'warn', 'under': 'ignore'}
>>> np.array([1])/0   #'print' mode
Warning: divide by zero encountered in divide
array([0])

This means that the warning you see is not a real warning, but it’s just some characters printed to stdout(see the documentation for seterr). If you want to catch it you can:

  1. Use numpy.seterr(all='raise') which will directly raise the exception. This however changes the behaviour of all the operations, so it’s a pretty big change in behaviour.
  2. Use numpy.seterr(all='warn'), which will transform the printed warning in a real warning and you’ll be able to use the above solution to localize this change in behaviour.

Once you actually have a warning, you can use the warnings module to control how the warnings should be treated:

>>> import warnings
>>> 
>>> warnings.filterwarnings('error')
>>> 
>>> try:
...     warnings.warn(Warning())
... except Warning:
...     print 'Warning was raised as an exception!'
... 
Warning was raised as an exception!

Read carefully the documentation for filterwarnings since it allows you to filter only the warning you want and has other options. I’d also consider looking at catch_warnings which is a context manager which automatically resets the original filterwarnings function:

>>> import warnings
>>> with warnings.catch_warnings():
...     warnings.filterwarnings('error')
...     try:
...         warnings.warn(Warning())
...     except Warning: print 'Raised!'
... 
Raised!
>>> try:
...     warnings.warn(Warning())
... except Warning: print 'Not raised!'
... 
__main__:2: Warning: 

回答 1

在@Bakuriu的答案中添加一些内容:

如果您已经知道警告可能在何处发生,那么使用numpy.errstate上下文管理器通常会更干净一些,而不是 numpy.seterr将所有相同类型的后续警告视为相同,而不管它们在代码中的位置如何:

import numpy as np

a = np.r_[1.]
with np.errstate(divide='raise'):
    try:
        a / 0   # this gets caught and handled as an exception
    except FloatingPointError:
        print('oh no!')
a / 0           # this prints a RuntimeWarning as usual

编辑:

在我最初的示例中,我有a = np.r_[0],但是显然numpy的行为发生了变化,使得在分子为全零的情况下对零除的处理方式有所不同。例如,在numpy 1.16.4中:

all_zeros = np.array([0., 0.])
not_all_zeros = np.array([1., 0.])

with np.errstate(divide='raise'):
    not_all_zeros / 0.  # Raises FloatingPointError

with np.errstate(divide='raise'):
    all_zeros / 0.  # No exception raised

with np.errstate(invalid='raise'):
    all_zeros / 0.  # Raises FloatingPointError

相应的警告消息也不同:1. / 0.记录为RuntimeWarning: divide by zero encountered in true_divide,而0. / 0.记录为RuntimeWarning: invalid value encountered in true_divide。我不确定为什么要进行此更改,但是我怀疑这与以下事实有关:0. / 0.是不能表示为数字(numpy的回报为NaN在这种情况下),而1. / 0.-1. / 0.分别返回+ Inf文件和-Inf ,符合IEE 754标准。

如果您想捕获两种类型的错误,则可以始终通过np.errstate(divide='raise', invalid='raise'),或者all='raise'如果您想对任何类型的浮点错误引发异常。

To add a little to @Bakuriu’s answer:

If you already know where the warning is likely to occur then it’s often cleaner to use the numpy.errstate context manager, rather than numpy.seterr which treats all subsequent warnings of the same type the same regardless of where they occur within your code:

import numpy as np

a = np.r_[1.]
with np.errstate(divide='raise'):
    try:
        a / 0   # this gets caught and handled as an exception
    except FloatingPointError:
        print('oh no!')
a / 0           # this prints a RuntimeWarning as usual

Edit:

In my original example I had a = np.r_[0], but apparently there was a change in numpy’s behaviour such that division-by-zero is handled differently in cases where the numerator is all-zeros. For example, in numpy 1.16.4:

all_zeros = np.array([0., 0.])
not_all_zeros = np.array([1., 0.])

with np.errstate(divide='raise'):
    not_all_zeros / 0.  # Raises FloatingPointError

with np.errstate(divide='raise'):
    all_zeros / 0.  # No exception raised

with np.errstate(invalid='raise'):
    all_zeros / 0.  # Raises FloatingPointError

The corresponding warning messages are also different: 1. / 0. is logged as RuntimeWarning: divide by zero encountered in true_divide, whereas 0. / 0. is logged as RuntimeWarning: invalid value encountered in true_divide. I’m not sure why exactly this change was made, but I suspect it has to do with the fact that the result of 0. / 0. is not representable as a number (numpy returns a NaN in this case) whereas 1. / 0. and -1. / 0. return +Inf and -Inf respectively, per the IEE 754 standard.

If you want to catch both types of error you can always pass np.errstate(divide='raise', invalid='raise'), or all='raise' if you want to raise an exception on any kind of floating point error.


回答 2

为了详细说明上述@Bakuriu的答案,我发现这使我能够以类似于捕获错误警告的方式捕获运行时警告,从而很好地打印警告:

import warnings

with warnings.catch_warnings():
    warnings.filterwarnings('error')
    try:
        answer = 1 / 0
    except Warning as e:
        print('error found:', e)

您可能可以尝试放置warnings.catch_warnings()的位置,具体取决于您要用这种方式捕获错误的伞的大小。

To elaborate on @Bakuriu’s answer above, I’ve found that this enables me to catch a runtime warning in a similar fashion to how I would catch an error warning, printing out the warning nicely:

import warnings

with warnings.catch_warnings():
    warnings.filterwarnings('error')
    try:
        answer = 1 / 0
    except Warning as e:
        print('error found:', e)

You will probably be able to play around with placing of the warnings.catch_warnings() placement depending on how big of an umbrella you want to cast with catching errors this way.


回答 3

删除warnings.filterwarnings并添加:

numpy.seterr(all='raise')

Remove warnings.filterwarnings and add:

numpy.seterr(all='raise')

在Python中,如何指示我要覆盖方法?

问题:在Python中,如何指示我要覆盖方法?

例如,在Java中,@Override注释不仅提供覆盖的编译时检查,而且还提供了出色的自记录代码。

我只是在寻找文档(尽管如果它是指示诸如pylint之类的检查器的指标,那是一个额外的好处)。我可以在某处添加注释或文档字符串,但是在Python中指示替代的惯用方式是什么?

In Java, for example, the @Override annotation not only provides compile-time checking of an override but makes for excellent self-documenting code.

I’m just looking for documentation (although if it’s an indicator to some checker like pylint, that’s a bonus). I can add a comment or docstring somewhere, but what is the idiomatic way to indicate an override in Python?


回答 0

基于此和fwc:s的答案,我创建了一个pip可安装软件包https://github.com/mkorpela/overrides

我有时会不时地在这里看这个问题。主要是在(再次)在我们的代码库中看到相同的错误之后发生的:有人在重命名“接口”中的方法时忘记了一些“接口”实现类。

好吧,Python不是Java,但是Python具有强大的功能-显式的要比隐式的好-并且在现实世界中确实有具体的案例可以帮助我。

因此,这是替代装饰器的草图。这将检查作为参数给出的类是否具有与要修饰的方法相同的方法(或某些名称)。

如果您能想到更好的解决方案,请在此处发布!

def overrides(interface_class):
    def overrider(method):
        assert(method.__name__ in dir(interface_class))
        return method
    return overrider

其工作方式如下:

class MySuperInterface(object):
    def my_method(self):
        print 'hello world!'


class ConcreteImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def my_method(self):
        print 'hello kitty!'

如果版本错误,则会在类加载期间引发断言错误:

class ConcreteFaultyImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def your_method(self):
        print 'bye bye!'

>> AssertionError!!!!!!!

Based on this and fwc:s answer I created a pip installable package https://github.com/mkorpela/overrides

From time to time I end up here looking at this question. Mainly this happens after (again) seeing the same bug in our code base: Someone has forgotten some “interface” implementing class while renaming a method in the “interface”..

Well Python ain’t Java but Python has power — and explicit is better than implicit — and there are real concrete cases in the real world where this thing would have helped me.

So here is a sketch of overrides decorator. This will check that the class given as a parameter has the same method (or something) name as the method being decorated.

If you can think of a better solution please post it here!

def overrides(interface_class):
    def overrider(method):
        assert(method.__name__ in dir(interface_class))
        return method
    return overrider

It works as follows:

class MySuperInterface(object):
    def my_method(self):
        print 'hello world!'


class ConcreteImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def my_method(self):
        print 'hello kitty!'

and if you do a faulty version it will raise an assertion error during class loading:

class ConcreteFaultyImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def your_method(self):
        print 'bye bye!'

>> AssertionError!!!!!!!

回答 1

这是一个不需要指定interface_class名称的实现。

import inspect
import re

def overrides(method):
    # actually can't do this because a method is really just a function while inside a class def'n  
    #assert(inspect.ismethod(method))

    stack = inspect.stack()
    base_classes = re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1)

    # handle multiple inheritance
    base_classes = [s.strip() for s in base_classes.split(',')]
    if not base_classes:
        raise ValueError('overrides decorator: unable to determine base class') 

    # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n
    derived_class_locals = stack[2][0].f_locals

    # replace each class name in base_classes with the actual class type
    for i, base_class in enumerate(base_classes):

        if '.' not in base_class:
            base_classes[i] = derived_class_locals[base_class]

        else:
            components = base_class.split('.')

            # obj is either a module or a class
            obj = derived_class_locals[components[0]]

            for c in components[1:]:
                assert(inspect.ismodule(obj) or inspect.isclass(obj))
                obj = getattr(obj, c)

            base_classes[i] = obj


    assert( any( hasattr(cls, method.__name__) for cls in base_classes ) )
    return method

Here’s an implementation that doesn’t require specification of the interface_class name.

import inspect
import re

def overrides(method):
    # actually can't do this because a method is really just a function while inside a class def'n  
    #assert(inspect.ismethod(method))

    stack = inspect.stack()
    base_classes = re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1)

    # handle multiple inheritance
    base_classes = [s.strip() for s in base_classes.split(',')]
    if not base_classes:
        raise ValueError('overrides decorator: unable to determine base class') 

    # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n
    derived_class_locals = stack[2][0].f_locals

    # replace each class name in base_classes with the actual class type
    for i, base_class in enumerate(base_classes):

        if '.' not in base_class:
            base_classes[i] = derived_class_locals[base_class]

        else:
            components = base_class.split('.')

            # obj is either a module or a class
            obj = derived_class_locals[components[0]]

            for c in components[1:]:
                assert(inspect.ismodule(obj) or inspect.isclass(obj))
                obj = getattr(obj, c)

            base_classes[i] = obj


    assert( any( hasattr(cls, method.__name__) for cls in base_classes ) )
    return method

回答 2

如果仅出于文档目的而希望这样做,则可以定义自己的替代装饰器:

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

除非您以一种实际上检查替代的方式创建override(f),否则这实际上只是让人眼花can乱。

但是,这就是Python,为什么要像Java一样编写它?

If you want this for documentation purposes only, you can define your own override decorator:

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

This is really nothing but eye-candy, unless you create override(f) in such a way that is actually checks for an override.

But then, this is Python, why write it like it was Java?


回答 3

Python不是Java。当然,没有真正的编译时检查之类的东西。

我认为文档字符串中的注释很多。这允许您的方法的任何用户键入help(obj.method)并看到该方法是替代。

您还可以使用显式扩展一个接口class Foo(Interface),该接口允许用户键入help(Interface.method)以了解有关您的方法旨在提供的功能的想法。

Python ain’t Java. There’s of course no such thing really as compile-time checking.

I think a comment in the docstring is plenty. This allows any user of your method to type help(obj.method) and see that the method is an override.

You can also explicitly extend an interface with class Foo(Interface), which will allow users to type help(Interface.method) to get an idea about the functionality your method is intended to provide.


回答 4

即兴在@mkorpela 很好的答案,这是一个版本

更精确的检查,命名和引发的Error对象

def overrides(interface_class):
    """
    Function override annotation.
    Corollary to @abc.abstractmethod where the override is not of an
    abstractmethod.
    Modified from answer https://stackoverflow.com/a/8313042/471376
    """
    def confirm_override(method):
        if method.__name__ not in dir(interface_class):
            raise NotImplementedError('function "%s" is an @override but that'
                                      ' function is not implemented in base'
                                      ' class %s'
                                      % (method.__name__,
                                         interface_class)
                                      )

        def func():
            pass

        attr = getattr(interface_class, method.__name__)
        if type(attr) is not type(func):
            raise NotImplementedError('function "%s" is an @override'
                                      ' but that is implemented as type %s'
                                      ' in base class %s, expected implemented'
                                      ' type %s'
                                      % (method.__name__,
                                         type(attr),
                                         interface_class,
                                         type(func))
                                      )
        return method
    return confirm_override


实际上是这样的:

NotImplementedError未在基类中实现

class A(object):
    # ERROR: `a` is not a implemented!
    pass

class B(A):
    @overrides(A)
    def a(self):
        pass

导致更多描述性NotImplementedError错误

function "a" is an @override but that function is not implemented in base class <class '__main__.A'>

全栈

Traceback (most recent call last):
  
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 110, in confirm_override
    interface_class)
NotImplementedError: function "a" is an @override but that function is not implemented in base class <class '__main__.A'>


NotImplementedError预期的实现类型

class A(object):
    # ERROR: `a` is not a function!
    a = ''

class B(A):
    @overrides(A)
    def a(self):
        pass

导致更多描述性NotImplementedError错误

function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>

全栈

Traceback (most recent call last):
  
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 125, in confirm_override
    type(func))
NotImplementedError: function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>




关于@mkorpela答案,很棒的事情是检查发生在某些初始化阶段。该检查不需要“运行”。参考前面的示例,class B它从未被初始化(B()),但NotImplementedError仍然会上升。这意味着overrides可以更快地发现错误。

Improvising on @mkorpela great answer, here is a version with

more precise checks, naming, and raised Error objects

def overrides(interface_class):
    """
    Function override annotation.
    Corollary to @abc.abstractmethod where the override is not of an
    abstractmethod.
    Modified from answer https://stackoverflow.com/a/8313042/471376
    """
    def confirm_override(method):
        if method.__name__ not in dir(interface_class):
            raise NotImplementedError('function "%s" is an @override but that'
                                      ' function is not implemented in base'
                                      ' class %s'
                                      % (method.__name__,
                                         interface_class)
                                      )

        def func():
            pass

        attr = getattr(interface_class, method.__name__)
        if type(attr) is not type(func):
            raise NotImplementedError('function "%s" is an @override'
                                      ' but that is implemented as type %s'
                                      ' in base class %s, expected implemented'
                                      ' type %s'
                                      % (method.__name__,
                                         type(attr),
                                         interface_class,
                                         type(func))
                                      )
        return method
    return confirm_override


Here is what it looks like in practice:

NotImplementedErrornot implemented in base class

class A(object):
    # ERROR: `a` is not a implemented!
    pass

class B(A):
    @overrides(A)
    def a(self):
        pass

results in more descriptive NotImplementedError error

function "a" is an @override but that function is not implemented in base class <class '__main__.A'>

full stack

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 110, in confirm_override
    interface_class)
NotImplementedError: function "a" is an @override but that function is not implemented in base class <class '__main__.A'>


NotImplementedErrorexpected implemented type

class A(object):
    # ERROR: `a` is not a function!
    a = ''

class B(A):
    @overrides(A)
    def a(self):
        pass

results in more descriptive NotImplementedError error

function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>

full stack

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 125, in confirm_override
    type(func))
NotImplementedError: function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>




The great thing about @mkorpela answer is the check happens during some initialization phase. The check does not need to be “run”. Referring to the prior examples, class B is never initialized (B()) yet the NotImplementedError will still raise. This means overrides errors are caught sooner.


回答 5

就像其他人所说的,与Java不同,这里没有@Overide标记,但是您可以使用装饰器创建自己的标记,但是我建议使用getattrib()全局方法,而不要使用内部dict,这样您将获得以下内容:

def Override(superClass):
    def method(func)
        getattr(superClass,method.__name__)
    return method

如果您愿意,可以在自己的尝试中捕获getattr(),这会引发您自己的错误,但我认为在这种情况下,getattr方法更好。

同样,这会捕获绑定到类的所有项目,包括类方法和可变项

Like others have said unlike Java there is not @Overide tag however above you can create your own using decorators however I would suggest using the getattrib() global method instead of using the internal dict so you get something like the following:

def Override(superClass):
    def method(func)
        getattr(superClass,method.__name__)
    return method

If you wanted to you could catch getattr() in your own try catch raise your own error but I think getattr method is better in this case.

Also this catches all items bound to a class including class methods and vairables


回答 6

基于@mkorpela的出色回答,我编写了一个类似的软件包(ipromise pypi github),该软件包可以进行更多检查:

假设A从继承BCB从继承C

ipromise模块检查:

  • 如果A.f覆盖B.f,则B.f必须存在,并且A必须从继承B。(这是覆盖程序包中的检查)。

  • 您没有模式A.f声明它被覆盖B.f,然后模式声明它被覆盖C.fA应该说它重写自,C.f因为它B可能决定停止重写此方法,并且不应导致下游更新。

  • 您没有模式A.f声明其覆盖C.f,但B.f没有声明其覆盖。

  • 您没有模式A.f声明它被覆盖C.f,但是B.f声明它被某些模式覆盖D.f

它还具有用于标记和检查实现抽象方法的各种功能。

Based on @mkorpela’s great answer, I’ve written a similar package (ipromise pypi github) that does many more checks:

Suppose A inherits from B and C, B inherits from C.

Module ipromise checks that:

  • If A.f overrides B.f, B.f must exist, and A must inherit from B. (This is the check from the overrides package).

  • You don’t have the pattern A.f declares that it overrides B.f, which then declares that it overrides C.f. A should say that it overrides from C.f since B might decide to stop overriding this method, and that should not result in downstream updates.

  • You don’t have the pattern A.f declares that it overrides C.f, but B.f does not declare its override.

  • You don’t have the pattern A.f declares that it overrides C.f, but B.f declares that it overrides from some D.f.

It also has various features for marking and checking implementing an abstract method.


回答 7

听觉是最简单的,并且可以在Jython下使用Java类进行工作:

class MyClass(SomeJavaClass):
     def __init__(self):
         setattr(self, "name_of_method_to_override", __method_override__)

     def __method_override__(self, some_args):
         some_thing_to_do()

Hear is simplest and working under Jython with Java classes:

class MyClass(SomeJavaClass):
     def __init__(self):
         setattr(self, "name_of_method_to_override", __method_override__)

     def __method_override__(self, some_args):
         some_thing_to_do()

回答 8

我制作的装饰器不仅检查了覆盖属性的名称是否是该属性所在类的任何超类,而无需指定超类,而且该装饰器还检查以确保覆盖属性必须与被覆盖的类型相同属性。类方法被视为方法,静态方法被视为函数。此装饰器适用于可调用对象,类方法,静态方法和属性。

有关源代码,请参见:https : //github.com/fireuser909/override

此装饰器仅适用于重写类实例的类。OverridesMeta,但如果您的类是自定义元类的实例,请使用create_custom_overrides_meta函数创建与重写装饰器兼容的元类。对于测试,请运行override .__ init__模块。

Not only did the decorator I made check if the name of the overriding attribute in is any superclass of the class the attribute is in without having to specify a superclass, this decorator also check to ensure the overriding attribute must be the same type as the overridden attribute. Class Methods are treated like methods and Static Methods are treated like functions. This decorator works for callables, class methods, static methods, and properties.

For source code see: https://github.com/fireuser909/override

This decorator only works for classes that are instances of override.OverridesMeta but if your class is an instance of a custom metaclass use the create_custom_overrides_meta function to create a metaclass that is compatible with the override decorator. For tests, run the override.__init__ module.


回答 9

在Python 2.6+和Python 3.2+中,您可以做到(实际上是模拟它,Python不支持函数重载,并且子类会自动覆盖parent的方法)。我们可以为此使用装饰器。但是首先,请注意,Python @decorators和Java @Annotations是完全不同的东西。前一个是带有具体代码的包装器,而后一个是编译器的标志。

为此,首先 pip install multipledispatch

from multipledispatch import dispatch as Override
# using alias 'Override' just to give you some feel :)

class A:
    def foo(self):
        print('foo in A')

    # More methods here


class B(A):
    @Override()
    def foo(self):
        print('foo in B')
    
    @Override(int)
    def foo(self,a):
        print('foo in B; arg =',a)
        
    @Override(str,float)
    def foo(self,a,b):
        print('foo in B; arg =',(a,b))
        
a=A()
b=B()
a.foo()
b.foo()
b.foo(4)
b.foo('Wheee',3.14)

输出:

foo in A
foo in B
foo in B; arg = 4
foo in B; arg = ('Wheee', 3.14)

请注意,您必须在此处使用带括号的装饰器

要记住的一件事是,由于Python没有直接的函数重载,因此即使Class B不继承自Class A但需要所有这些foos,也需要使用@Override(尽管使用别名’Overload’看起来在那种情况下更好)

In Python 2.6+ and Python 3.2+ you can do it (Actually simulate it, Python doesn’t support function overloading and child class automatically overrides parent’s method). We can use Decorators for this. But first, note that Python’s @decorators and Java’s @Annotations are totally different things. The prior one is a wrapper with concrete code while later one is a flag to compiler.

For this, first do pip install multipledispatch

from multipledispatch import dispatch as Override
# using alias 'Override' just to give you some feel :)

class A:
    def foo(self):
        print('foo in A')

    # More methods here


class B(A):
    @Override()
    def foo(self):
        print('foo in B')
    
    @Override(int)
    def foo(self,a):
        print('foo in B; arg =',a)
        
    @Override(str,float)
    def foo(self,a,b):
        print('foo in B; arg =',(a,b))
        
a=A()
b=B()
a.foo()
b.foo()
b.foo(4)
b.foo('Wheee',3.14)

output:

foo in A
foo in B
foo in B; arg = 4
foo in B; arg = ('Wheee', 3.14)

Note that you must have to use decorator here with parenthesis

One thing to remember is that since Python doesn’t have function overloading directly, so even if Class B don’t inherit from Class A but needs all those foos than also you need to use @Override (though using alias ‘Overload’ will look better in that case)


将变量名作为字符串获取

问题:将变量名作为字符串获取

此线程讨论如何在Python中以字符串形式获取函数名称如何以字符串 形式获取函数名称?

如何对变量执行相同操作?与函数相反,Python变量没有__name__属性。

换句话说,如果我有一个变量,例如:

foo = dict()
foo['bar'] = 2

我正在寻找一个功能/属性,例如retrieve_name(),以便从此列表在Pandas中创建一个DataFrame,其中列名由实际字典的名称给出:

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [retrieve_name(d) for d in list_of_dicts] 

This thread discusses how to get the name of a function as a string in Python: How to get a function name as a string?

How can I do the same for a variable? As opposed to functions, Python variables do not have the __name__ attribute.

In other words, if I have a variable such as:

foo = dict()
foo['bar'] = 2

I am looking for a function/attribute, e.g. retrieve_name() in order to create a DataFrame in Pandas from this list, where the column names are given by the names of the actual dictionaries:

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [retrieve_name(d) for d in list_of_dicts] 

回答 0

使用该python-varname包,您可以轻松检索变量的名称

https://github.com/pwwang/python-varname

就您而言,您可以执行以下操作:

from varname import Wrapper

foo = Wrapper(dict())

# foo.name == 'foo'
# foo.value == {}
foo.value['bar'] = 2

或者,您也可以尝试直接检索变量名称:

from varname import nameof

foo = dict()

fooname = nameof(foo)
# fooname == 'foo'

我是这个软件包的作者。如果您有任何疑问,请告诉我,或者可以在github上提交问题。

Using the python-varname package, you can easily retrieve the name of the variables

https://github.com/pwwang/python-varname

In your case, you can do:

from varname import Wrapper

foo = Wrapper(dict())

# foo.name == 'foo'
# foo.value == {}
foo.value['bar'] = 2

For list comprehension part, you can do:

n_jobs = Wrapper(<original_value>) 
users = Wrapper(<original_value>) 
queues = Wrapper(<original_value>) 
priorities = Wrapper(<original_value>) 

list_of_dicts = [n_jobs, users, queues, priorities]
columns = [d.name for d in list_of_dicts]
# ['n_jobs', 'users', 'queues', 'priorities']
# REMEMBER that you have to access the <original_value> by d.value

You can also try to retrieve the variable name DIRECTLY:

from varname import nameof

foo = dict()

fooname = nameof(foo)
# fooname == 'foo'

Note that this is working in this case as you expected:

n_jobs = <original_value>
d = n_jobs

nameof(d) # will return d, instead of n_jobs
# nameof only works directly with the variable

I am the author of this package. Please let me know if you have any questions or you can submit issues on Github.


回答 1

Python中唯一具有规范名称的对象是模块,函数和类,并且在定义函数或类或导入模块后,当然不能保证此规范名称在任何命名空间中都具有任何含义。这些名称也可以在创建对象后进行修改,因此它们可能并不总是特别值得信赖。

如果不递归地遍历命名对象的树,你要做的就是不可能; 名称是对对象的单向引用。常见的或具有花园多样性的Python对象不包含对其名称的引用。想象一下,如果要维护代表表示引用它的名称的字符串列表,是否需要每个整数,每个字典,每个列表,每个布尔值!这将是实施的噩梦,对程序员几乎没有好处。

The only objects in Python that have canonical names are modules, functions, and classes, and of course there is no guarantee that this canonical name has any meaning in any namespace after the function or class has been defined or the module imported. These names can also be modified after the objects are created so they may not always be particularly trustworthy.

What you want to do is not possible without recursively walking the tree of named objects; a name is a one-way reference to an object. A common or garden-variety Python object contains no references to its names. Imagine if every integer, every dict, every list, every Boolean needed to maintain a list of strings that represented names that referred to it! It would be an implementation nightmare, with little benefit to the programmer.


回答 2

即使变量值没有指向名称,您也可以访问每个分配的变量及其值的列表,所以我很惊讶只有一个人建议在其中循环查找您的var名称。

在该答复中提到有人说,你可能必须走栈和检查每个人的当地人和全局找到foo,但如果foo在你调用这个范围被分配retrieve_name的功能,你可以用inspectcurrent frame,让你所有的局部变量。

我的解释可能有点罗word(也许我应该少用“ foo”一词),但这是它在代码中的样子(请注意,如果有多个变量分配给相同的值,您将获得这两个变量名):

import inspect

x,y,z = 1,2,3

def retrieve_name(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    return [var_name for var_name, var_val in callers_local_vars if var_val is var]

print retrieve_name(y)

如果要从另一个函数调用此函数,则类似:

def foo(bar):
    return retrieve_name(bar)

foo(baz)

而您想要baz代替bar,则只需进一步返回范围。这可以通过.f_backcaller_local_vars初始化中添加额外的内容来完成。

在这里查看示例:ideone

Even if variable values don’t point back to the name, you have access to the list of every assigned variable and its value, so I’m astounded that only one person suggested looping through there to look for your var name.

Someone mentioned on that answer that you might have to walk the stack and check everyone’s locals and globals to find foo, but if foo is assigned in the scope where you’re calling this retrieve_name function, you can use inspect‘s current frame to get you all of those local variables.

My explanation might be a little bit too wordy (maybe I should’ve used a “foo” less words), but here’s how it would look in code (Note that if there is more than one variable assigned to the same value, you will get both of those variable names):

import inspect

x,y,z = 1,2,3

def retrieve_name(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    return [var_name for var_name, var_val in callers_local_vars if var_val is var]

print retrieve_name(y)

If you’re calling this function from another function, something like:

def foo(bar):
    return retrieve_name(bar)

foo(baz)

And you want the baz instead of bar, you’ll just need to go back a scope further. This can be done by adding an extra .f_back in the caller_local_vars initialization.

See an example here: ideone


回答 3

使用Python 3.8可以简单地使用f字符串调试功能:

>>> foo = dict()
>>> f'{foo=}'.split('=')[0]
'foo' 

With Python 3.8 one can simply use f-string debugging feature:

>>> foo = dict()
>>> f'{foo=}'.split('=')[0]
'foo' 

回答 4

在python3上,此函数将在堆栈中获得最外部的名称:

import inspect


def retrieve_name(var):
        """
        Gets the name of var. Does it from the out most frame inner-wards.
        :param var: variable to get name from.
        :return: string
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]

它在代码中的任何地方都很有用。遍历反向堆栈以查找第一个匹配项。

On python3, this function will get the outer most name in the stack:

import inspect


def retrieve_name(var):
        """
        Gets the name of var. Does it from the out most frame inner-wards.
        :param var: variable to get name from.
        :return: string
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]

It is useful anywhere on the code. Traverses the reversed stack looking for the first match.


回答 5

我不认为这是可能的。考虑以下示例:

>>> a = []
>>> b = a
>>> id(a)
140031712435664
>>> id(b)
140031712435664

ab指向同一个对象,但对象无法知道指向它哪些变量。

I don’t believe this is possible. Consider the following example:

>>> a = []
>>> b = a
>>> id(a)
140031712435664
>>> id(b)
140031712435664

The a and b point to the same object, but the object can’t know what variables point to it.


回答 6

def name(**variables):
    return [x for x in variables]

它的用法如下:

name(variable=variable)
def name(**variables):
    return [x for x in variables]

It’s used like this:

name(variable=variable)

回答 7

这是一种方法。我不会推荐任何重要的东西,因为它会很脆。但这是可以完成的。

创建一个使用inspect模块查找调用它的源代码的函数。然后,您可以解析源代码以标识要检索的变量名称。例如,这是一个名为的函数autodict,该函数获取变量列表并返回将变量名称映射为其值的字典。例如:

x = 'foo'
y = 'bar'
d = autodict(x, y)
print d

将给出:

{'x': 'foo', 'y': 'bar'}

检查源代码本身比搜索locals()or 更好,globals()因为后一种方法不会告诉您哪个变量是您想要的变量。

无论如何,这是代码:

def autodict(*args):
    get_rid_of = ['autodict(', ',', ')', '\n']
    calling_code = inspect.getouterframes(inspect.currentframe())[1][4][0]
    calling_code = calling_code[calling_code.index('autodict'):]
    for garbage in get_rid_of:
        calling_code = calling_code.replace(garbage, '')
    var_names, var_values = calling_code.split(), args
    dyn_dict = {var_name: var_value for var_name, var_value in
                zip(var_names, var_values)}
    return dyn_dict

该操作在的行中进行inspect.getouterframes,该操作返回调用的代码中的字符串autodict

这种魔术的明显缺点是,它对源代码的结构进行了假设。当然,如果它在解释器中运行,它将根本无法工作。

Here’s one approach. I wouldn’t recommend this for anything important, because it’ll be quite brittle. But it can be done.

Create a function that uses the inspect module to find the source code that called it. Then you can parse the source code to identify the variable names that you want to retrieve. For example, here’s a function called autodict that takes a list of variables and returns a dictionary mapping variable names to their values. E.g.:

x = 'foo'
y = 'bar'
d = autodict(x, y)
print d

Would give:

{'x': 'foo', 'y': 'bar'}

Inspecting the source code itself is better than searching through the locals() or globals() because the latter approach doesn’t tell you which of the variables are the ones you want.

At any rate, here’s the code:

def autodict(*args):
    get_rid_of = ['autodict(', ',', ')', '\n']
    calling_code = inspect.getouterframes(inspect.currentframe())[1][4][0]
    calling_code = calling_code[calling_code.index('autodict'):]
    for garbage in get_rid_of:
        calling_code = calling_code.replace(garbage, '')
    var_names, var_values = calling_code.split(), args
    dyn_dict = {var_name: var_value for var_name, var_value in
                zip(var_names, var_values)}
    return dyn_dict

The action happens in the line with inspect.getouterframes, which returns the string within the code that called autodict.

The obvious downside to this sort of magic is that it makes assumptions about how the source code is structured. And of course, it won’t work at all if it’s run inside the interpreter.


回答 8

我编写了包裹法术来稳健地执行这种魔术。你可以写:

from sorcery import dict_of

columns = dict_of(n_jobs, users, queues, priorities)

并将其传递给dataframe构造函数。等效于:

columns = dict(n_jobs=n_jobs, users=users, queues=queues, priorities=priorities)

I wrote the package sorcery to do this kind of magic robustly. You can write:

from sorcery import dict_of

columns = dict_of(n_jobs, users, queues, priorities)

and pass that to the dataframe constructor. It’s equivalent to:

columns = dict(n_jobs=n_jobs, users=users, queues=queues, priorities=priorities)

回答 9

>>> locals()['foo']
{}
>>> globals()['foo']
{}

如果要编写自己的函数,可以这样做,以便可以检查在本地变量中定义的变量,然后检查全局变量。如果未找到任何内容,则可以在id()上进行比较,以查看变量是否指向内存中的相同位置。

如果变量在类中,则可以使用className。dict .keys()或vars(self)来查看变量是否已定义。

>>> locals()['foo']
{}
>>> globals()['foo']
{}

If you wanted to write your own function, it could be done such that you could check for a variable defined in locals then check globals. If nothing is found you could compare on id() to see if the variable points to the same location in memory.

If your variable is in a class, you could use className.dict.keys() or vars(self) to see if your variable has been defined.


回答 10

在Python中,defandclass关键字会将特定名称绑定到它们定义的对象(函数或类)。同样,模块被称为文件系统中的特定名称。在这三种情况下,都有一种明显的方法可以为所讨论的对象分配“规范”名称。

但是,对于其他种类的对象,这样的规范名称可能根本不存在。例如,考虑列表的元素。列表中的元素没有单独命名,并且完全有可能在程序中引用它们的唯一方法是使用包含列表中的列表索引。如果将这样的对象列表传递到函数中,则可能无法为这些值分配有意义的标识符。

Python不会将分配左侧的名称保存到分配的对象中,因为:

  1. 这就需要弄清楚在多个冲突对象中哪个名称是“规范的”,
  2. 对于从未分配给显式变量名称的对象没有任何意义,
  3. 效率极低,
  4. 从字面上看,没有其他语言可以做到这一点。

因此,例如,使用定义的函数lambda将始终具有“ name” <lambda>,而不是特定的函数名。

最好的方法是简单地要求调用方法传递一个(可选)名称列表。如果键入'...','...'太麻烦,则可以接受例如包含逗号分隔的名称列表的单个字符串(就像namedtuple这样)。

In Python, the def and class keywords will bind a specific name to the object they define (function or class). Similarly, modules are given a name by virtue of being called something specific in the filesystem. In all three cases, there’s an obvious way to assign a “canonical” name to the object in question.

However, for other kinds of objects, such a canonical name may simply not exist. For example, consider the elements of a list. The elements in the list are not individually named, and it is entirely possible that the only way to refer to them in a program is by using list indices on the containing list. If such a list of objects was passed into your function, you could not possibly assign meaningful identifiers to the values.

Python doesn’t save the name on the left hand side of an assignment into the assigned object because:

  1. It would require figuring out which name was “canonical” among multiple conflicting objects,
  2. It would make no sense for objects which are never assigned to an explicit variable name,
  3. It would be extremely inefficient,
  4. Literally no other language in existence does that.

So, for example, functions defined using lambda will always have the “name” <lambda>, rather than a specific function name.

The best approach would be simply to ask the caller to pass in an (optional) list of names. If typing the '...','...' is too cumbersome, you could accept e.g. a single string containing a comma-separated list of names (like namedtuple does).


回答 11

>> my_var = 5
>> my_var_name = [ k for k,v in locals().items() if v == my_var][0]
>> my_var_name 
'my_var'

locals()-返回包含当前范围的局部变量的字典。通过遍历该字典,我们可以检查具有等于定义的变量的值的键,仅提取键将为我们提供字符串格式的变量文本。

来自(经过一些更改) https://www.tutorialspoint.com/How-to-get-a-variable-name-as-a-string-in-Python

>> my_var = 5
>> my_var_name = [ k for k,v in locals().items() if v == my_var][0]
>> my_var_name 
'my_var'

locals() – Return a dictionary containing the current scope’s local variables. by iterating through this dictionary we can check the key which has a value equal to the defined variable, just extracting the key will give us the text of variable in string format.

from (after a bit changes) https://www.tutorialspoint.com/How-to-get-a-variable-name-as-a-string-in-Python


回答 12

我认为用Python做到这一点是如此困难,因为一个简单的事实,就是您永远不会知道所使用的变量的名称。因此,在他的示例中,您可以执行以下操作:

代替:

list_of_dicts = [n_jobs, users, queues, priorities]

dict_of_dicts = {"n_jobs" : n_jobs, "users" : users, "queues" : queues, "priorities" : priorities}

I think it’s so difficult to do this in Python because of the simple fact that you never will not know the name of the variable you’re using. So, in his example, you could do:

Instead of:

list_of_dicts = [n_jobs, users, queues, priorities]

dict_of_dicts = {"n_jobs" : n_jobs, "users" : users, "queues" : queues, "priorities" : priorities}

回答 13

这是基于输入变量的内容执行此操作的另一种方法:

(它返回与输入变量匹配的第一个变量的名称,否则返回None。可以对其进行修改以获取与输入变量具有相同内容的所有变量名称)

def retrieve_name(x, Vars=vars()):
    for k in Vars:
        if type(x) == type(Vars[k]):
            if x is Vars[k]:
                return k
    return None

just another way to do this based on the content of input variable:

(it returns the name of the first variable that matches to the input variable, otherwise None. One can modify it to get all variable names which are having the same content as input variable)

def retrieve_name(x, Vars=vars()):
    for k in Vars:
        if type(x) == type(Vars[k]):
            if x is Vars[k]:
                return k
    return None

回答 14

此函数将打印变量名称及其值:

import inspect

def print_this(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    print(str([k for k, v in callers_local_vars if v is var][0])+': '+str(var))
***Input & Function call:***
my_var = 10

print_this(my_var)

***Output**:*
my_var: 10

This function will print variable name with its value:

import inspect

def print_this(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    print(str([k for k, v in callers_local_vars if v is var][0])+': '+str(var))
***Input & Function call:***
my_var = 10

print_this(my_var)

***Output**:*
my_var: 10

回答 15

我有一种方法,虽然不是最有效的 …但是有效!(并且它不涉及任何高级模块)。

基本上,它将变量的IDglobals()变量的ID进行比较,然后返回匹配项的名称。

def getVariableName(variable, globalVariables=globals().copy()):
    """ Get Variable Name as String by comparing its ID to globals() Variables' IDs

        args:
            variable(var): Variable to find name for (Obviously this variable has to exist)

        kwargs:
            globalVariables(dict): Copy of the globals() dict (Adding to Kwargs allows this function to work properly when imported from another .py)
    """
    for globalVariable in globalVariables:
        if id(variable) == id(globalVariables[globalVariable]): # If our Variable's ID matches this Global Variable's ID...
            return globalVariable # Return its name from the Globals() dict

I have a method, and while not the most efficient…it works! (and it doesn’t involve any fancy modules).

Basically it compares your Variable’s ID to globals() Variables’ IDs, then returns the match’s name.

def getVariableName(variable, globalVariables=globals().copy()):
    """ Get Variable Name as String by comparing its ID to globals() Variables' IDs

        args:
            variable(var): Variable to find name for (Obviously this variable has to exist)

        kwargs:
            globalVariables(dict): Copy of the globals() dict (Adding to Kwargs allows this function to work properly when imported from another .py)
    """
    for globalVariable in globalVariables:
        if id(variable) == id(globalVariables[globalVariable]): # If our Variable's ID matches this Global Variable's ID...
            return globalVariable # Return its name from the Globals() dict

回答 16

如果目标是帮助您跟踪变量,则可以编写一个简单的函数来标记变量并返回其值和类型。例如,假设i_f = 3.01并将其四舍五入为一个称为i_n的整数以在代码中使用,然后需要一个字符串i_s并将其输入报告中。

def whatis(string, x):
    print(string+' value=',repr(x),type(x))
    return string+' value='+repr(x)+repr(type(x))
i_f=3.01
i_n=int(i_f)
i_s=str(i_n)
i_l=[i_f, i_n, i_s]
i_u=(i_f, i_n, i_s)

## make report that identifies all types
report='\n'+20*'#'+'\nThis is the report:\n'
report+= whatis('i_f ',i_f)+'\n'
report+=whatis('i_n ',i_n)+'\n'
report+=whatis('i_s ',i_s)+'\n'
report+=whatis('i_l ',i_l)+'\n'
report+=whatis('i_u ',i_u)+'\n'
print(report)

在每次调用时,此命令都会打印到窗口中以进行调试,并为书面报告生成一个字符串。唯一的缺点是,每次调用该函数时,必须两次键入该变量。

我是Python的新手,发现这种非常有用的方式可以记录我在编程时的工作并尝试处理Python中的所有对象。一个缺点是,如果whatis()调用在使用它的过程之外描述的函数,则它将失败。例如,int(i_f)是有效的函数调用,仅是因为Python知道了int函数。您可以使用int(i_f ** 2)调用whatis(),但是如果出于某些奇怪的原因而选择定义一个名为int_squared的函数,则必须在使用whatis()的过程中声明它。

If the goal is to help you keep track of your variables, you can write a simple function that labels the variable and returns its value and type. For example, suppose i_f=3.01 and you round it to an integer called i_n to use in a code, and then need a string i_s that will go into a report.

def whatis(string, x):
    print(string+' value=',repr(x),type(x))
    return string+' value='+repr(x)+repr(type(x))
i_f=3.01
i_n=int(i_f)
i_s=str(i_n)
i_l=[i_f, i_n, i_s]
i_u=(i_f, i_n, i_s)

## make report that identifies all types
report='\n'+20*'#'+'\nThis is the report:\n'
report+= whatis('i_f ',i_f)+'\n'
report+=whatis('i_n ',i_n)+'\n'
report+=whatis('i_s ',i_s)+'\n'
report+=whatis('i_l ',i_l)+'\n'
report+=whatis('i_u ',i_u)+'\n'
print(report)

This prints to the window at each call for debugging purposes and also yields a string for the written report. The only downside is that you have to type the variable twice each time you call the function.

I am a Python newbie and found this very useful way to log my efforts as I program and try to cope with all the objects in Python. One flaw is that whatis() fails if it calls a function described outside the procedure where it is used. For example, int(i_f) was a valid function call only because the int function is known to Python. You could call whatis() using int(i_f**2), but if for some strange reason you choose to define a function called int_squared it must be declared inside the procedure where whatis() is used.


回答 17

也许这可能是有用的:

def Retriever(bar):
    return (list(globals().keys()))[list(map(lambda x: id(x), list(globals().values()))).index(id(bar))]

该函数遍历全局作用域中值的ID列表(可以编辑命名空间),根据其ID查找所需/所需的var或函数的索引,然后从基于以下名称的全局名称列表中返回名称在获取的索引上。

Maybe this could be useful:

def Retriever(bar):
    return (list(globals().keys()))[list(map(lambda x: id(x), list(globals().values()))).index(id(bar))]

The function goes through the list of IDs of values from the global scope (the namespace could be edited), finds the index of the wanted/required var or function based on its ID, and then returns the name from the list of global names based on the acquired index.


回答 18

以下方法不会返回变量的名称,但是如果变量在全局范围内可用,则使用此方法可以轻松创建数据框。

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}

A = [0, 1]
B = [1, 2]
pd.DataFrame(G.A + G.B) # It will return a data frame with A and B columns

Following method will not return the name of variable but using this method you can create data frame easily if variable is available in global scope.

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}

A = [0, 1]
B = [1, 2]
pd.DataFrame(G.A + G.B) # It will return a data frame with A and B columns

回答 19

对于常量,可以使用枚举,该枚举支持检索其名称。

For constants, you can use an enum, which supports retrieving its name.


回答 20

我尝试从本地检查人员那里获取名称,但是它无法处理像a [1],b.val这样的var。之后,我有了一个新主意—从代码中获取var名称,然后尝试使用succ!如下代码:

#direct get from called function code
def retrieve_name_ex(var):
    stacks = inspect.stack()
    try:
        func = stacks[0].function
        code = stacks[1].code_context[0]
        s = code.index(func)
        s = code.index("(", s + len(func)) + 1
        e = code.index(")", s)
        return code[s:e].strip()
    except:
        return ""

I try to get name from inspect locals, but it cann’t process var likes a[1], b.val. After it, I got a new idea — get var name from the code, and I try it succ! code like below:

#direct get from called function code
def retrieve_name_ex(var):
    stacks = inspect.stack()
    try:
        func = stacks[0].function
        code = stacks[1].code_context[0]
        s = code.index(func)
        s = code.index("(", s + len(func)) + 1
        e = code.index(")", s)
        return code[s:e].strip()
    except:
        return ""

回答 21

您可以尝试以下操作来检索定义的函数的名称(尽管不适用于内置函数):

import re
def retrieve_name(func):
    return re.match("<function\s+(\w+)\s+at.*", str(func)).group(1)

def foo(x):
    return x**2

print(retrieve_name(foo))
# foo

You can try the following to retrieve the name of a function you defined (does not work for built-in functions though):

import re
def retrieve_name(func):
    return re.match("<function\s+(\w+)\s+at.*", str(func)).group(1)

def foo(x):
    return x**2

print(retrieve_name(foo))
# foo