标签归档:python-2.7

获取类的属性

问题:获取类的属性

我想获取一个类的属性,说:

class MyClass():
  a = "12"
  b = "34"

  def myfunc(self):
    return self.a

使用MyClass.__dict__给了我一系列属性和函数,甚至还有像__module__和的函数__doc__。而MyClass().__dict__除非我显式设置该实例的属性值,否则会给我一个空的字典。

我只想要属性,在上面的示例中,这些属性是:ab

I want to get the attributes of a class, say:

class MyClass():
  a = "12"
  b = "34"

  def myfunc(self):
    return self.a

using MyClass.__dict__ gives me a list of attributes and functions, and even functions like __module__ and __doc__. While MyClass().__dict__ gives me an empty dict unless I explicitly set an attribute value of that instance.

I just want the attributes, in the example above those would be: a and b


回答 0

尝试检查模块。getmembers并且各种测试应该会有所帮助。

编辑:

例如,

class MyClass(object):
    a = '12'
    b = '34'
    def myfunc(self):
        return self.a

>>> import inspect
>>> inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
[('__class__', type),
 ('__dict__',
  <dictproxy {'__dict__': <attribute '__dict__' of 'MyClass' objects>,
   '__doc__': None,
   '__module__': '__main__',
   '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
   'a': '34',
   'b': '12',
   'myfunc': <function __main__.myfunc>}>),
 ('__doc__', None),
 ('__module__', '__main__'),
 ('__weakref__', <attribute '__weakref__' of 'MyClass' objects>),
 ('a', '34'),
 ('b', '12')]

现在,特殊的方法和属性引起了我的共鸣-可以通过多种方式处理这些方法和属性,其中最简单的方法就是根据名称进行过滤。

>>> attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
>>> [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))]
[('a', '34'), ('b', '12')]

…,其中更复杂的可以包括特殊的属性名称检查甚至元类;)

Try the inspect module. getmembers and the various tests should be helpful.

EDIT:

For example,

class MyClass(object):
    a = '12'
    b = '34'
    def myfunc(self):
        return self.a

>>> import inspect
>>> inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
[('__class__', type),
 ('__dict__',
  <dictproxy {'__dict__': <attribute '__dict__' of 'MyClass' objects>,
   '__doc__': None,
   '__module__': '__main__',
   '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
   'a': '34',
   'b': '12',
   'myfunc': <function __main__.myfunc>}>),
 ('__doc__', None),
 ('__module__', '__main__'),
 ('__weakref__', <attribute '__weakref__' of 'MyClass' objects>),
 ('a', '34'),
 ('b', '12')]

Now, the special methods and attributes get on my nerves- those can be dealt with in a number of ways, the easiest of which is just to filter based on name.

>>> attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
>>> [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))]
[('a', '34'), ('b', '12')]

…and the more complicated of which can include special attribute name checks or even metaclasses ;)


回答 1

def props(cls):   
  return [i for i in cls.__dict__.keys() if i[:1] != '_']

properties = props(MyClass)
def props(cls):   
  return [i for i in cls.__dict__.keys() if i[:1] != '_']

properties = props(MyClass)

回答 2

myfunc 的属性MyClass。这是在运行时发现的方式:

myinstance = MyClass()
myinstance.myfunc()

它在myinstancenamed myfunc上寻找一个属性,找不到一个,发现它myinstance是的一个实例,MyClass并在那里查找。

因此,属性的完整列表MyClass为:

>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']

(请注意,我使用dir只是列出类成员的一种快速简便的方法:它只能以探索的方式使用,而不能在生产代码中使用)

如果您只想要特定的属性,则需要使用一些条件来过滤此列表,因为__doc____module__myfunc没有特殊的以任何方式,他们的属性完全相同的方式ab是。

我从未使用过Matt和Borealid提到的inspect模块,但是从一个简短的链接来看,它似乎具有测试可以帮助您完成此任务,但是您需要编写自己的谓词函数,因为这似乎是您想要的大概是 通过的isroutine测试且不会以两个下划线开头和结尾。

另请注意:通过class MyClass():在python 2.7中使用,您正在使用过时的老式类。除非您是为了与极老的库兼容而故意这样做,否则应将您的类定义为class MyClass(object):。在Python 3中,没有“旧式”类,并且此行为是默认行为。然而,使用newstyle班会帮你很多更多的自动定义的属性:

>>> class MyClass(object):
        a = "12"
        b = "34"
        def myfunc(self):
            return self.a
>>> dir(MyClass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'myfunc']

myfunc is an attribute of MyClass. That’s how it’s found when you run:

myinstance = MyClass()
myinstance.myfunc()

It looks for an attribute on myinstance named myfunc, doesn’t find one, sees that myinstance is an instance of MyClass and looks it up there.

So the complete list of attributes for MyClass is:

>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']

(Note that I’m using dir just as a quick and easy way to list the members of the class: it should only be used in an exploratory fashion, not in production code)

If you only want particular attributes, you’ll need to filter this list using some criteria, because __doc__, __module__, and myfunc aren’t special in any way, they’re attributes in exactly the same way that a and b are.

I’ve never used the inspect module referred to by Matt and Borealid, but from a brief link it looks like it has tests to help you do this, but you’ll need to write your own predicate function, since it seems what you want is roughly the attributes that don’t pass the isroutine test and don’t start and end with two underscores.

Also note: by using class MyClass(): in Python 2.7 you’re using the wildly out of date old-style classes. Unless you’re doing so deliberately for compatibility with extremely old libraries, you should be instead defining your class as class MyClass(object):. In Python 3 there are no “old-style” classes, and this behaviour is the default. However, using newstyle classes will get you a lot more automatically defined attributes:

>>> class MyClass(object):
        a = "12"
        b = "34"
        def myfunc(self):
            return self.a
>>> dir(MyClass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'myfunc']

回答 3

仅获取实例属性很容易。
但是还要获取类属性没有函数的情况下比较棘手。

仅实例属性

如果您只需要列出实例属性,请使用
for attribute, value in my_instance__dict__items()

>>> from __future__ import (absolute_import, division, print_function)
>>> class MyClass(object):
...   def __init__(self):
...     self.a = 2
...     self.b = 3
...   def print_instance_attributes(self):
...     for attribute, value in self.__dict__.items():
...       print(attribute, '=', value)
...
>>> my_instance = MyClass()
>>> my_instance.print_instance_attributes()
a = 2
b = 3
>>> for attribute, value in my_instance.__dict__.items():
...   print(attribute, '=', value)
...
a = 2
b = 3

实例和类属性

要获得没有功能的类属性,诀窍是使用callable()

静态方法不总是callable

因此,不要使用callable(value)use
callablegetattrMyClass, attribute))

from __future__ import (absolute_import, division, print_function)

class MyClass(object):
   a = "12"
   b = "34"               # class attributes

   def __init__(self, c, d):
     self.c = c
     self.d = d           # instance attributes

   @staticmethod
   def mystatic():        # static method
       return MyClass.b

   def myfunc(self):      # non-static method
     return self.a

   def print_instance_attributes(self):
     print('[instance attributes]')
     for attribute, value in self.__dict__.items():
        print(attribute, '=', value)

   def print_class_attributes(self):
     print('[class attributes]')
     for attribute in self.__dict__.keys():
       if attribute[:2] != '__':
         value = getattr(self, attribute)
         if not callable(value):
           print(attribute, '=', value)

v = MyClass(4,2)
v.print_class_attributes()
v.print_instance_attributes()

注意: print_class_attributes()应该       但不是这个愚蠢和简单@staticmethod
示例中,。

的结果

$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2

的结果相同

$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2

Getting only the instance attributes is easy.
But getting also the class attributes without the functions is a bit more tricky.

Instance attributes only

If you only have to list instance attributes just use
for attribute, value in my_instance.__dict__.items()

>>> from __future__ import (absolute_import, division, print_function)
>>> class MyClass(object):
...   def __init__(self):
...     self.a = 2
...     self.b = 3
...   def print_instance_attributes(self):
...     for attribute, value in self.__dict__.items():
...       print(attribute, '=', value)
...
>>> my_instance = MyClass()
>>> my_instance.print_instance_attributes()
a = 2
b = 3
>>> for attribute, value in my_instance.__dict__.items():
...   print(attribute, '=', value)
...
a = 2
b = 3

Instance and class attributes

To get also the class attributes without the functions, the trick is to use callable().

But static methods are not always callable!

Therefore, instead of using callable(value) use
callable(getattr(MyClass, attribute))

Example

from __future__ import (absolute_import, division, print_function)

class MyClass(object):
   a = "12"
   b = "34"               # class attributes

   def __init__(self, c, d):
     self.c = c
     self.d = d           # instance attributes

   @staticmethod
   def mystatic():        # static method
       return MyClass.b

   def myfunc(self):      # non-static method
     return self.a

   def print_instance_attributes(self):
     print('[instance attributes]')
     for attribute, value in self.__dict__.items():
        print(attribute, '=', value)

   def print_class_attributes(self):
     print('[class attributes]')
     for attribute in self.__dict__.keys():
       if attribute[:2] != '__':
         value = getattr(self, attribute)
         if not callable(value):
           print(attribute, '=', value)

v = MyClass(4,2)
v.print_class_attributes()
v.print_instance_attributes()

Note: print_class_attributes() should be @staticmethod
      but not in this stupid and simple example.

Result for

$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2

Same result for

$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2

回答 4

MyClass().__class__.__dict__

但是,这样做的“正确”是通过检查模块

MyClass().__class__.__dict__

However, the “right” was to do this is via the inspect module.


回答 5

import re

class MyClass:
    a = "12"
    b = "34"

    def myfunc(self):
        return self.a

attributes = [a for a, v in MyClass.__dict__.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

对于MyClass的实例,例如

mc = MyClass()

用于type(mc)代替MyClass列表理解。但是,如果将一个属性动态添加到mc,例如mc.c = "42",则type(mc)在此策略中使用该属性时将不会显示该属性。它仅提供原始类的属性。

要获得类实例的完整字典,您需要将type(mc).__dict__和的字典合并mc.__dict__

mc = MyClass()
mc.c = "42"

# Python 3.5
combined_dict = {**type(mc).__dict__, **mc.__dict__}

# Or Python < 3.5
def dict_union(d1, d2):
    z = d1.copy()
    z.update(d2)
    return z

combined_dict = dict_union(type(mc).__dict__, mc.__dict__)

attributes = [a for a, v in combined_dict.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]
import re

class MyClass:
    a = "12"
    b = "34"

    def myfunc(self):
        return self.a

attributes = [a for a, v in MyClass.__dict__.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

For an instance of MyClass, such as

mc = MyClass()

use type(mc) in place of MyClass in the list comprehension. However, if one dynamically adds an attribute to mc, such as mc.c = "42", the attribute won’t show up when using type(mc) in this strategy. It only gives the attributes of the original class.

To get the complete dictionary for a class instance, you would need to COMBINE the dictionaries of type(mc).__dict__ and mc.__dict__.

mc = MyClass()
mc.c = "42"

# Python 3.5
combined_dict = {**type(mc).__dict__, **mc.__dict__}

# Or Python < 3.5
def dict_union(d1, d2):
    z = d1.copy()
    z.update(d2)
    return z

combined_dict = dict_union(type(mc).__dict__, mc.__dict__)

attributes = [a for a, v in combined_dict.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

回答 6

我不知道是否已经做过类似的事情,但是我使用vars()做了一个不错的属性搜索功能。vars()创建您通过其传递的类的属性的字典。

class Player():
    def __init__(self):
        self.name = 'Bob'
        self.age = 36
        self.gender = 'Male'

s = vars(Player())
#From this point if you want to print all the attributes, just do print(s)

#If the class has a lot of attributes and you want to be able to pick 1 to see
#run this function
def play():
    ask = input("What Attribute?>: ")
    for key, value in s.items():
        if key == ask:
            print("self.{} = {}".format(key, value))
            break
    else:
        print("Couldn't find an attribute for self.{}".format(ask))

我正在用Python开发大量的Text Adventure,到目前为止,我的Player类具有100多个属性。我用它来搜索需要查看的特定属性。

I don’t know if something similar has been made by now or not, but I made a nice attribute search function using vars(). vars() creates a dictionary of the attributes of a class you pass through it.

class Player():
    def __init__(self):
        self.name = 'Bob'
        self.age = 36
        self.gender = 'Male'

s = vars(Player())
#From this point if you want to print all the attributes, just do print(s)

#If the class has a lot of attributes and you want to be able to pick 1 to see
#run this function
def play():
    ask = input("What Attribute?>: ")
    for key, value in s.items():
        if key == ask:
            print("self.{} = {}".format(key, value))
            break
    else:
        print("Couldn't find an attribute for self.{}".format(ask))

I’m developing a pretty massive Text Adventure in Python, my Player class so far has over 100 attributes. I use this to search for specific attributes I need to see.


回答 7

我想这可以在没有检查的情况下完成。

参加以下类:

 class Test:
   a = 1
   b = 2

   def __init__(self):
     self.c = 42

   @staticmethod
   def toto():
     return "toto"

   def test(self):
     return "test"

查看成员及其类型:

t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]

…给出:

[('__doc__', 'NoneType'),
 ('__init__', 'instancemethod'),
 ('__module__', 'str'),
 ('a', 'int'),
 ('b', 'int'),
 ('c', 'int'),
 ('test', 'instancemethod'),
 ('toto', 'function')]

因此,仅输出变量,您只需按类型过滤结果,并且名称不能以“ __”开头。例如

filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)

[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result

而已。

注意:如果您使用的是Python 3,请将迭代器转换为列表。

如果您想要一种更强大的方法,请使用inspect

This can be done without inspect, I guess.

Take the following class:

 class Test:
   a = 1
   b = 2

   def __init__(self):
     self.c = 42

   @staticmethod
   def toto():
     return "toto"

   def test(self):
     return "test"

Looking at the members along with their types:

t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]

… gives:

[('__doc__', 'NoneType'),
 ('__init__', 'instancemethod'),
 ('__module__', 'str'),
 ('a', 'int'),
 ('b', 'int'),
 ('c', 'int'),
 ('test', 'instancemethod'),
 ('toto', 'function')]

So to output only the variables, you just have to filter the results by type, and names not starting with ‘__’. E.g.

filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)

[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result

That’s it.

Note: if you’re using Python 3, convert the iterators to lists.

If you want a more robust way to do it, use inspect.


回答 8

Python 2和3,Whitout导入,通过对象地址过滤对象

简短的解决方案:

返回dict {attribute_name:attribute_value},对象已过滤。即{'a': 1, 'b': (2, 2), 'c': [3, 3]}

{k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}

返回列表[attribute_names],对象已过滤。即['a', 'b', 'c', 'd']

[k for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

返回列表[attribute_values],对象已过滤。即[1, (2, 2), [3, 3], {4: 4}]

[val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

不过滤对象

消除if条件。返回{'a': 1, 'c': [3, 3], 'b': (2, 2), 'e': <function <lambda> at 0x7fc8a870fd70>, 'd': {4: 4}, 'f': <object object at 0x7fc8abe130e0>}

{k: val for k, val in self.__dict__.items()}

长期解决

只要的默认实现__repr__不被覆盖if语句将返回True如果位置在记忆的十六进制表示val是在__repr__返回的字符串。

关于默认实现,__repr__您可以找到此答案有用。简而言之:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

Wich返回类似以下的字符串:

<__main__.Bar object at 0x7f3373be5998>

通过该id()方法可以获取每个元素在内存中的位置。

Python文档对id()说:

返回对象的“身份”。这是一个整数,可以保证在此对象的生存期内唯一且恒定。具有不重叠生存期的两个对象可能具有相同的id()值。

CPython实现细节:这是对象在内存中的地址。


自己尝试

class Bar:

    def __init__(self):

        self.a = 1
        self.b = (2, 2)
        self.c = [3, 3]
        self.d = {4: 4}
        self.e = lambda: "5"
        self.f = object()

    #__str__ or __repr__ as you prefer
    def __str__(self):
        return "{}".format(

            # Solution in Short Number 1
            {k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}

        )

# Main
print(Bar())

输出:

{'a': 1, 'c': [3, 3], 'b': (2, 2), 'd': {4: 4}}

注意事项

  • 经过Python 2.7.13和Python 测试3.5.3

  • 在Python 2.x .iteritems()中,优先于.items()

Python 2 & 3, whitout imports, filtering objects by their address

Solutions in short:

Return dict {attribute_name: attribute_value}, objects filtered. i.e {'a': 1, 'b': (2, 2), 'c': [3, 3]}

{k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}

Return list [attribute_names], objects filtered. i.e ['a', 'b', 'c', 'd']

[k for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

Return list [attribute_values], objects filtered. i.e [1, (2, 2), [3, 3], {4: 4}]

[val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

Not filtering objects

Removing the if condition. Return {'a': 1, 'c': [3, 3], 'b': (2, 2), 'e': <function <lambda> at 0x7fc8a870fd70>, 'd': {4: 4}, 'f': <object object at 0x7fc8abe130e0>}

{k: val for k, val in self.__dict__.items()}

Solution in long

As long as the default implementation of __repr__ is not overridden the if statement will return True if the hexadecimal representation of the location in memory of val is in the __repr__ return string.

Regarding the default implementation of __repr__ you could find useful this answer. In short:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

Wich returns a string like:

<__main__.Bar object at 0x7f3373be5998>

The location in memory of each element is got via the id() method.

Python Docs says about id():

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.


Try by yourself

class Bar:

    def __init__(self):

        self.a = 1
        self.b = (2, 2)
        self.c = [3, 3]
        self.d = {4: 4}
        self.e = lambda: "5"
        self.f = object()

    #__str__ or __repr__ as you prefer
    def __str__(self):
        return "{}".format(

            # Solution in Short Number 1
            {k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}

        )

# Main
print(Bar())

Output:

{'a': 1, 'c': [3, 3], 'b': (2, 2), 'd': {4: 4}}

Note:

  • Tested with Python 2.7.13 and Python 3.5.3

  • In Python 2.x .iteritems() is preferred over .items()


回答 9

我最近需要弄清楚与该问题类似的内容,因此我想发布一些背景信息,这些信息可能会对将来面对相同问题的其他人有所帮助。

以下是它在Python中的工作方式(来自https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy):

MyClass是类对象,MyClass()是类对象的实例。实例__dict__仅具有特定于该实例的属性和方法(例如self.somethings)。如果属性或方法是类的一部分,则它在类的中__dict__。当您执行时MyClass().__dict__,会建立的实例,MyClass除了类别属性外,没有其他属性或方法,因此为空__dict__

因此,如果您说的话print(MyClass().b),Python首先检查新实例的字典MyClass().__dict__['b'],但找不到b。然后,它检查该类MyClass.__dict__['b']并找到b

这就是为什么您需要该inspect模块来模拟相同的搜索过程。

I recently needed to figure out something similar to this question, so I wanted to post some background info that might be helpful to others facing the same in future.

Here’s how it works in Python (from https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy):

MyClass is a class object, MyClass() is an instance of the class object. An instance’s __dict__ only hold attributes and methods specific to that instance (e.g. self.somethings). If an attribute or method is part of a class, it is in the class’s __dict__. When you do MyClass().__dict__, an instance of MyClass is created with no attributes or methods besides the class attributes, thus the empty __dict__

So if you say print(MyClass().b), Python first checks the new instance’s dict MyClass().__dict__['b'] and fails to find b. It then checks the class MyClass.__dict__['b'] and finds b.

That’s why you need the inspect module, to emulate that same search process.


回答 10

您可以dir()列表推导中使用以获取属性名称:

names = [p for p in dir(myobj) if not p.startswith('_')]

使用getattr()来获得属性本身:

attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]

You can use dir() in a list comprehension to get the attribute names:

names = [p for p in dir(myobj) if not p.startswith('_')]

Use getattr() to get the attributes themselves:

attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]

回答 11

我的解决方案,以获取类的所有属性(而不是方法)(如果该类的文档字符串正确书写,并且属性清楚地说明了):

def get_class_attrs(cls):
    return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])

这一部分cls.__dict__['__doc__']提取了该类的文档字符串。

My solution to get all attributes (not methods) of a class (if the class has a properly written docstring that has the attributes clearly spelled out):

def get_class_attrs(cls):
    return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])

This piece cls.__dict__['__doc__'] extracts the docstring of the class.


回答 12

为什么需要列出属性?从语义上看,您的类是一个集合。在这种情况下,我建议使用枚举:

import enum

class myClass(enum.Enum):
     a = "12"
     b = "34"

列出您的属性?没有比这更容易的了:

for attr in myClass:
    print("Name / Value:", attr.name, attr.value)

Why do you need to list the attributes? Seems that semantically your class is a collection. In this cases I recommend to use enum:

import enum

class myClass(enum.Enum):
     a = "12"
     b = "34"

List your attributes? Nothing easier than this:

for attr in myClass:
    print("Name / Value:", attr.name, attr.value)

回答 13

如果要“获取”属性,则有一个非常简单的答案,该答案应该很明显:getattr

class MyClass(object):
a = '12'
b = '34'
def myfunc(self):
    return self.a

>>> getattr(MyClass, 'a')
'12'

>>> getattr(MyClass, 'myfunc')
<function MyClass.myfunc at 0x10de45378>

它在python 2.7和python 3.x中都很好用。

如果要列出这些项目,则仍然需要使用inspect。

If you want to “get” an attribute, there is a very simple answer, which should be obvious: getattr

class MyClass(object):
a = '12'
b = '34'
def myfunc(self):
    return self.a

>>> getattr(MyClass, 'a')
'12'

>>> getattr(MyClass, 'myfunc')
<function MyClass.myfunc at 0x10de45378>

It works dandy both in Python 2.7 and Python 3.x.

If you want a list of these items, you will still need to use inspect.


回答 14

两个功能:

def get_class_attr(Cls) -> []:
    import re
    return [a for a, v in Cls.__dict__.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

def get_class_attr_val(cls):
    attr = get_class_attr(type(cls))
    attr_dict = {}
    for a in attr:
        attr_dict[a] = getattr(cls, a)
    return attr_dict

用:

>>> class MyClass:
    a = "12"
    b = "34"
    def myfunc(self):
        return self.a

>>> m = MyClass()
>>> get_class_attr_val(m)
{'a': '12', 'b': '34'}

two function:

def get_class_attr(Cls) -> []:
    import re
    return [a for a, v in Cls.__dict__.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

def get_class_attr_val(cls):
    attr = get_class_attr(type(cls))
    attr_dict = {}
    for a in attr:
        attr_dict[a] = getattr(cls, a)
    return attr_dict

use:

>>> class MyClass:
    a = "12"
    b = "34"
    def myfunc(self):
        return self.a

>>> m = MyClass()
>>> get_class_attr_val(m)
{'a': '12', 'b': '34'}

回答 15

以下是我想要的。

测试数据

class Base:
    b = 'b'


class MyClass(Base):
    a = '12'

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

    @classmethod
    def c(cls):
        ...

    @property
    def p(self):
        return self.a

    def my_fun(self):
        return self.name
print([name for name, val in inspect.getmembers(MyClass) if not name.startswith('_') and not callable(val)])  # need `import inspect`
print([_ for _ in dir(MyClass) if not _.startswith('_') and not callable(getattr(MyClass, _))])
# both are equ: ['a', 'b', 'p']

my_instance = MyClass('c')
print([_ for _ in dir(my_instance) if not _.startswith('_') and not callable(getattr(my_instance, _))])
# ['a', 'b', 'name', 'p']

The following is what I want.

Test Data

class Base:
    b = 'b'


class MyClass(Base):
    a = '12'

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

    @classmethod
    def c(cls):
        ...

    @property
    def p(self):
        return self.a

    def my_fun(self):
        return self.name
print([name for name, val in inspect.getmembers(MyClass) if not name.startswith('_') and not callable(val)])  # need `import inspect`
print([_ for _ in dir(MyClass) if not _.startswith('_') and not callable(getattr(MyClass, _))])
# both are equ: ['a', 'b', 'p']

my_instance = MyClass('c')
print([_ for _ in dir(my_instance) if not _.startswith('_') and not callable(getattr(my_instance, _))])
# ['a', 'b', 'name', 'p']

回答 16

我知道这是三年前的事,但对于那些将来遇到这个问题的人来说,对我来说:

class_name.attribute 

效果很好。

I know this was three years ago, but for those who are to come by this question in the future, for me:

class_name.attribute 

works just fine.


回答 17

您可以使用MyClass.__attrs__。它只是给出了该类的所有属性。而已。

You can use MyClass.__attrs__. It just gives all the attributes of that class. Nothing more.


如何在Windows上点子或easy_install tkinter

问题:如何在Windows上点子或easy_install tkinter

我的空闲状态抛出错误,并指出tkinter无法导入。

有没有一种简单的方法可以tkinter通过pip或安装easy_install

似乎有很多软件包名称在出现……

此版本以及其他各种各样的版本tkinter-pypy均无效。

pip install python-tk

我在Windows上使用python 2.7,不能apt-get

谢谢。

My Idle is throwing errors that and says tkinter can’t be imported.

Is there a simple way to install tkinter via pip or easy_install?

There seem to be a lot of package names flying around for this…

This and other assorted variations with tkinter-pypy aren’t working.

pip install python-tk

I’m on Windows with Python 2.7 and I don’t have apt-get or other system package managers.


回答 0

好吧,我可以在这里看到两个解决方案:

1)按照适用于PythonDocs-Tkinter安装适用于Windows):

所有标准的Python发行版都包含Tkinter(以及从Python 3.1开始的ttk)。使用支持Tk 8.5或更高版本以及ttk的Python版本很重要。我们建议从ActiveState安装“ ActivePython”发行版,其中包括您需要的所有内容。

在您的Web浏览器中,转到Activestate.com,然后按照链接下载Windows版ActivePython社区版。确保您下载的是3.1或更高版本,而不是2.x版本。

运行安装程序,然后继续。最后,您将获得一个全新的ActivePython安装,例如位于C:\python32。在Windows命令提示符或“开始”菜单的“运行…”命令中,您应该能够通过以下方式运行Python Shell:

% C:\python32\python

这应该给您Python命令提示符。在提示符下,输入以下两个命令:

>>> import tkinter
>>> tkinter._test()

这应该会弹出一个小窗口。窗口顶部的第一行应显示“这是Tcl / Tk版本8.5”;确保它不是8.4!

2)卸载64位Python,然后安装32位Python。

Well I can see two solutions here:

1) Follow the Docs-Tkinter install for Python (for Windows):

Tkinter (and, since Python 3.1, ttk) are included with all standard Python distributions. It is important that you use a version of Python supporting Tk 8.5 or greater, and ttk. We recommend installing the “ActivePython” distribution from ActiveState, which includes everything you’ll need.

In your web browser, go to Activestate.com, and follow along the links to download the Community Edition of ActivePython for Windows. Make sure you’re downloading a 3.1 or newer version, not a 2.x version.

Run the installer, and follow along. You’ll end up with a fresh install of ActivePython, located in, e.g. C:\python32. From a Windows command prompt, or the Start Menu’s “Run…” command, you should then be able to run a Python shell via:

% C:\python32\python

This should give you the Python command prompt. From the prompt, enter these two commands:

>>> import tkinter
>>> tkinter._test()

This should pop up a small window; the first line at the top of the window should say “This is Tcl/Tk version 8.5”; make sure it is not 8.4!

2) Uninstall 64-bit Python and install 32 bit Python.


回答 1

Tkinter库在每个Python安装中都是内置的。而且由于您使用的是Windows,我相信您是通过Python的网站上的二进制文件安装的吗?

如果是这样,那么很可能您输入的命令是错误的。它应该是:

import Tkinter as tk

注意Tkinter开头的大写字母T。

对于Python 3,

import tkinter as tk

The Tkinter library is built-in with every Python installation. And since you are on Windows, I believe you installed Python through the binaries on their website?

If so, Then most probably you are typing the command wrong. It should be:

import Tkinter as tk

Note the capital T at the beginning of Tkinter.

For Python 3,

import tkinter as tk

回答 2

如果您使用virtualenv,则可以使用sudo apt-get install python-tk(python2),sudo apt-get install python3-tk(python3)安装tkinter,并且在虚拟环境中也可以正常工作

If you are using virtualenv, it is fine to install tkinter using sudo apt-get install python-tk(python2), sudo apt-get install python3-tk(python3), and and it will work fine in the virtual environment


回答 3

在安装时,请确保Tcl/Tk选择下Will be installed on hard drive。如果安装时带有左侧的叉号,则不会安装Tkinter。

Python 3也是如此:

When installing make sure that under Tcl/Tk you select Will be installed on hard drive. If it is installing with a cross at the left then Tkinter will not be installed.

The same goes for Python 3:


回答 4

当您为Windows安装python时,请使用标准选项或安装它要求的所有内容。我收到错误消息是因为我取消选择了tcl。

When you install python for Windows, use the standard option or install everything it asks. I got the error because I deselected tcl.


回答 5

在Linux中也有同样的问题。这解决了。(我正在使用Debian 9衍生的本生氦气)

$ sudo apt-get install python3-tk

Had the same problem in Linux. This solved it. (I’m on Debian 9 derived Bunsen Helium)

$ sudo apt-get install python3-tk


回答 6

我发布的是最佳答案,重新引用了我认为没有用的文档。

如果您在安装窗口中选择了tkinter,则会在Windows IFF上将python install打包在一起。

解决方法是修复安装(通过卸载GUI即可),然后选择安装tk。在此过程中,您可能需要指向或重新下载二进制文件。直接从activestate下载对我不起作用。

这是人们在Windows上经常遇到的问题,因为如果您不知道TCL / TK是什么,很容易不想安装它,但是Matplotlib等需要它。

I’m posting as the top answer requotes the documentation which I didn’t find useful.

tkinter comes packaged with python install on windows IFF you select it during the install window.

The solution is to repair the installation (via uninstall GUI is fine), and select to install tk this time. You may need to point at or redownload the binary in this process. Downloading directly from activestate did not work for me.

This is a common problem people have on windows as it’s easy to not want to install TCL/TK if you don’t know what it is, but Matplotlib etc require it.


回答 7

在python中,Tkinter是默认软件包,您可以修复安装并选择Tcl / Tk。运行此命令时,应按以下方式安装DDL:

In python, Tkinter was a default package, you can repair the installation and select Tcl/Tk. When you run this, DDL should be installed like so:


回答 8

我在Win-8和python-3.4 32位上也遇到了类似的问题,可以通过从python.org下载相同版本来解决。

下一步将是点击修复按钮并安装Tk / tkinter软件包,或者只是修复。现在应该获得Python34 / Lib / tkinter模块。导入tkinter应该工作..

I had the similar problem with Win-8 and python-3.4 32 bit , I got it resolved by downloading same version from python.org .

Next step will be to hit the repair button and Install the Tk/tkinter Package or Just hit the repair. Now should get Python34/Lib/tkinter Module present. The import tkinter should work ..


回答 9

在内部cmd,运行命令pip install tk和Tkinter应该安装。

Inside cmd, run command pip install tk and Tkinter should install.


回答 10

最简单的方法:

cd C:\Users\%User%\AppData\Local\Programs\Python\Python37\Scripts> 
pip install pythonds 

Easiest way to do this:

cd C:\Users\%User%\AppData\Local\Programs\Python\Python37\Scripts> 
pip install pythonds 


回答 11

如果您使用的是python 3.4.1,则只需编写此行,from tkinter import *这会将模块中的所有内容放入程序的默认命名空间。实际上,不是像tkinter.Button您说的那样说一个按钮Button

if your using python 3.4.1 just write this line from tkinter import * this will put everything in the module into the default namespace of your program. in fact instead of referring to say a button like tkinter.Button you just type Button


为什么元组在内存中的空间比列表少?

问题:为什么元组在内存中的空间比列表少?

A tuple在Python中占用更少的内存空间:

>>> a = (1,2,3)
>>> a.__sizeof__()
48

lists占用更多的内存空间:

>>> b = [1,2,3]
>>> b.__sizeof__()
64

Python内存管理内部会发生什么?

A tuple takes less memory space in Python:

>>> a = (1,2,3)
>>> a.__sizeof__()
48

whereas lists takes more memory space:

>>> b = [1,2,3]
>>> b.__sizeof__()
64

What happens internally on the Python memory management?


回答 0

我假设您正在使用CPython并使用64位(在CPython 2.7 64位上得到的结果相同)。其他Python实现可能会有所不同,或者您拥有32位Python。

无论采用哪种实现方式,lists都是可变大小的,而tuples是固定大小的。

因此tuples可以将元素直接存储在struct内部,另一方面,列表需要一层间接寻址(它存储指向元素的指针)。间接层是一个指针,在64位系统(即64位,即8字节)上。

但是还有另一件事list:它们过度分配。否则,list.append始终是一项O(n)操作-要使其摊销(快得多!!!),它会过度分配。但是现在它必须跟踪分配的大小和填充的大小(s只需要存储一个大小,因为分配的和填充的大小始终相同)。这意味着每个列表必须存储另一个“大小”,它在64位系统上是64位整数,也是8个字节。O(1)tuple

因此lists比tuples 需要至少16个字节的内存。为什么我说“至少”?由于分配过多。过度分配意味着它分配了比所需更多的空间。但是,过度分配的数量取决于创建列表的“方式”和附加/删除历史记录:

>>> l = [1,2,3]
>>> l.__sizeof__()
64
>>> l.append(4)  # triggers re-allocation (with over-allocation), because the original list is full
>>> l.__sizeof__()
96

>>> l = []
>>> l.__sizeof__()
40
>>> l.append(1)  # re-allocation with over-allocation
>>> l.__sizeof__()
72
>>> l.append(2)  # no re-alloc
>>> l.append(3)  # no re-alloc
>>> l.__sizeof__()
72
>>> l.append(4)  # still has room, so no over-allocation needed (yet)
>>> l.__sizeof__()
72

图片

我决定创建一些图像以伴随以上说明。也许这些有帮助

在示例中,这是(示意性地)将其存储在内存中的方式。我强调了红色(徒手)循环的区别:

这实际上只是一个近似值,因为int对象也是Python对象,并且CPython甚至重用了小整数,因此内存中对象的一种可能更准确的表示形式(尽管不那么可读)将是:

有用的链接:

请注意,__sizeof__它并不会真正返回“正确”的大小!它仅返回存储值的大小。但是,使用sys.getsizeof结果不同:

>>> import sys
>>> l = [1,2,3]
>>> t = (1, 2, 3)
>>> sys.getsizeof(l)
88
>>> sys.getsizeof(t)
72

有24个“额外”字节。这些是真实的,这是方法中未考虑的垃圾收集器开销__sizeof__。这是因为您通常不应该直接使用魔术方法-在这种情况下,请使用知道如何处理魔术方法的函数:(sys.getsizeof这实际上会将GC开销加到的返回值上__sizeof__)。

I assume you’re using CPython and with 64bits (I got the same results on my CPython 2.7 64-bit). There could be differences in other Python implementations or if you have a 32bit Python.

Regardless of the implementation, lists are variable-sized while tuples are fixed-size.

So tuples can store the elements directly inside the struct, lists on the other hand need a layer of indirection (it stores a pointer to the elements). This layer of indirection is a pointer, on 64bit systems that’s 64bit, hence 8bytes.

But there’s another thing that lists do: They over-allocate. Otherwise list.append would be an O(n) operation always – to make it amortized O(1) (much faster!!!) it over-allocates. But now it has to keep track of the allocated size and the filled size (tuples only need to store one size, because allocated and filled size are always identical). That means each list has to store another “size” which on 64bit systems is a 64bit integer, again 8 bytes.

So lists need at least 16 bytes more memory than tuples. Why did I say “at least”? Because of the over-allocation. Over-allocation means it allocates more space than needed. However, the amount of over-allocation depends on “how” you create the list and the append/deletion history:

>>> l = [1,2,3]
>>> l.__sizeof__()
64
>>> l.append(4)  # triggers re-allocation (with over-allocation), because the original list is full
>>> l.__sizeof__()
96

>>> l = []
>>> l.__sizeof__()
40
>>> l.append(1)  # re-allocation with over-allocation
>>> l.__sizeof__()
72
>>> l.append(2)  # no re-alloc
>>> l.append(3)  # no re-alloc
>>> l.__sizeof__()
72
>>> l.append(4)  # still has room, so no over-allocation needed (yet)
>>> l.__sizeof__()
72

Images

I decided to create some images to accompany the explanation above. Maybe these are helpful

This is how it (schematically) is stored in memory in your example. I highlighted the differences with red (free-hand) cycles:

That’s actually just an approximation because int objects are also Python objects and CPython even reuses small integers, so a probably more accurate representation (although not as readable) of the objects in memory would be:

Useful links:

Note that __sizeof__ doesn’t really return the “correct” size! It only returns the size of the stored values. However when you use sys.getsizeof the result is different:

>>> import sys
>>> l = [1,2,3]
>>> t = (1, 2, 3)
>>> sys.getsizeof(l)
88
>>> sys.getsizeof(t)
72

There are 24 “extra” bytes. These are real, that’s the garbage collector overhead that isn’t accounted for in the __sizeof__ method. That’s because you’re generally not supposed to use magic methods directly – use the functions that know how to handle them, in this case: sys.getsizeof (which actually adds the GC overhead to the value returned from __sizeof__).


回答 1

我将更深入地研究CPython代码库,以便我们可以看到大小的实际计算方式。在您的特定示例中没有执行过度分配,因此我不会赘述

我将在这里使用64位值。


lists 的大小由以下函数计算得出list_sizeof

static PyObject *
list_sizeof(PyListObject *self)
{
    Py_ssize_t res;

    res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*);
    return PyInt_FromSsize_t(res);
}

Py_TYPE(self)是一个抓取ob_typeself(返回PyList_Type),而 _PyObject_SIZE另一种宏抓斗tp_basicsize从该类型。tp_basicsize计算为实例结构sizeof(PyListObject)在哪里PyListObject

PyListObject结构包含三个字段:

PyObject_VAR_HEAD     # 24 bytes 
PyObject **ob_item;   #  8 bytes
Py_ssize_t allocated; #  8 bytes

这些内容有评论(我将它们修剪掉)以解释它们的含义,请点击上面的链接阅读它们。PyObject_VAR_HEAD扩展到3个8字节字段(ob_refcountob_typeob_size),所以一个24字节的贡献。

所以现在res是:

sizeof(PyListObject) + self->allocated * sizeof(void*)

要么:

40 + self->allocated * sizeof(void*)

如果列表实例具有已分配的元素。第二部分计算他们的贡献。self->allocated顾名思义,它保存分配的元素数。

没有任何元素,列表的大小计算为:

>>> [].__sizeof__()
40

即实例结构的大小。


tuple对象没有定义tuple_sizeof函数。而是使用它们object_sizeof来计算大小:

static PyObject *
object_sizeof(PyObject *self, PyObject *args)
{
    Py_ssize_t res, isize;

    res = 0;
    isize = self->ob_type->tp_itemsize;
    if (isize > 0)
        res = Py_SIZE(self) * isize;
    res += self->ob_type->tp_basicsize;

    return PyInt_FromSsize_t(res);
}

lists一样,它获取tp_basicsize和,如果对象具有非零值tp_itemsize(意味着它具有可变长度的实例),它将乘以元组中的项数(通过Py_SIZEtp_itemsize

tp_basicsize再次使用sizeof(PyTupleObject)其中的 PyTupleObject结构包含

PyObject_VAR_HEAD       # 24 bytes 
PyObject *ob_item[1];   # 8  bytes

因此,没有任何元素(即Py_SIZEreturn 0),空元组的大小等于sizeof(PyTupleObject)

>>> ().__sizeof__()
24

?? 嗯,这里是我还没有找到一个解释,一个古怪tp_basicsizetuples的实际计算公式如下:

sizeof(PyTupleObject) - sizeof(PyObject *)

为什么8要从中删除其他字节tp_basicsize是我一直无法找到的。(有关可能的解释,请参阅MSeifert的评论)


但是,这基本上是您特定示例中的区别list还会保留许多已分配的元素,这有助于确定何时再次过度分配。

现在,当添加其他元素时,列表确实会执行此过度分配以实现O(1)追加。由于MSeifert的封面很好地覆盖了他的答案,因此尺寸更大。

I’ll take a deeper dive into the CPython codebase so we can see how the sizes are actually calculated. In your specific example, no over-allocations have been performed, so I won’t touch on that.

I’m going to use 64-bit values here, as you are.


The size for lists is calculated from the following function, list_sizeof:

static PyObject *
list_sizeof(PyListObject *self)
{
    Py_ssize_t res;

    res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*);
    return PyInt_FromSsize_t(res);
}

Here Py_TYPE(self) is a macro that grabs the ob_type of self (returning PyList_Type) while _PyObject_SIZE is another macro that grabs tp_basicsize from that type. tp_basicsize is calculated as sizeof(PyListObject) where PyListObject is the instance struct.

The PyListObject structure has three fields:

PyObject_VAR_HEAD     # 24 bytes 
PyObject **ob_item;   #  8 bytes
Py_ssize_t allocated; #  8 bytes

these have comments (which I trimmed) explaining what they are, follow the link above to read them. PyObject_VAR_HEAD expands into three 8 byte fields (ob_refcount, ob_type and ob_size) so a 24 byte contribution.

So for now res is:

sizeof(PyListObject) + self->allocated * sizeof(void*)

or:

40 + self->allocated * sizeof(void*)

If the list instance has elements that are allocated. the second part calculates their contribution. self->allocated, as it’s name implies, holds the number of allocated elements.

Without any elements, the size of lists is calculated to be:

>>> [].__sizeof__()
40

i.e the size of the instance struct.


tuple objects don’t define a tuple_sizeof function. Instead, they use object_sizeof to calculate their size:

static PyObject *
object_sizeof(PyObject *self, PyObject *args)
{
    Py_ssize_t res, isize;

    res = 0;
    isize = self->ob_type->tp_itemsize;
    if (isize > 0)
        res = Py_SIZE(self) * isize;
    res += self->ob_type->tp_basicsize;

    return PyInt_FromSsize_t(res);
}

This, as for lists, grabs the tp_basicsize and, if the object has a non-zero tp_itemsize (meaning it has variable-length instances), it multiplies the number of items in the tuple (which it gets via Py_SIZE) with tp_itemsize.

tp_basicsize again uses sizeof(PyTupleObject) where the PyTupleObject struct contains:

PyObject_VAR_HEAD       # 24 bytes 
PyObject *ob_item[1];   # 8  bytes

So, without any elements (that is, Py_SIZE returns 0) the size of empty tuples is equal to sizeof(PyTupleObject):

>>> ().__sizeof__()
24

huh? Well, here’s an oddity which I haven’t found an explanation for, the tp_basicsize of tuples is actually calculated as follows:

sizeof(PyTupleObject) - sizeof(PyObject *)

why an additional 8 bytes is removed from tp_basicsize is something I haven’t been able to find out. (See MSeifert’s comment for a possible explanation)


But, this is basically the difference in your specific example. lists also keep around a number of allocated elements which helps determine when to over-allocate again.

Now, when additional elements are added, lists do indeed perform this over-allocation in order to achieve O(1) appends. This results in greater sizes as MSeifert’s covers nicely in his answer.


回答 2

MSeifert的答案涵盖了广泛的范围;为简单起见,您可以想到:

tuple是一成不变的。一旦设置,您将无法更改。因此,您预先知道需要为该对象分配多少内存。

list易变。您可以在其中添加或删除项目。它必须知道它的大小(用于内部隐含)。根据需要调整大小。

没有免费的餐点 -这些功能需要付费。因此,列表的内存开销。

MSeifert answer covers it broadly; to keep it simple you can think of:

tuple is immutable. Once it set, you can’t change it. So you know in advance how much memory you need to allocate for that object.

list is mutable. You can add or remove items to or from it. It has to know the size of it (for internal impl.). It resizes as needed.

There are no free meals – these capabilities comes with a cost. Hence the overhead in memory for lists.


回答 3

元组的大小是有前缀的,这意味着在元组初始化时,解释器会为所包含的数据分配足够的空间,这就是它的结尾,使其具有不变性(无法修改),而列表是可变对象,因此意味着动态分配内存,因此避免每次您追加或修改列表时都要分配空间(分配足够的空间来容纳已更改的数据并将数据复制到其中),它会为以后的追加,修改等分配更多的空间。总结。

The size of the tuple is prefixed, meaning at tuple initialization the interpreter allocate enough space for the contained data, and that’s the end of it, giving it’s immutable (can’t be modified), whereas a list is a mutable object hence implying dynamic allocation of memory, so to avoid allocating space each time you append or modify the list ( allocate enough space to contain the changed data and copy the data to it), it allocates additional space for future append, modifications, … that pretty much sums it up.


如何以固定宽度打印字符串?

问题:如何以固定宽度打印字符串?

我有这段代码(在字符串中打印所有排列的出现)

def splitter(str):
    for i in range(1, len(str)):
        start = str[0:i]
        end = str[i:]
        yield (start, end)
        for split in splitter(end):
            result = [start]
            result.extend(split)
            yield result    

el =[];

string = "abcd"
for b in splitter("abcd"):
    el.extend(b);

unique =  sorted(set(el));

for prefix in unique:
    if prefix != "":
        print "value  " , prefix  , "- num of occurrences =   " , string.count(str(prefix));

我想打印字符串可变项中所有出现的排列。

由于排列的长度不同,所以我想固定宽度并以一种不太好的方式打印它:

value   a - num of occurrences =    1
value   ab - num of occurrences =    1
value   abc - num of occurrences =    1
value   b - num of occurrences =    1
value   bc - num of occurrences =    1
value   bcd - num of occurrences =    1
value   c - num of occurrences =    1
value   cd - num of occurrences =    1
value   d - num of occurrences =    1

我该如何使用format呢?

我找到了这些帖子,但与字母数字字符串的配合并不理想:

python字符串格式固定宽度

使用python设置固定长度

I have this code (printing the occurrence of the all permutations in a string)

def splitter(str):
    for i in range(1, len(str)):
        start = str[0:i]
        end = str[i:]
        yield (start, end)
        for split in splitter(end):
            result = [start]
            result.extend(split)
            yield result    

el =[];

string = "abcd"
for b in splitter("abcd"):
    el.extend(b);

unique =  sorted(set(el));

for prefix in unique:
    if prefix != "":
        print "value  " , prefix  , "- num of occurrences =   " , string.count(str(prefix));

I want to print all the permutation occurrence there is in string varaible.

since the permutation aren’t in the same length i want to fix the width and print it in a nice not like this one:

value   a - num of occurrences =    1
value   ab - num of occurrences =    1
value   abc - num of occurrences =    1
value   b - num of occurrences =    1
value   bc - num of occurrences =    1
value   bcd - num of occurrences =    1
value   c - num of occurrences =    1
value   cd - num of occurrences =    1
value   d - num of occurrences =    1

How can I use format to do it?

I found these posts but it didn’t go well with alphanumeric strings:

python string formatting fixed width

Setting fixed length with python


回答 0

编辑2013-12-11-这个答案很老了。它仍然是有效且正确的,但是关注此问题的人们应该更喜欢新格式的语法

您可以使用以下字符串格式

>>> print '%5s' % 'aa'
   aa
>>> print '%5s' % 'aaa'
  aaa
>>> print '%5s' % 'aaaa'
 aaaa
>>> print '%5s' % 'aaaaa'
aaaaa

基本上:

  • %字符运筹学Python它将不得不替代的东西令牌
  • s字符运筹学Python令牌将是一个字符串
  • 5(或任意你想要的号码)通知Python垫字符串用空格最多5个字符。

在您的特定情况下,可能的实现可能类似于:

>>> dict_ = {'a': 1, 'ab': 1, 'abc': 1}
>>> for item in dict_.items():
...     print 'value %3s - num of occurances = %d' % item # %d is the token of integers
... 
value   a - num of occurances = 1
value  ab - num of occurances = 1
value abc - num of occurances = 1

旁注:只是想知道您是否知道itertools模块的存在。例如,您可以使用以下命令在一行中获取所有组合的列表:

>>> [''.join(perm) for i in range(1, len(s)) for perm in it.permutations(s, i)]
['a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'ba', 'bc', 'bd', 'ca', 'cb', 'cd', 'da', 'db', 'dc', 'abc', 'abd', 'acb', 'acd', 'adb', 'adc', 'bac', 'bad', 'bca', 'bcd', 'bda', 'bdc', 'cab', 'cad', 'cba', 'cbd', 'cda', 'cdb', 'dab', 'dac', 'dba', 'dbc', 'dca', 'dcb']

,您可以combinations结合使用来获得出现次数count()

EDIT 2013-12-11 – This answer is very old. It is still valid and correct, but people looking at this should prefer the new format syntax.

You can use string formatting like this:

>>> print '%5s' % 'aa'
   aa
>>> print '%5s' % 'aaa'
  aaa
>>> print '%5s' % 'aaaa'
 aaaa
>>> print '%5s' % 'aaaaa'
aaaaa

Basically:

  • the % character informs python it will have to substitute something to a token
  • the s character informs python the token will be a string
  • the 5 (or whatever number you wish) informs python to pad the string with spaces up to 5 characters.

In your specific case a possible implementation could look like:

>>> dict_ = {'a': 1, 'ab': 1, 'abc': 1}
>>> for item in dict_.items():
...     print 'value %3s - num of occurances = %d' % item # %d is the token of integers
... 
value   a - num of occurances = 1
value  ab - num of occurances = 1
value abc - num of occurances = 1

SIDE NOTE: Just wondered if you are aware of the existence of the itertools module. For example you could obtain a list of all your combinations in one line with:

>>> [''.join(perm) for i in range(1, len(s)) for perm in it.permutations(s, i)]
['a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'ba', 'bc', 'bd', 'ca', 'cb', 'cd', 'da', 'db', 'dc', 'abc', 'abd', 'acb', 'acd', 'adb', 'adc', 'bac', 'bad', 'bca', 'bcd', 'bda', 'bdc', 'cab', 'cad', 'cba', 'cbd', 'cda', 'cdb', 'dab', 'dac', 'dba', 'dbc', 'dca', 'dcb']

and you could get the number of occurrences by using combinations in conjunction with count().


回答 1

我发现使用str.format起来更加优雅:

>>> '{0: <5}'.format('ss')
'ss   '
>>> '{0: <5}'.format('sss')
'sss  '
>>> '{0: <5}'.format('ssss')
'ssss '
>>> '{0: <5}'.format('sssss')
'sssss'

如果要使字符串正确对齐,请使用>代替<

>>> '{0: >5}'.format('ss')
'   ss'

编辑:如注释中所述:0表示传递给的参数的索引str.format()

I find using str.format much more elegant:

>>> '{0: <5}'.format('s')
's    '
>>> '{0: <5}'.format('ss')
'ss   '
>>> '{0: <5}'.format('sss')
'sss  '
>>> '{0: <5}'.format('ssss')
'ssss '
>>> '{0: <5}'.format('sssss')
'sssss'

If you want to align the string to the right use > instead of <:

>>> '{0: >5}'.format('ss')
'   ss'

Edit 1: As mentioned in the comments: the 0 in '{0: <5}' indicates the argument’s index passed to str.format().


Edit 2: In python3 one could use also f-string:

sub_str='s'
for i in range(1,6):
    s = sub_str*i
    print(f'{s:>5}')
    
'    s'
'   ss'
'  sss'
' ssss'
'sssss'

or:

for i in range(1,5):
    s = sub_str*i
    print(f'{s:<5}')
's    '
'ss   '
'sss  '
'ssss '
'sssss'

of note, in some places above, ' ' (single quotation marks) were added to emphasize the width of the printed strings.


回答 2

最初是作为对@ 0x90答案的编辑而发布的,但是由于偏离了帖子的原始意图而被拒绝,建议将其发布为评论或答案,因此,我在此处包括简短的文章。

除了来自@ 0x90的答案,还可以通过使用宽度变量(根据@ user2763554的注释)来使语法更加灵活:

width=10
'{0: <{width}}'.format('sss', width=width)

此外,您可以仅通过使用数字并依靠传递给的参数的顺序来使表达式更简短format

width=10
'{0: <{1}}'.format('sss', width)

甚至不考虑所有数字,以获得最大的,可能是非Python隐式的紧凑性:

width=10
'{: <{}}'.format('sss', width)

更新2017-05-26

随着Python 3.6 中格式化字符串文字(简称为“ f-strings”)的引入,现在可以使用更简短的语法访问先前定义的变量:

>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'

这也适用于字符串格式

>>> width=10
>>> string = 'sss'
>>> f'{string: <{width}}'
'sss       '

Originally posted as an edit to @0x90’s answer, but it got rejected for deviating from the post’s original intent and recommended to post as a comment or answer, so I’m including the short write-up here.

In addition to the answer from @0x90, the syntax can be made more flexible, by using a variable for the width (as per @user2763554’s comment):

width=10
'{0: <{width}}'.format('sss', width=width)

Further, you can make this expression briefer, by only using numbers and relying on the order of the arguments passed to format:

width=10
'{0: <{1}}'.format('sss', width)

Or even leave out all numbers for maximal, potentially non-pythonically implicit, compactness:

width=10
'{: <{}}'.format('sss', width)

Update 2017-05-26

With the introduction of formatted string literals (“f-strings” for short) in Python 3.6, it is now possible to access previously defined variables with a briefer syntax:

>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'

This also applies to string formatting

>>> width=10
>>> string = 'sss'
>>> f'{string: <{width}}'
'sss       '

回答 3

format绝对是最优雅的方法,但是afaik不能在python的logging模块中使用它,因此这是使用%格式化的方法:

formatter = logging.Formatter(
    fmt='%(asctime)s | %(name)-20s | %(levelname)-10s | %(message)s',
)

在此,-表示左对齐,而前面的数字s表示固定宽度。

一些示例输出:

2017-03-14 14:43:42,581 | this-app             | INFO       | running main
2017-03-14 14:43:42,581 | this-app.aux         | DEBUG      | 5 is an int!
2017-03-14 14:43:42,581 | this-app.aux         | INFO       | hello
2017-03-14 14:43:42,581 | this-app             | ERROR      | failed running main

此处的文档提供了更多信息:https : //docs.python.org/2/library/stdtypes.html#string-formatting-operations

format is definitely the most elegant way, but afaik you can’t use that with python’s logging module, so here’s how you can do it using the % formatting:

formatter = logging.Formatter(
    fmt='%(asctime)s | %(name)-20s | %(levelname)-10s | %(message)s',
)

Here, the - indicates left-alignment, and the number before s indicates the fixed width.

Some sample output:

2017-03-14 14:43:42,581 | this-app             | INFO       | running main
2017-03-14 14:43:42,581 | this-app.aux         | DEBUG      | 5 is an int!
2017-03-14 14:43:42,581 | this-app.aux         | INFO       | hello
2017-03-14 14:43:42,581 | this-app             | ERROR      | failed running main

More info at the docs here: https://docs.python.org/2/library/stdtypes.html#string-formatting-operations


回答 4

>>> print(f"{'123':<4}56789")
123 56789
>>> print(f"{'123':<4}56789")
123 56789

如何为带有测试的pytest类正确设置和拆卸?

问题:如何为带有测试的pytest类正确设置和拆卸?

我正在使用硒进行端到端测试,但无法获得使用方法setup_classteardown_class方法。

我需要在setup_class方法中设置浏览器,然后执行一堆定义为类方法的测试,最后退出teardown_class方法中的浏览器。

但是从逻辑上讲,这似乎是一个糟糕的解决方案,因为实际上我的测试不适用于类,而适用于对象。我self在每个测试方法中传递参数,因此可以访问对象的vars:

class TestClass:
  
    def setup_class(cls):
        pass
        
    def test_buttons(self, data):
        # self.$attribute can be used, but not cls.$attribute?  
        pass
        
    def test_buttons2(self, data):
        # self.$attribute can be used, but not cls.$attribute?
        pass
        
    def teardown_class(cls):
        pass
    

甚至为类创建浏览器实例似乎也不正确。应该为每个对象分别创建,对吗?

因此,我需要使用__init__and __del__方法代替setup_classand teardown_class

I am using selenium for end to end testing and I can’t get how to use setup_class and teardown_class methods.

I need to set up browser in setup_class method, then perform a bunch of tests defined as class methods and finally quit browser in teardown_class method.

But logically it seems like a bad solution, because in fact my tests will not work with class, but with object. I pass self param inside every test method, so I can access objects’ vars:

class TestClass:
  
    def setup_class(cls):
        pass
        
    def test_buttons(self, data):
        # self.$attribute can be used, but not cls.$attribute?  
        pass
        
    def test_buttons2(self, data):
        # self.$attribute can be used, but not cls.$attribute?
        pass
        
    def teardown_class(cls):
        pass
    

And it even seems not to be correct to create browser instance for class.. It should be created for every object separately, right?

So, I need to use __init__ and __del__ methods instead of setup_class and teardown_class?


回答 0

根据Fixture的完成/执行拆卸代码,当前设置和拆卸的最佳做法是使用yield而不是return

import pytest

@pytest.fixture()
def resource():
    print("setup")
    yield "resource"
    print("teardown")

class TestResource:
    def test_that_depends_on_resource(self, resource):
        print("testing {}".format(resource))

运行它会导致

$ py.test --capture=no pytest_yield.py
=== test session starts ===
platform darwin -- Python 2.7.10, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
collected 1 items

pytest_yield.py setup
testing resource
.teardown


=== 1 passed in 0.01 seconds ===

编写拆卸代码的另一种方法是,将一个request-context对象接受到您的Fixture函数中,并request.addfinalizer使用执行一次或多次拆卸的函数调用其方法:

import pytest

@pytest.fixture()
def resource(request):
    print("setup")

    def teardown():
        print("teardown")
    request.addfinalizer(teardown)
    
    return "resource"

class TestResource:
    def test_that_depends_on_resource(self, resource):
        print("testing {}".format(resource))

According to Fixture finalization / executing teardown code, the current best practice for setup and teardown is to use yield instead of return:

import pytest

@pytest.fixture()
def resource():
    print("setup")
    yield "resource"
    print("teardown")

class TestResource:
    def test_that_depends_on_resource(self, resource):
        print("testing {}".format(resource))

Running it results in

$ py.test --capture=no pytest_yield.py
=== test session starts ===
platform darwin -- Python 2.7.10, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
collected 1 items

pytest_yield.py setup
testing resource
.teardown


=== 1 passed in 0.01 seconds ===

Another way to write teardown code is by accepting a request-context object into your fixture function and calling its request.addfinalizer method with a function that performs the teardown one or multiple times:

import pytest

@pytest.fixture()
def resource(request):
    print("setup")

    def teardown():
        print("teardown")
    request.addfinalizer(teardown)
    
    return "resource"

class TestResource:
    def test_that_depends_on_resource(self, resource):
        print("testing {}".format(resource))

回答 1

当您编写“定义为类方法的测试”时,您是说类方法(将其作为第一个参数的方法)还是常规方法(将实例作为第一个参数的方法)?

由于您的示例使用self了测试方法,因此我假设是后者,因此您只需要使用setup_method

class Test:

    def setup_method(self, test_method):
        # configure self.attribute

    def teardown_method(self, test_method):
        # tear down self.attribute

    def test_buttons(self):
        # use self.attribute for test

测试方法实例传递给setup_methodteardown_method,但是如果您的设置/拆卸代码不需要了解测试上下文,则可以忽略该方法。可以在这里找到更多信息

我还建议您熟悉py.test的装置,因为它们是更强大的概念。

When you write “tests defined as class methods”, do you really mean class methods (methods which receive its class as first parameter) or just regular methods (methods which receive an instance as first parameter)?

Since your example uses self for the test methods I’m assuming the latter, so you just need to use setup_method instead:

class Test:

    def setup_method(self, test_method):
        # configure self.attribute

    def teardown_method(self, test_method):
        # tear down self.attribute

    def test_buttons(self):
        # use self.attribute for test

The test method instance is passed to setup_method and teardown_method, but can be ignored if your setup/teardown code doesn’t need to know the testing context. More information can be found here.

I also recommend that you familiarize yourself with py.test’s fixtures, as they are a more powerful concept.


回答 2

这可能会有所帮助http://docs.pytest.org/en/latest/xunit_setup.html

在测试套件中,我将测试用例分组。对于安装和拆卸,我需要该类中的所有测试用例,我使用setup_class(cls)teardown_class(cls)类方法。

对于每个测试用例的设置和拆卸,我使用setup_method(method)teardown_method(methods)

例:

lh = <got log handler from logger module>

class TestClass:
    @classmethod
    def setup_class(cls):
        lh.info("starting class: {} execution".format(cls.__name__))

    @classmethod
    def teardown_class(cls):
        lh.info("starting class: {} execution".format(cls.__name__))

    def setup_method(self, method):
        lh.info("starting execution of tc: {}".format(method.__name__))

    def teardown_method(self, method):
        lh.info("starting execution of tc: {}".format(method.__name__))

    def test_tc1(self):
        <tc_content>
        assert 

    def test_tc2(self):
        <tc_content>
        assert

现在,当我运行测试时,当TestClass执行开始时,它将记录何时开始执行,何时结束执行以及方法的详细信息。

您可以在相应位置添加其他设置和拆卸步骤。

希望能帮助到你!

This might help http://docs.pytest.org/en/latest/xunit_setup.html

In my test suite, I group my test cases into classes. For the setup and teardown I need for all the test cases in that class, I use the setup_class(cls) and teardown_class(cls) classmethods.

And for the setup and teardown I need for each of the test case, I use the setup_method(method) and teardown_method(methods)

Example:

lh = <got log handler from logger module>

class TestClass:
    @classmethod
    def setup_class(cls):
        lh.info("starting class: {} execution".format(cls.__name__))

    @classmethod
    def teardown_class(cls):
        lh.info("starting class: {} execution".format(cls.__name__))

    def setup_method(self, method):
        lh.info("starting execution of tc: {}".format(method.__name__))

    def teardown_method(self, method):
        lh.info("starting execution of tc: {}".format(method.__name__))

    def test_tc1(self):
        <tc_content>
        assert 

    def test_tc2(self):
        <tc_content>
        assert

Now when I run my tests, when the TestClass execution is starting, it logs the details for when it is beginning execution, when it is ending execution and same for the methods..

You can add up other setup and teardown steps you might have in the respective locations.

Hope it helps!


回答 3

正如@Bruno所建议的那样,使用pytest固定装置是另一种解决方案,可用于两个测试类甚至是简单的测试函数。这是测试python2.7函数的示例

import pytest

@pytest.fixture(scope='function')
def some_resource(request):
    stuff_i_setup = ["I setup"]

    def some_teardown():
        stuff_i_setup[0] += " ... but now I'm torn down..."
        print stuff_i_setup[0]
    request.addfinalizer(some_teardown)

    return stuff_i_setup[0]

def test_1_that_needs_resource(some_resource):
    print some_resource + "... and now I'm testing things..."

所以,跑步 test_1...生成:

I setup... and now I'm testing things...
I setup ... but now I'm torn down...

该通知stuff_i_setup是在夹具中引用,使该对象是setuptorn down为测试它与交互。您可以想象这对于持久性对象(例如假设的数据库或某些连接)很有用,必须在每次测试运行之前清除这些持久性对象以使它们隔离。

As @Bruno suggested, using pytest fixtures is another solution that is accessible for both test classes or even just simple test functions. Here’s an example testing python2.7 functions:

import pytest

@pytest.fixture(scope='function')
def some_resource(request):
    stuff_i_setup = ["I setup"]

    def some_teardown():
        stuff_i_setup[0] += " ... but now I'm torn down..."
        print stuff_i_setup[0]
    request.addfinalizer(some_teardown)

    return stuff_i_setup[0]

def test_1_that_needs_resource(some_resource):
    print some_resource + "... and now I'm testing things..."

So, running test_1... produces:

I setup... and now I'm testing things...
I setup ... but now I'm torn down...

Notice that stuff_i_setup is referenced in the fixture, allowing that object to be setup and torn down for the test it’s interacting with. You can imagine this could be useful for a persistent object, such as a hypothetical database or some connection, that must be cleared before each test runs to keep them isolated.


回答 4

添加@classmethod装饰器后,您的代码应该可以按预期工作。

@classmethod 
def setup_class(cls):
    "Runs once per class"

@classmethod 
def teardown_class(cls):
    "Runs at end of class"

参见http://pythontesting.net/framework/pytest/pytest-xunit-style-fixtures/

Your code should work just as you expect it to if you add @classmethod decorators.

@classmethod 
def setup_class(cls):
    "Runs once per class"

@classmethod 
def teardown_class(cls):
    "Runs at end of class"

See http://pythontesting.net/framework/pytest/pytest-xunit-style-fixtures/


在python中检测按键?

问题:在python中检测按键?

我正在用python开发一个秒表类型的程序,我想知道如何检测是否按下了一个键(例如p表示暂停,s表示停止),而我不希望它像raw_input这样等待用户输入,然后继续执行。有人知道如何在while循环中执行此操作吗?

另外,我想做这个跨平台的,但是如果那不可能,那么我的主要开发目标是linux

I am making a stopwatch type program in python and I would like to know how to detect if a key is pressed (such as p for pause and s for stop), and I would not like it to be something like raw_input that waits for the user’s input before continuing execution. Anyone know how to do this in a while loop?

Also, I would like to make this cross-platform, but if that is not possible, then my main development target is linux


回答 0

Python有一个具有许多功能的键盘模块。安装它,也许使用以下命令:

pip3 install keyboard

然后在如下代码中使用它:

import keyboard  # using module keyboard
while True:  # making a loop
    try:  # used try so that if user pressed other than the given key error will not be shown
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            print('You Pressed A Key!')
            break  # finishing the loop
    except:
        break  # if user pressed a key other than the given key the loop will break

Python has a keyboard module with many features. Install it, perhaps with this command:

pip3 install keyboard

Then use it in code like:

import keyboard  # using module keyboard
while True:  # making a loop
    try:  # used try so that if user pressed other than the given key error will not be shown
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            print('You Pressed A Key!')
            break  # finishing the loop
    except:
        break  # if user pressed a key other than the given key the loop will break

回答 1

对于那些在窗户上努力寻找可行答案的人,我的是:pynput

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

上面的功能将打印您所按的任何键,并在您释放“ esc”键时启动操作。键盘文档在这里用于更多变化的用法。

马库斯·冯·布罗迪(Markus von Broady)强调了一个潜在的问题,即:这个答案并不需要您在当前窗口中激活此脚本,Windows的解决方案是:

from win32gui import GetWindowText, GetForegroundWindow
current_window = (GetWindowText(GetForegroundWindow()))
desired_window_name = "Stopwatch" #Whatever the name of your window should be

#Infinite loops are dangerous.
while True: #Don't rely on this line of code too much and make sure to adapt this to your project.
    if current_window == desired_window_name:

        with Listener(
            on_press=on_press,
            on_release=on_release) as listener:
            listener.join()

For those who are on windows and were struggling to find an working answer here’s mine: pynput

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

The function above will print whichever key you are pressing plus start an action as you release the ‘esc’ key. The keyboard documentation is here for a more variated usage.

Markus von Broady highlighted a potential issue that is: This answer doesn’t require you being in the current window to this script be activated, a solution to windows would be:

from win32gui import GetWindowText, GetForegroundWindow
current_window = (GetWindowText(GetForegroundWindow()))
desired_window_name = "Stopwatch" #Whatever the name of your window should be

#Infinite loops are dangerous.
while True: #Don't rely on this line of code too much and make sure to adapt this to your project.
    if current_window == desired_window_name:

        with Listener(
            on_press=on_press,
            on_release=on_release) as listener:
            listener.join()

回答 2

正如OP关于raw_input的提及-这意味着他想要cli解决方案。Linux:curses是您想要的(Windows PDCurses)。Curses是cli软件的图形API,您不仅可以检测关键事件,还可以实现更多目标。

该代码将检测按键,直到按下新行为止。

import curses
import os

def main(win):
    win.nodelay(True)
    key=""
    win.clear()                
    win.addstr("Detected key:")
    while 1:          
        try:                 
           key = win.getkey()         
           win.clear()                
           win.addstr("Detected key:")
           win.addstr(str(key)) 
           if key == os.linesep:
              break           
        except Exception as e:
           # No input   
           pass         

curses.wrapper(main)

As OP mention about raw_input – that means he want cli solution. Linux: curses is what you want (windows PDCurses). Curses, is an graphical API for cli software, you can achieve more than just detect key events.

This code will detect keys until new line is pressed.

import curses
import os

def main(win):
    win.nodelay(True)
    key=""
    win.clear()                
    win.addstr("Detected key:")
    while 1:          
        try:                 
           key = win.getkey()         
           win.clear()                
           win.addstr("Detected key:")
           win.addstr(str(key)) 
           if key == os.linesep:
              break           
        except Exception as e:
           # No input   
           pass         

curses.wrapper(main)

回答 3

使用keyboard模块可以做更多的事情。

以下是一些方法:


方法1:

使用功能read_key()

import keyboard

while True:
    if keyboard.read_key() == "p":
        print("You pressed p")
        break

p按下该键将打破循环。


方法2:

使用功能wait

import keyboard

keyboard.wait("p")
print("You pressed p")

它将等待您按下p并继续按下代码。


方法3:

使用功能on_press_key

import keyboard

keyboard.on_press_key("p", lambda _:print("You pressed p"))

它需要一个回调函数。我_之所以使用,是因为键盘功能将键盘事件返回到该功能。

一旦执行,当按下键时它将运行该功能。您可以通过运行以下行来停止所有挂钩:

keyboard.unhook_all()

方法4:

user8167727已经回答了这种方法,但是我不同意他们编写的代码。它将使用该函数,is_pressed但以另一种方式:

import keyboard

while True:
    if keyboard.is_pressed("p"):
        print("You pressed p")
        break

p按下将打破循环。


笔记:

  • keyboard 将从整个操作系统读取按键。
  • keyboard 在Linux上需要root

There are more things which can be done with keyboard module.

Here are some of the methods:


Method #1:

Using the function read_key():

import keyboard

while True:
    if keyboard.read_key() == "p":
        print("You pressed p")
        break

This is gonna break the loop as the key p is pressed.


Method #2:

Using function wait:

import keyboard

keyboard.wait("p")
print("You pressed p")

It will wait for you to press p and continue the code as it is pressed.


Method #3:

Using the function on_press_key:

import keyboard

keyboard.on_press_key("p", lambda _:print("You pressed p"))

It needs a callback function. I used _ because the keyboard function returns the keyboard event to that function.

Once executed, it will run the function when the key is pressed. You can stop all hooks by running this line:

keyboard.unhook_all()

Method #4:

This method is sort of already answered by user8167727 but I disagree with the code they made. It will be using the function is_pressed but in an other way:

import keyboard

while True:
    if keyboard.is_pressed("p"):
        print("You pressed p")
        break

It will break the loop as p is pressed.


Notes:

  • keyboard will read keypresses from the whole OS.
  • keyboard requires root on linux

回答 4

对于Windows,您可以这样使用msvcrt

   import msvcrt
   while True:
       if msvcrt.kbhit():
           key = msvcrt.getch()
           print(key)   # just to show the result

For Windows you could use msvcrt like this:

   import msvcrt
   while True:
       if msvcrt.kbhit():
           key = msvcrt.getch()
           print(key)   # just to show the result

回答 5

使用此代码查找按下了哪个键

from pynput import keyboard

def on_press(key):
    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))

def on_release(key):
    print('{0} released'.format(
        key))
    if key == keyboard.Key.esc:
        # Stop listener
        return False

# Collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

Use this code for find the which key pressed

from pynput import keyboard

def on_press(key):
    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))

def on_release(key):
    print('{0} released'.format(
        key))
    if key == keyboard.Key.esc:
        # Stop listener
        return False

# Collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

回答 6

使用PyGame拥有一个窗口,然后您可以获取关键事件。

对于这封信p

import pygame, sys
import pygame.locals

pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)

windowSurface.fill(BLACK)

while True:
    for event in pygame.event.get():
        if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
             pass #Do what you want to here
        if event.type == pygame.locals.QUIT:
             pygame.quit()
             sys.exit()

Use PyGame to have a window and then you can get the key events.

For the letter p:

import pygame, sys
import pygame.locals

pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)

windowSurface.fill(BLACK)

while True:
    for event in pygame.event.get():
        if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
             pass #Do what you want to here
        if event.type == pygame.locals.QUIT:
             pygame.quit()
             sys.exit()

回答 7

所以我根据这篇文章(使用msvcr库和Python 3.7)制作了这款游戏。

以下是游戏的“主要功能”,即检测所按下的按键:

# Requiered libraries - - - -
import msvcrt
# - - - - - - - - - - - - - -


def _secret_key(self):
    # Get the key pressed by the user and check if he/she wins.

    bk = chr(10) + "-"*25 + chr(10)

    while True:

        print(bk + "Press any key(s)" + bk)
        #asks the user to type any key(s)

        kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
        # Store key's value.

        if r'\xe0' in kp:
            kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
            # Refactor the variable in case of multi press.

        if kp == r'\xe0\x8a':
            # If user pressed the secret key, the game ends.
            # \x8a is CTRL+F12, that's the secret key.

            print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
            print("Press any key to exit the game")
            msvcrt.getch()
            break
        else:
            print("    You pressed:'", kp + "', that's not the secret key(s)\n")
            if self.select_continue() == "n":
                if self.secondary_options():
                    self._main_menu()
                break

如果您想要该porgram的完整源代码,则可以在这里查看或下载它:

秘钥游戏(GitHub)

(注意:秘密按键为:Ctrl+ F12

我希望您可以作为一个例子,并为那些来此信息的人提供帮助。

So I made this ..kind of game.. based on this post (using msvcr library and Python 3.7).

The following is the “main function” of the game, that is detecting the keys pressed:

# Requiered libraries - - - -
import msvcrt
# - - - - - - - - - - - - - -


def _secret_key(self):
    # Get the key pressed by the user and check if he/she wins.

    bk = chr(10) + "-"*25 + chr(10)

    while True:

        print(bk + "Press any key(s)" + bk)
        #asks the user to type any key(s)

        kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
        # Store key's value.

        if r'\xe0' in kp:
            kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
            # Refactor the variable in case of multi press.

        if kp == r'\xe0\x8a':
            # If user pressed the secret key, the game ends.
            # \x8a is CTRL+F12, that's the secret key.

            print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
            print("Press any key to exit the game")
            msvcrt.getch()
            break
        else:
            print("    You pressed:'", kp + "', that's not the secret key(s)\n")
            if self.select_continue() == "n":
                if self.secondary_options():
                    self._main_menu()
                break

If you want the full source code of the porgram you can see it or download it from here:

The Secret Key Game (GitHub)

(note: the secret keypress is: Ctrl+F12)

I hope you can serve as an example and help for those who come to consult this information.


回答 8

我建议您使用PyGame并添加一个事件句柄。

http://www.pygame.org/docs/ref/event.html

I would suggest you use PyGame and add an event handle.

http://www.pygame.org/docs/ref/event.html


回答 9

key = cv2.waitKey(1)

这是来自openCV软件包。它无需等待即可检测到按键。

key = cv2.waitKey(1)

This is from the openCV package. It detects a keypress without waiting.


AttributeError:“模块”对象没有属性“测试”

问题:AttributeError:“模块”对象没有属性“测试”

我正在运行以下命令:

python manage.py test project.apps.app1.tests

并导致此错误:

AttributeError:“模块”对象没有属性“测试”

下面是我的目录结构。我还已将app1添加到已安装的应用程序配置中。

Traceback (most recent call last):
    File "manage.py", line 10, in <module> execute_from_command_line(sys.argv)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 50, in run_from_argv
    super(Command, self).run_from_argv(argv)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 71, in execute
    super(Command, self).execute(*args, **options)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 88, in handle
    failures = test_runner.run_tests(test_labels)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/test/runner.py", line 146, in run_tests
    suite = self.build_suite(test_labels, extra_tests)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/test/runner.py", line 66, in build_suite
    tests = self.test_loader.loadTestsFromName(label)
    File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
    parent, obj = obj, getattr(obj, part)
    AttributeError: 'module' object has no attribute 'tests'

目录结构:

I’m running this command:

python manage.py test project.apps.app1.tests

and it causes this error:

AttributeError: ‘module’ object has no attribute ‘tests’

Below is my directory structure. I’ve also added app1 to my installed apps config.

Traceback (most recent call last):
    File "manage.py", line 10, in <module> execute_from_command_line(sys.argv)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 50, in run_from_argv
    super(Command, self).run_from_argv(argv)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 71, in execute
    super(Command, self).execute(*args, **options)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 88, in handle
    failures = test_runner.run_tests(test_labels)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/test/runner.py", line 146, in run_tests
    suite = self.build_suite(test_labels, extra_tests)
    File "/home/username/local/dev/local/lib/python2.7/site-packages/django/test/runner.py", line 66, in build_suite
    tests = self.test_loader.loadTestsFromName(label)
    File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
    parent, obj = obj, getattr(obj, part)
    AttributeError: 'module' object has no attribute 'tests'

Directory structure:


回答 0

我终于想出了解决另一个问题的方法。问题是我的测试找不到导入。

如果您的测试无法导入,您似乎会收到上述错误。这是有道理的,因为测试套件无法导入损坏的测试。至少我认为这是正在发生的事情,因为我在测试文件中修复了导入,并确定导入已开始起作用。

要验证您的测试用例,只需尝试在python控制台中导入测试用例文件即可。

例:

from project.apps.app1.tests import *

I finally figured it out working on another problem. The problem was that my test couldn’t find an import.

It looks like you get the above error if your test fails to import. This makes sense because the test suite can’t import a broken test. At least I think this is what is going on because I fixed the import within my test file and sure enough it started working.

To validate your test case just try import the test case file in python console.

Example:

from project.apps.app1.tests import *

回答 1

用:

./manage.py shell

其次是

import myapp.tests

查找导入错误的性质。

Use:

./manage.py shell

followed by

import myapp.tests

to find the nature of the import error.


回答 2

就我而言,我需要在文件夹中创建一个空的__init__.pyapp/tests

For my case, I need to create an empty __init__.py in my app/tests folder


回答 3

上面的Steve Bradshaw的示例可解决导入错误(感谢Steve)。

其他类型的错误(例如ValueError)也可能导致

AttributeError: 'module' object has no attribute 'tests'

看看这些错误是什么

./manage.py shell
from myapp.tests import SomeTestCase
t = SomeTestCase()

Steve Bradshaw’s example above works for import errors (thanks Steve).

Other type of errors (e.g. ValueError) may also cause

AttributeError: 'module' object has no attribute 'tests'

to see what these errors are

./manage.py shell
from myapp.tests import SomeTestCase
t = SomeTestCase()

回答 4

我和克里斯有同样的错误。我删除了一个旧模型,然后运行tests.py,但是另一个文件(views.py)仍在尝试导入已删除的模型。

当我取出现在已经过时的import语句时,问题解决了。

I had the same error as Chris. I had deleted an old model, then run tests.py, but another file (views.py) was still trying to import the deleted model.

When I took out the now-obsolete import statement, problem solved.


回答 5

确保脚本中使用的所有模块均未损坏。我的意思是在您的导入语句中检查拼写。

# invalid import
from app.model.notification import Notification
# valid import
from app.models.notification import Notification

您可以通过在djano的交互式控制台中执行import语句来测试您的模块。

$root@13faefes8: python manage.py shell
Type "help", "copyright", "credits" or "license" for more information (InteractiveConsole)
>>> from app.model.notification import Notification
Traceback (most recent call last): 
   File "<console>", line 1, in <module>
ImportError: No module named model.notification

Make sure that all modules that you are using in your script are not broken. By this I mean check spelling in your import statements.

# invalid import
from app.model.notification import Notification
# valid import
from app.models.notification import Notification

You can test yours modules by executing imports statements in djano’s interactive console.

$root@13faefes8: python manage.py shell
Type "help", "copyright", "credits" or "license" for more information (InteractiveConsole)
>>> from app.model.notification import Notification
Traceback (most recent call last): 
   File "<console>", line 1, in <module>
ImportError: No module named model.notification

回答 6

我通过修复循环导入引用解决了错误“ AttributeError:模块’utils’没有属性’name_of_my_function’”。我的文件manage.py和utils.py每个都有一个指向彼此的import语句。

I resolved the error “AttributeError: module ‘utils’ has no attribute ‘name_of_my_function’ ” by fixing a circular import reference. My files manage.py and utils.py each had an import statement pointing at each other.


回答 7

根据django文档,当运行测试时,测试实用程序的默认行为是在名称以test开头的任何文件中查找所有测试用例(即unittest.TestCase的子类),自动从中构建测试套件。这些测试用例,然后运行该套件。

所以试试这个: python manage.py test tests.py

According to django document When you run your tests, the default behavior of the test utility is to find all the test cases (that is, subclasses of unittest.TestCase) in any file whose name begins with test, automatically build a test suite out of those test cases, and run that suite.

so try this : python manage.py test tests.py


回答 8

遇到相同的错误,但检查了所有原因列表,没有解决我的问题。

最后弄清楚,原因是导入但尚未使用的一种方法的名称不正确。尽管这是一个愚蠢的错误,但它确实发生了。

Got the same error, but checked all the reasons list here, did not fix my problem.

Finally figure it out that, the reason is that the name of one method that imported but not used yet is not correct. Though it is a stupid error, it happens.


回答 9

我有同样的错误。原来是因为我将我的模块命名为common.py,但是已经有一些其他common.py模块。我要做的就是重命名我的模块。

I had the same error. It turned out to be because I named my module common.py, yet there already was some other common.py module. All I had to do was to rename my module.


回答 10

编写unittest.TestCase时遇到类似的错误。当我按原样重新键入相同的方法定义时,它似乎起作用了!

我在PyCharm上注意到的唯一变化是第二次弹出“覆盖”图标,因为setup(self)方法需要覆盖TestCase中定义的原始方法。

I had a similar error while writing a unittest.TestCase. When I re-typed the same method definition as-is, it seemed to work !

The only change I noticed on PyCharm was the ‘override’ icon pop-up the 2nd time, as the setup(self) method needs to override the original method defined in TestCase.


在Python中使用换行符分隔字符串

问题:在Python中使用换行符分隔字符串

我需要定界包含新行的字符串。我将如何实现?请参考下面的代码。

输入:

data = """a,b,c
d,e,f
g,h,i
j,k,l"""

所需的输出:

['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

我尝试了以下方法:

1. output = data.split('\n')
2. output = data.split('/n')
3. output = data.rstrip().split('\n')

I need to delimit the string which has new line in it. How would I achieve it? Please refer below code.

Input:

data = """a,b,c
d,e,f
g,h,i
j,k,l"""

Output desired:

['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

I have tried the below approaches:

1. output = data.split('\n')
2. output = data.split('/n')
3. output = data.rstrip().split('\n')

回答 0

str.splitlines 方法应该为您提供确切的信息。

>>> data = """a,b,c
... d,e,f
... g,h,i
... j,k,l"""
>>> data.splitlines()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

str.splitlines method should give you exactly that.

>>> data = """a,b,c
... d,e,f
... g,h,i
... j,k,l"""
>>> data.splitlines()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

回答 1

data = """a,b,c
d,e,f
g,h,i
j,k,l"""

print(data.split())       # ['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

str.split,默认情况下,按所有空白字符分割。如果实际的字符串还有其他空格字符,则可能要使用

print(data.split("\n"))   # ['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

或者按照评论中的@Ashwini Chaudhary的建议,可以使用

print(data.splitlines())
data = """a,b,c
d,e,f
g,h,i
j,k,l"""

print(data.split())       # ['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

str.split, by default, splits by all the whitespace characters. If the actual string has any other whitespace characters, you might want to use

print(data.split("\n"))   # ['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

Or as @Ashwini Chaudhary suggested in the comments, you can use

print(data.splitlines())

回答 2

如果只想用换行符分割,最好使用splitlines()

例:

>>> data = """a,b,c
... d,e,f
... g,h,i
... j,k,l"""
>>> data
'a,b,c\nd,e,f\ng,h,i\nj,k,l'
>>> data.splitlines()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

使用split()它也可以:

>>> data = """a,b,c
... d,e,f
... g,h,i
... j,k,l"""
>>> data
'a,b,c\nd,e,f\ng,h,i\nj,k,l'
>>> data.split()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

然而:

>>> data = """
... a, eqw, qwe
... v, ewr, err
... """
>>> data
'\na, eqw, qwe\nv, ewr, err\n'
>>> data.split()
['a,', 'eqw,', 'qwe', 'v,', 'ewr,', 'err']

If you want to split only by newlines, you can use str.splitlines():

Example:

>>> data = """a,b,c
... d,e,f
... g,h,i
... j,k,l"""
>>> data
'a,b,c\nd,e,f\ng,h,i\nj,k,l'
>>> data.splitlines()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

With str.split() your case also works:

>>> data = """a,b,c
... d,e,f
... g,h,i
... j,k,l"""
>>> data
'a,b,c\nd,e,f\ng,h,i\nj,k,l'
>>> data.split()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

However if you have spaces (or tabs) it will fail:

>>> data = """
... a, eqw, qwe
... v, ewr, err
... """
>>> data
'\na, eqw, qwe\nv, ewr, err\n'
>>> data.split()
['a,', 'eqw,', 'qwe', 'v,', 'ewr,', 'err']

回答 3

有专门用于此目的的方法:

data.splitlines()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

There is a method specifically for this purpose:

data.splitlines()
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']

回答 4

干得好:

>>> data = """a,b,c
d,e,f
g,h,i
j,k,l"""
>>> data.split()  # split automatically splits through \n and space
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']
>>> 

Here you go:

>>> data = """a,b,c
d,e,f
g,h,i
j,k,l"""
>>> data.split()  # split automatically splits through \n and space
['a,b,c', 'd,e,f', 'g,h,i', 'j,k,l']
>>> 

ValueError:不支持的泡菜协议:3,python2泡菜无法加载python 3泡菜转储的文件?

问题:ValueError:不支持的泡菜协议:3,python2泡菜无法加载python 3泡菜转储的文件?

我使用pickle在python 3上转储文件,并使用pickle在python 2上加载文件,出现ValueError。

那么,python 2 pickle不能加载python 3 pickle丢弃的文件吗?

如果我想要吗?怎么做?

I use pickle to dump a file on python 3, and I use pickle to load the file on python 2, the ValueError appears.

So, python 2 pickle can not load the file dumped by python 3 pickle?

If I want it? How to do?


回答 0

您应该在Python 3中使用较低的协议编号来编写腌制的数据。Python3引入了一个带有该编号的新协议3(并将其用作默认协议),因此切换回2可以由Python 2读取的值。

检查中的protocol参数pickle.dump。您生成的代码将如下所示。

pickle.dump(your_object, your_file, protocol=2)

中没有protocol参数,pickle.load因为pickle可以从文件确定协议。

You should write the pickled data with a lower protocol number in Python 3. Python 3 introduced a new protocol with the number 3 (and uses it as default), so switch back to a value of 2 which can be read by Python 2.

Check the protocolparameter in pickle.dump. Your resulting code will look like this.

pickle.dump(your_object, your_file, protocol=2)

There is no protocolparameter in pickle.load because pickle can determine the protocol from the file.


回答 1

Pickle使用不同的protocols方法将您的数据转换为二进制流。

3为了能够在python 2中加载数据,您必须在python 3中指定一个低于的协议。可以protocol在调用时指定参数pickle.dump

Pickle uses different protocols to convert your data to a binary stream.

You must specify in python 3 a protocol lower than 3 in order to be able to load the data in python 2. You can specify the protocol parameter when invoking pickle.dump.


什么时候在Python中hash(n)== n?

问题:什么时候在Python中hash(n)== n?

我一直在玩Python的hash函数。对于小整数,它hash(n) == n总是出现。但是,这不会扩展为大量:

>>> hash(2**100) == 2**100
False

我并不感到惊讶,我知道哈希值取值范围有限。这个范围是多少?

我尝试使用二进制搜索来找到最小的数字hash(n) != n

>>> import codejamhelpers # pip install codejamhelpers
>>> help(codejamhelpers.binary_search)
Help on function binary_search in module codejamhelpers.binary_search:

binary_search(f, t)
    Given an increasing function :math:`f`, find the greatest non-negative integer :math:`n` such that :math:`f(n) \le t`. If :math:`f(n) > t` for all :math:`n \ge 0`, return None.

>>> f = lambda n: int(hash(n) != n)
>>> n = codejamhelpers.binary_search(f, 0)
>>> hash(n)
2305843009213693950
>>> hash(n+1)
0

2305843009213693951有什么特别之处?我注意到它小于sys.maxsize == 9223372036854775807

编辑:我正在使用Python3。我在Python 2上运行了相同的二进制搜索,得到了不同的结果2147483648,我注意到这是 sys.maxint+1

我也玩过[hash(random.random()) for i in range(10**6)]以估计哈希函数的范围。最大值始终低于上面的n。比较最小值,似乎Python 3的哈希值始终为正值,而Python 2的哈希值可以为负值。

I’ve been playing with Python’s hash function. For small integers, it appears hash(n) == n always. However this does not extend to large numbers:

>>> hash(2**100) == 2**100
False

I’m not surprised, I understand hash takes a finite range of values. What is that range?

I tried using binary search to find the smallest number hash(n) != n

>>> import codejamhelpers # pip install codejamhelpers
>>> help(codejamhelpers.binary_search)
Help on function binary_search in module codejamhelpers.binary_search:

binary_search(f, t)
    Given an increasing function :math:`f`, find the greatest non-negative integer :math:`n` such that :math:`f(n) \le t`. If :math:`f(n) > t` for all :math:`n \ge 0`, return None.

>>> f = lambda n: int(hash(n) != n)
>>> n = codejamhelpers.binary_search(f, 0)
>>> hash(n)
2305843009213693950
>>> hash(n+1)
0

What’s special about 2305843009213693951? I note it’s less than sys.maxsize == 9223372036854775807

Edit: I’m using Python 3. I ran the same binary search on Python 2 and got a different result 2147483648, which I note is sys.maxint+1

I also played with [hash(random.random()) for i in range(10**6)] to estimate the range of hash function. The max is consistently below n above. Comparing the min, it seems Python 3’s hash is always positively valued, whereas Python 2’s hash can take negative values.


回答 0

基于文件中的python文档pyhash.c

对于数字类型,数字x的哈希值是基于对x的减乘以模数质数得出的P = 2**_PyHASH_BITS - 1。它的设计使 hash(x) == hash(y)x和y在数值上相等时,即使x和y具有不同的类型。

因此,对于64/32位计算机,减少量将为2 _PyHASH_BITS -1,但是什么是_PyHASH_BITS

您可以在pyhash.h头文件中找到该文件,对于64位计算机,该头文件已定义为61(您可以在pyconfig.h文件中阅读更多说明)。

#if SIZEOF_VOID_P >= 8
#  define _PyHASH_BITS 61
#else
#  define _PyHASH_BITS 31
#endif

因此首先基于您的平台,例如在我的64位Linux平台上,减少幅度是2 61 -1,即2305843009213693951

>>> 2**61 - 1
2305843009213693951

也可以使用math.frexp来获取尾数和尾数sys.maxint,对于64位机器,该尾数和尾数表明max int为2 63

>>> import math
>>> math.frexp(sys.maxint)
(0.5, 64)

您可以通过一个简单的测试来查看差异:

>>> hash(2**62) == 2**62
True
>>> hash(2**63) == 2**63
False

阅读有关python哈希算法的完整文档https://github.com/python/cpython/blob/master/Python/pyhash.c#L34

如注释中所述,您可以使用sys.hash_info(在python 3.X中),这将为您提供用于计算哈希的参数的结构序列。

>>> sys.hash_info
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003, algorithm='siphash24', hash_bits=64, seed_bits=128, cutoff=0)
>>> 

除了我在前inf几行中描述的模数之外,您还可以获得以下值:

>>> hash(float('inf'))
314159
>>> sys.hash_info.inf
314159

Based on python documentation in pyhash.c file:

For numeric types, the hash of a number x is based on the reduction of x modulo the prime P = 2**_PyHASH_BITS - 1. It’s designed so that hash(x) == hash(y) whenever x and y are numerically equal, even if x and y have different types.

So for a 64/32 bit machine, the reduction would be 2 _PyHASH_BITS – 1, but what is _PyHASH_BITS?

You can find it in pyhash.h header file which for a 64 bit machine has been defined as 61 (you can read more explanation in pyconfig.h file).

#if SIZEOF_VOID_P >= 8
#  define _PyHASH_BITS 61
#else
#  define _PyHASH_BITS 31
#endif

So first off all it’s based on your platform for example in my 64bit Linux platform the reduction is 261-1, which is 2305843009213693951:

>>> 2**61 - 1
2305843009213693951

Also You can use math.frexp in order to get the mantissa and exponent of sys.maxint which for a 64 bit machine shows that max int is 263:

>>> import math
>>> math.frexp(sys.maxint)
(0.5, 64)

And you can see the difference by a simple test:

>>> hash(2**62) == 2**62
True
>>> hash(2**63) == 2**63
False

Read the complete documentation about python hashing algorithm https://github.com/python/cpython/blob/master/Python/pyhash.c#L34

As mentioned in comment you can use sys.hash_info (in python 3.X) which will give you a struct sequence of parameters used for computing hashes.

>>> sys.hash_info
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003, algorithm='siphash24', hash_bits=64, seed_bits=128, cutoff=0)
>>> 

Alongside the modulus that I’ve described in preceding lines, you can also get the inf value as following:

>>> hash(float('inf'))
314159
>>> sys.hash_info.inf
314159

回答 1

23058430092136939512^61 - 1。它是最大的Mersenne素数,适合64位。

如果您只需要将值mod取一个数字就可以进行哈希处理,那么大的Mersenne素数是一个不错的选择-它易于计算并且可以确保可能性的均匀分布。(尽管我个人永远不会这样散列)

计算浮点数的模数特别方便。它们具有将整数乘以的指数成分2^x。既然2^61 = 1 mod 2^61-1,您只需要考虑(exponent) mod 61

请参阅:https//en.wikipedia.org/wiki/Mersenne_prime

2305843009213693951 is 2^61 - 1. It’s the largest Mersenne prime that fits into 64 bits.

If you have to make a hash just by taking the value mod some number, then a large Mersenne prime is a good choice — it’s easy to compute and ensures an even distribution of possibilities. (Although I personally would never make a hash this way)

It’s especially convenient to compute the modulus for floating point numbers. They have an exponential component that multiplies the whole number by 2^x. Since 2^61 = 1 mod 2^61-1, you only need to consider the (exponent) mod 61.

See: https://en.wikipedia.org/wiki/Mersenne_prime


回答 2

哈希函数返回的是纯整数int,这意味着返回的值大于-sys.maxint和小于sys.maxint,这意味着如果传递sys.maxint + x给它,结果将为-sys.maxint + (x - 2)

hash(sys.maxint + 1) == sys.maxint + 1 # False
hash(sys.maxint + 1) == - sys.maxint -1 # True
hash(sys.maxint + sys.maxint) == -sys.maxint + sys.maxint - 2 # True

同时2**200n倍大于sys.maxint-我的猜测是,哈希将范围去了-sys.maxint..+sys.maxint,直到它停止在普通整数在这个范围内,如上面的代码段n次..

因此,通常,对于任何n <= sys.maxint

hash(sys.maxint*n) == -sys.maxint*(n%2) +  2*(n%2)*sys.maxint - n/2 - (n + 1)%2 ## True

注意:这适用于python 2。

Hash function returns plain int that means that returned value is greater than -sys.maxint and lower than sys.maxint, which means if you pass sys.maxint + x to it result would be -sys.maxint + (x - 2).

hash(sys.maxint + 1) == sys.maxint + 1 # False
hash(sys.maxint + 1) == - sys.maxint -1 # True
hash(sys.maxint + sys.maxint) == -sys.maxint + sys.maxint - 2 # True

Meanwhile 2**200 is a n times greater than sys.maxint – my guess is that hash would go over range -sys.maxint..+sys.maxint n times until it stops on plain integer in that range, like in code snippets above..

So generally, for any n <= sys.maxint:

hash(sys.maxint*n) == -sys.maxint*(n%2) +  2*(n%2)*sys.maxint - n/2 - (n + 1)%2 ## True

Note: this is true for python 2.


回答 3

可以在这里找到cpython中int类型实现。

它只返回值,除了-1,则返回-2

static long
int_hash(PyIntObject *v)
{
    /* XXX If this is changed, you also need to change the way
       Python's long, float and complex types are hashed. */
    long x = v -> ob_ival;
    if (x == -1)
        x = -2;
    return x;
}

The implementation for the int type in cpython can be found here.

It just returns the value, except for -1, than it returns -2:

static long
int_hash(PyIntObject *v)
{
    /* XXX If this is changed, you also need to change the way
       Python's long, float and complex types are hashed. */
    long x = v -> ob_ival;
    if (x == -1)
        x = -2;
    return x;
}