标签归档:class

获取类的属性

问题:获取类的属性

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

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.


在Python中调用基类的类方法

问题:在Python中调用基类的类方法

考虑以下代码:

class Base(object):

    @classmethod
    def do(cls, a):
        print cls, a

class Derived(Base):

    @classmethod
    def do(cls, a):
        print 'In derived!'
        # Base.do(cls, a) -- can't pass `cls`
        Base.do(a)

if __name__ == '__main__':
    d = Derived()
    d.do('hello')

> $ python play.py  
> In derived! 
> <class '__main__.Base'> msg

从哪里来Derived.do,我怎么打电话Base.do

super如果这是一个普通的对象方法,通常我会直接使用甚至直接使用基类名称,但是显然我找不到在基类中调用类方法的方法。

在上面的示例中,Base.do(a)打印Baseclass而不是Derivedclass。

Consider the following code:

class Base(object):

    @classmethod
    def do(cls, a):
        print cls, a

class Derived(Base):

    @classmethod
    def do(cls, a):
        print 'In derived!'
        # Base.do(cls, a) -- can't pass `cls`
        Base.do(a)

if __name__ == '__main__':
    d = Derived()
    d.do('hello')

> $ python play.py  
> In derived! 
> <class '__main__.Base'> msg

From Derived.do, how do I call Base.do?

I would normally use super or even the base class name directly if this is a normal object method, but apparently I can’t find a way to call the classmethod in the base class.

In the above example, Base.do(a) prints Base class instead of Derived class.


回答 0

如果您使用的是新样式的类(例如,是从objectPython 2 派生的,或者总是在Python 3中派生的),则可以这样操作super()

super(Derived, cls).do(a)

这是您如何在基类版本的方法(即print cls, a)中从派生类调用代码并将cls其设置为派生类的方式。

If you’re using a new-style class (i.e. derives from object in Python 2, or always in Python 3), you can do it with super() like this:

super(Derived, cls).do(a)

This is how you would invoke the code in the base class’s version of the method (i.e. print cls, a), from the derived class, with cls being set to the derived class.


回答 1

这已经有一段时间了,但是我想我可能已经找到了答案。当您装饰一个方法成为类方法时,原始的未绑定方法存储在名为“ im_func”的属性中:

class Base(object):
    @classmethod
    def do(cls, a):
        print cls, a

class Derived(Base):

    @classmethod
    def do(cls, a):
        print 'In derived!'
        # Base.do(cls, a) -- can't pass `cls`
        Base.do.im_func(cls, a)

if __name__ == '__main__':
    d = Derived()
    d.do('hello')

this has been a while, but I think I may have found an answer. When you decorate a method to become a classmethod the original unbound method is stored in a property named ‘im_func’:

class Base(object):
    @classmethod
    def do(cls, a):
        print cls, a

class Derived(Base):

    @classmethod
    def do(cls, a):
        print 'In derived!'
        # Base.do(cls, a) -- can't pass `cls`
        Base.do.im_func(cls, a)

if __name__ == '__main__':
    d = Derived()
    d.do('hello')

回答 2

这对我有用:

Base.do('hi')

This works for me:

Base.do('hi')

如何为带有测试的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/


获取当前类的名称?

问题:获取当前类的名称?

如何获得当前所在Class的名称?

例:

def get_input(class_name):
    [do things]
    return class_name_result

class foo():
    input = get_input([class name goes here])

由于我要与(vistrails)交互的程序的性质,我不能使用__init__()initialize input

How do I get the name of the class I am currently in?

Example:

def get_input(class_name):
    [do things]
    return class_name_result

class foo():
    input = get_input([class name goes here])

Due to the nature of the program I am interfacing with (vistrails), I cannot use __init__() to initialize input.


回答 0

obj.__class__.__name__ 将获得任何对象名称,因此您可以执行以下操作:

class Clazz():
    def getName(self):
        return self.__class__.__name__

用法:

>>> c = Clazz()
>>> c.getName()
'Clazz'

obj.__class__.__name__ will get you any objects name, so you can do this:

class Clazz():
    def getName(self):
        return self.__class__.__name__

Usage:

>>> c = Clazz()
>>> c.getName()
'Clazz'

回答 1

在类的主体内,类名尚未定义,因此不可用。您不能简单地输入类的名称吗?也许您需要更多地谈论该问题,以便我们为您找到解决方案。

我将创建一个元类来为您完成这项工作。它是在类创建时调用的(概念上是在类的最后:块),并且可以操纵正在创建的类。我还没有测试过:

class InputAssigningMetaclass(type):
    def __new__(cls, name, bases, attrs):
        cls.input = get_input(name)
        return super(MyType, cls).__new__(cls, name, bases, newattrs)

class MyBaseFoo(object):
    __metaclass__ = InputAssigningMetaclass

class foo(MyBaseFoo):
    # etc, no need to create 'input'

class foo2(MyBaseFoo):
    # etc, no need to create 'input'

Within the body of a class, the class name isn’t defined yet, so it is not available. Can you not simply type the name of the class? Maybe you need to say more about the problem so we can find a solution for you.

I would create a metaclass to do this work for you. It’s invoked at class creation time (conceptually at the very end of the class: block), and can manipulate the class being created. I haven’t tested this:

class InputAssigningMetaclass(type):
    def __new__(cls, name, bases, attrs):
        cls.input = get_input(name)
        return super(MyType, cls).__new__(cls, name, bases, newattrs)

class MyBaseFoo(object):
    __metaclass__ = InputAssigningMetaclass

class foo(MyBaseFoo):
    # etc, no need to create 'input'

class foo2(MyBaseFoo):
    # etc, no need to create 'input'

回答 2

您可以通过类的私有属性来访问它:

cls_name = self.__class__.__name__

编辑:

如所述Ned Batcheler,这在类主体中不起作用,但在方法中将起作用。

You can access it by the class’ private attributes:

cls_name = self.__class__.__name__

EDIT:

As said by Ned Batcheler, this wouldn’t work in the class body, but it would in a method.


回答 3

引入了PEP 3155__qualname__,它是在Python 3.3中实现的。

对于顶级函数和类,该__qualname__属性等于该__name__属性。对于嵌套类,方法和嵌套函数,该__qualname__属性包含一个虚线路径,该虚线路径从模块顶层通向该对象。

可从类或函数的定义中访问它,例如:

class Foo:
    print(__qualname__)

将有效打印Foo。您将获得全限定名称(不包括模块名称),因此您可能希望将其拆分到.字符。

但是,无法获得要定义的类的实际句柄。

>>> class Foo:
...     print('Foo' in globals())
... 
False

PEP 3155 introduced __qualname__, which was implemented in Python 3.3.

For top-level functions and classes, the __qualname__ attribute is equal to the __name__ attribute. For nested classes, methods, and nested functions, the __qualname__ attribute contains a dotted path leading to the object from the module top-level.

It is accessible from within the very definition of a class or a function, so for instance:

class Foo:
    print(__qualname__)

will effectively print Foo. You’ll get the fully qualified name (excluding the module’s name), so you might want to split it on the . character.

However, there is no way to get an actual handle on the class being defined.

>>> class Foo:
...     print('Foo' in globals())
... 
False

回答 4

编辑:是的,您可以;但您必须作弊:调用堆栈中存在当前正在运行的类名,并且该traceback模块允许您访问堆栈。

>>> import traceback
>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> class foo(object):
...      _name = traceback.extract_stack()[-1][2]
...     input = get_input(_name)
... 
>>> 
>>> foo.input
'sbb'

但是,我不会这样做。我最初的答案仍然是我自己的解决方案。原始答案:

可能最简单的解决方案是使用装饰器,该装饰器与Ned涉及元类的答案类似,但功能较弱(装饰器具有黑魔法的能力,但元类却具有古老的,神秘的黑魔法的能力)

>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> def inputize(cls):
...     cls.input = get_input(cls.__name__)
...     return cls
... 
>>> @inputize
... class foo(object):
...     pass
... 
>>> foo.input
'sbb'
>>> 

EDIT: Yes, you can; but you have to cheat: The currently running class name is present on the call stack, and the traceback module allows you to access the stack.

>>> import traceback
>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> class foo(object):
...      _name = traceback.extract_stack()[-1][2]
...     input = get_input(_name)
... 
>>> 
>>> foo.input
'sbb'

However, I wouldn’t do this; My original answer is still my own preference as a solution. Original answer:

probably the very simplest solution is to use a decorator, which is similar to Ned’s answer involving metaclasses, but less powerful (decorators are capable of black magic, but metaclasses are capable of ancient, occult black magic)

>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> def inputize(cls):
...     cls.input = get_input(cls.__name__)
...     return cls
... 
>>> @inputize
... class foo(object):
...     pass
... 
>>> foo.input
'sbb'
>>> 

回答 5

import sys

def class_meta(frame):
    class_context = '__module__' in frame.f_locals
    assert class_context, 'Frame is not a class context'

    module_name = frame.f_locals['__module__']
    class_name = frame.f_code.co_name
    return module_name, class_name

def print_class_path():
    print('%s.%s' % class_meta(sys._getframe(1)))

class MyClass(object):
    print_class_path()
import sys

def class_meta(frame):
    class_context = '__module__' in frame.f_locals
    assert class_context, 'Frame is not a class context'

    module_name = frame.f_locals['__module__']
    class_name = frame.f_code.co_name
    return module_name, class_name

def print_class_path():
    print('%s.%s' % class_meta(sys._getframe(1)))

class MyClass(object):
    print_class_path()

回答 6

我认为应该是这样的:

    class foo():
        input = get_input(__qualname__)

I think, it should be like this:

    class foo():
        input = get_input(__qualname__)

如何在Python中从__init__返回值?

问题:如何在Python中从__init__返回值?

我有一个带__init__功能的课。

创建对象时如何从该函数返回整数值?

我写了一个程序,在其中进行__init__命令行解析,我需要设置一些值。可以在全局变量中设置它并在其他成员函数中使用它吗?如果是这样,该怎么做?到目前为止,我在课外声明了一个变量。并将其设置为一个功能不会反映在其他功能中?

I have a class with an __init__ function.

How can I return an integer value from this function when an object is created?

I wrote a program, where __init__ does command line parsing and I need to have some value set. Is it OK set it in global variable and use it in other member functions? If so how to do that? So far, I declared a variable outside class. and setting it one function doesn’t reflect in other function ??


回答 0

__init__必须返回无。您不能(或至少不应该)返回其他东西。

尝试做任何您想返回的实例变量(或函数)。

>>> class Foo:
...     def __init__(self):
...         return 42
... 
>>> foo = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None

__init__ is required to return None. You cannot (or at least shouldn’t) return something else.

Try making whatever you want to return an instance variable (or function).

>>> class Foo:
...     def __init__(self):
...         return 42
... 
>>> foo = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None

回答 1

你为什么想这么做?

如果要在调用类时返回其他对象,请使用以下__new__()方法:

class MyClass(object):
    def __init__(self):
        print "never called in this case"
    def __new__(cls):
        return 42

obj = MyClass()
print obj

Why would you want to do that?

If you want to return some other object when a class is called, then use the __new__() method:

class MyClass(object):
    def __init__(self):
        print "never called in this case"
    def __new__(cls):
        return 42

obj = MyClass()
print obj

回答 2

从以下文档中__init__

作为对构造函数的特殊限制,不能返回任何值。这样做将导致在运行时引发TypeError。

作为证明,此代码:

class Foo(object):
    def __init__(self):
        return 2

f = Foo()

给出此错误:

Traceback (most recent call last):
  File "test_init.py", line 5, in <module>
    f = Foo()
TypeError: __init__() should return None, not 'int'

From the documentation of __init__:

As a special constraint on constructors, no value may be returned; doing so will cause a TypeError to be raised at runtime.

As a proof, this code:

class Foo(object):
    def __init__(self):
        return 2

f = Foo()

Gives this error:

Traceback (most recent call last):
  File "test_init.py", line 5, in <module>
    f = Foo()
TypeError: __init__() should return None, not 'int'

回答 3

有问题的示例用法如下:

class SampleObject(object):

    def __new__(cls, item):
        if cls.IsValid(item):
            return super(SampleObject, cls).__new__(cls)
        else:
            return None

    def __init__(self, item):
        self.InitData(item) #large amount of data and very complex calculations

...

ValidObjects = []
for i in data:
    item = SampleObject(i)
    if item:             # in case the i data is valid for the sample object
        ValidObjects.append(item)

我没有足够的声誉,所以我无法发表评论,这太疯狂了!我希望我可以将其发布为对weronika的评论

Sample Usage of the matter in question can be like:

class SampleObject(object):

    def __new__(cls, item):
        if cls.IsValid(item):
            return super(SampleObject, cls).__new__(cls)
        else:
            return None

    def __init__(self, item):
        self.InitData(item) #large amount of data and very complex calculations

...

ValidObjects = []
for i in data:
    item = SampleObject(i)
    if item:             # in case the i data is valid for the sample object
        ValidObjects.append(item)

I do not have enough reputation so I can not write a comment, it is crazy! I wish I could post it as a comment to weronika


回答 4

__init__与其他方法和函数一样,该方法默认情况下在没有return语句的情况下返回None,因此您可以像以下任何一种一样编写它:

class Foo:
    def __init__(self):
        self.value=42

class Bar:
    def __init__(self):
        self.value=42
        return None

但是,当然,添加return None并不会给您带来任何好处。

我不确定您要追求的是什么,但是您可能会对其中之一感兴趣:

class Foo:
    def __init__(self):
        self.value=42
    def __str__(self):
        return str(self.value)

f=Foo()
print f.value
print f

印刷品:

42
42

The __init__ method, like other methods and functions returns None by default in the absence of a return statement, so you can write it like either of these:

class Foo:
    def __init__(self):
        self.value=42

class Bar:
    def __init__(self):
        self.value=42
        return None

But, of course, adding the return None doesn’t buy you anything.

I’m not sure what you are after, but you might be interested in one of these:

class Foo:
    def __init__(self):
        self.value=42
    def __str__(self):
        return str(self.value)

f=Foo()
print f.value
print f

prints:

42
42

回答 5

__init__不返回任何东西,应该总是返回None

__init__ doesn’t return anything and should always return None.


回答 6

您可以将其设置为类变量,然后从主程序中读取它:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode

You can just set it to a class variable and read it from the main program:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode

回答 7

只需添加即可,您可以在 __init__

@property
def failureException(self):
    class MyCustomException(AssertionError):
        def __init__(self_, *args, **kwargs):
            *** Your code here ***
            return super().__init__(*args, **kwargs)

    MyCustomException.__name__ = AssertionError.__name__
    return MyCustomException

上面的方法可以帮助您对测试中的异常执行特定的操作

Just wanted to add, you can return classes in __init__

@property
def failureException(self):
    class MyCustomException(AssertionError):
        def __init__(self_, *args, **kwargs):
            *** Your code here ***
            return super().__init__(*args, **kwargs)

    MyCustomException.__name__ = AssertionError.__name__
    return MyCustomException

The above method helps you implement a specific action upon an Exception in your test


回答 8

init()返回无值,完美解决

class Solve:
def __init__(self,w,d):
    self.value=w
    self.unit=d
def __str__(self):
    return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)

输出:我的速度是21 kmh

init() return none value solved perfectly

class Solve:
def __init__(self,w,d):
    self.value=w
    self.unit=d
def __str__(self):
    return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)

output: my speed is 21 kmh


回答 9

好吧,如果您不再关心对象实例,则可以替换它!

class MuaHaHa():
def __init__(self, ret):
    self=ret

print MuaHaHa('foo')=='foo'

Well, if you don’t care about the object instance anymore … you can just replace it!

class MuaHaHa():
def __init__(self, ret):
    self=ret

print MuaHaHa('foo')=='foo'

如何实现__getattribute__而没有无限递归错误?

问题:如何实现__getattribute__而没有无限递归错误?

我想覆盖对类中一个变量的访问,但通常返回所有其他变量。我该怎么做__getattribute__呢?

我尝试了以下操作(它也应说明我要执行的操作),但是出现了递归错误:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

I want to override access to one variable in a class, but return all others normally. How do I accomplish this with __getattribute__?

I tried the following (which should also illustrate what I’m trying to do) but I get a recursion error:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

回答 0

您收到递归错误,因为您尝试访问其中的self.__dict__属性会再次__getattribute__调用您__getattribute__。如果你使用object__getattribute__不是,它的工作原理:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return object.__getattribute__(self, name)

之所以可行,是因为object(在此示例中)是基类。通过调用您的基本版本,__getattribute__可以避免您以前遇到的递归地狱。

IPython的输出与foo.py中的代码:

In [1]: from foo import *

In [2]: d = D()

In [3]: d.test
Out[3]: 0.0

In [4]: d.test2
Out[4]: 21

更新:

在当前文档中,标题为“ 针对新样式类的更多属性访问 ”的部分中有一些内容,他们建议完全这样做以避免无限递归。

You get a recursion error because your attempt to access the self.__dict__ attribute inside __getattribute__ invokes your __getattribute__ again. If you use object‘s __getattribute__ instead, it works:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return object.__getattribute__(self, name)

This works because object (in this example) is the base class. By calling the base version of __getattribute__ you avoid the recursive hell you were in before.

Ipython output with code in foo.py:

In [1]: from foo import *

In [2]: d = D()

In [3]: d.test
Out[3]: 0.0

In [4]: d.test2
Out[4]: 21

Update:

There’s something in the section titled More attribute access for new-style classes in the current documentation, where they recommend doing exactly this to avoid the infinite recursion.


回答 1

实际上,我相信您想改用__getattr__特殊方法。

引用Python文档:

__getattr__( self, name)

当在常规位置未找到属性时调用该属性(即,它不是实例属性,也不是在自身的类树中找到该属性)。name是属性名称。此方法应返回(计算出的)属性值或引发AttributeError异常。
请注意,如果通过常规机制找到该属性,__getattr__()则不会调用该属性。(这是__getattr__()和之间的故意不对称__setattr__()。)这样做是出于效率方面的考虑,并且因为否则__setattr__()将无法访问实例的其他属性。请注意,至少对于实例变量,您可以通过不在实例属性字典中插入任何值(而是将其插入另一个对象中)来伪造总体控制。见__getattribute__() 方法,以实际获得新样式类中的总控制权。

注:对于这项工作,该实例应该不会有一个test属性,因此行self.test=20应该被删除。

Actually, I believe you want to use the __getattr__ special method instead.

Quote from the Python docs:

__getattr__( self, name)

Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
Note that if the attribute is found through the normal mechanism, __getattr__() is not called. (This is an intentional asymmetry between __getattr__() and __setattr__().) This is done both for efficiency reasons and because otherwise __setattr__() would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the __getattribute__() method below for a way to actually get total control in new-style classes.

Note: for this to work, the instance should not have a test attribute, so the line self.test=20 should be removed.


回答 2

Python语言参考:

为了避免此方法的无限递归,其实现应始终调用具有相同名称的基类方法以访问其所需的任何属性,例如 object.__getattribute__(self, name)

含义:

def __getattribute__(self,name):
    ...
        return self.__dict__[name]

您正在调用名为的属性__dict__。由于它是一个属性,因此__getattribute__会在搜索__dict__中调用__getattribute__哪个调用而被调用… yada yada yada

return  object.__getattribute__(self, name)

使用基类__getattribute__有助于查找真实属性。

Python language reference:

In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__getattribute__(self, name).

Meaning:

def __getattribute__(self,name):
    ...
        return self.__dict__[name]

You’re calling for an attribute called __dict__. Because it’s an attribute, __getattribute__ gets called in search for __dict__ which calls __getattribute__ which calls … yada yada yada

return  object.__getattribute__(self, name)

Using the base classes __getattribute__ helps finding the real attribute.


回答 3

确定要使用__getattribute__吗?您实际上想实现什么?

最简单的方法是:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    test = 0

要么:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    @property
    def test(self):
        return 0

编辑:请注意,的实例在每种情况下D将具有不同的值test。在第一种情况下d.test为20,在第二种情况下为0。我将由您自己确定原因。

Edit2:Greg指出示例2将失败,因为该属性是只读属性,并且该__init__方法尝试将其设置为20。对此的更完整示例为:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    _test = 0

    def get_test(self):
        return self._test

    def set_test(self, value):
        self._test = value

    test = property(get_test, set_test)

显然,作为一门课,这几乎是毫无用处的,但它为您提供了继续学习的想法。

Are you sure you want to use __getattribute__? What are you actually trying to achieve?

The easiest way to do what you ask is:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    test = 0

or:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    @property
    def test(self):
        return 0

Edit: Note that an instance of D would have different values of test in each case. In the first case d.test would be 20, in the second it would be 0. I’ll leave it to you to work out why.

Edit2: Greg pointed out that example 2 will fail because the property is read only and the __init__ method tried to set it to 20. A more complete example for that would be:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    _test = 0

    def get_test(self):
        return self._test

    def set_test(self, value):
        self._test = value

    test = property(get_test, set_test)

Obviously, as a class this is almost entirely useless, but it gives you an idea to move on from.


回答 4

这是一个更可靠的版本:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21
    def __getattribute__(self, name):
        if name == 'test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

它从父类调用__ getattribute __方法,最终退回到对象。__ getattribute __方法,如果其他祖先没有覆盖它。

Here is a more reliable version:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21
    def __getattribute__(self, name):
        if name == 'test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

It calls __getattribute__ method from parent class, eventually falling back to object.__getattribute__ method if other ancestors don’t override it.


回答 5

如何__getattribute__使用该方法?

在普通的点分查找之前调用它。如果涨了AttributeError,我们打电话__getattr__

这种方法很少使用。标准库中只有两个定义:

$ grep -Erl  "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py

最佳实践

以编程方式控制对单个属性的访问的正确方法是使用property。类的D编写应如下所示(可以使用setter和Deleter来复制明显的预期行为):

class D(object):
    def __init__(self):
        self.test2=21

    @property
    def test(self):
        return 0.

    @test.setter
    def test(self, value):
        '''dummy function to avoid AttributeError on setting property'''

    @test.deleter
    def test(self):
        '''dummy function to avoid AttributeError on deleting property'''

和用法:

>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0

属性是数据描述符,因此它是常规点分查找算法中要查找的第一件事。

的选项 __getattribute__

如果您绝对需要通过来为每个属性实现查找,则有几种选择__getattribute__

  • 提高AttributeError,导致__getattr__被调用(如果已实现)
  • 从中退还东西
    • 通过super调用父类的(可能object的)执行
    • 呼唤 __getattr__
    • 以某种方式实现您自己的虚线查找算法

例如:

class NoisyAttributes(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self, name):
        print('getting: ' + name)
        try:
            return super(NoisyAttributes, self).__getattribute__(name)
        except AttributeError:
            print('oh no, AttributeError caught and reraising')
            raise
    def __getattr__(self, name):
        """Called if __getattribute__ raises AttributeError"""
        return 'close but no ' + name    


>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20

您最初想要的。

此示例说明了如何执行您最初想要的操作:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

并且会像这样:

>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test

Traceback (most recent call last):
  File "<pyshell#216>", line 1, in <module>
    del o.test
AttributeError: test

代码审查

您的代码带注释。您在中对自己进行了点查询__getattribute__。这就是为什么您会得到递归错误的原因。您可以检查名称是否可用,"__dict__"并使用它super来解决,但这并不覆盖__slots__。我将其留给读者练习。

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:      #   v--- Dotted lookup on self in __getattribute__
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

How is the __getattribute__ method used?

It is called before the normal dotted lookup. If it raises AttributeError, then we call __getattr__.

Use of this method is rather rare. There are only two definitions in the standard library:

$ grep -Erl  "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py

Best Practice

The proper way to programmatically control access to a single attribute is with property. Class D should be written as follows (with the setter and deleter optionally to replicate apparent intended behavior):

class D(object):
    def __init__(self):
        self.test2=21

    @property
    def test(self):
        return 0.

    @test.setter
    def test(self, value):
        '''dummy function to avoid AttributeError on setting property'''

    @test.deleter
    def test(self):
        '''dummy function to avoid AttributeError on deleting property'''

And usage:

>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0

A property is a data descriptor, thus it is the first thing looked for in the normal dotted lookup algorithm.

Options for __getattribute__

You several options if you absolutely need to implement lookup for every attribute via __getattribute__.

  • raise AttributeError, causing __getattr__ to be called (if implemented)
  • return something from it by
    • using super to call the parent (probably object‘s) implementation
    • calling __getattr__
    • implementing your own dotted lookup algorithm somehow

For example:

class NoisyAttributes(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self, name):
        print('getting: ' + name)
        try:
            return super(NoisyAttributes, self).__getattribute__(name)
        except AttributeError:
            print('oh no, AttributeError caught and reraising')
            raise
    def __getattr__(self, name):
        """Called if __getattribute__ raises AttributeError"""
        return 'close but no ' + name    


>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20

What you originally wanted.

And this example shows how you might do what you originally wanted:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

And will behave like this:

>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test

Traceback (most recent call last):
  File "<pyshell#216>", line 1, in <module>
    del o.test
AttributeError: test

Code review

Your code with comments. You have a dotted lookup on self in __getattribute__. This is why you get a recursion error. You could check if name is "__dict__" and use super to workaround, but that doesn’t cover __slots__. I’ll leave that as an exercise to the reader.

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:      #   v--- Dotted lookup on self in __getattribute__
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

我应该使用类还是字典?

问题:我应该使用类还是字典?

我有一个只包含字段而没有方法的类,如下所示:

class Request(object):

    def __init__(self, environ):
        self.environ = environ
        self.request_method = environ.get('REQUEST_METHOD', None)
        self.url_scheme = environ.get('wsgi.url_scheme', None)
        self.request_uri = wsgiref.util.request_uri(environ)
        self.path = environ.get('PATH_INFO', None)
        # ...

这可以很容易地翻译成字典。该类对于将来的添加更加灵活,使用可以更快__slots__。那么使用dict会有好处吗?字典会比全班更快吗?并且比具有插槽的类快吗?

I have a class that contains only fields and no methods, like this:

class Request(object):

    def __init__(self, environ):
        self.environ = environ
        self.request_method = environ.get('REQUEST_METHOD', None)
        self.url_scheme = environ.get('wsgi.url_scheme', None)
        self.request_uri = wsgiref.util.request_uri(environ)
        self.path = environ.get('PATH_INFO', None)
        # ...

This could easily be translated to a dict. The class is more flexible for future additions and could be fast with __slots__. So would there be a benefit of using a dict instead? Would a dict be faster than a class? And faster than a class with slots?


回答 0

你为什么要把它当作字典?有什么好处?如果您以后想要添加一些代码,会发生什么?您的__init__代码会去哪儿?

类用于捆绑相关数据(通常是代码)。

字典用于存储键-值关系,其中通常键都是同一类型,并且所有值也都是一种类型。有时,当键/属性名称并非一开始就为人所知时,它们对于捆绑数据很有用,但这通常表明您的设计有问题。

保持这堂课。

Why would you make this a dictionary? What’s the advantage? What happens if you later want to add some code? Where would your __init__ code go?

Classes are for bundling related data (and usually code).

Dictionaries are for storing key-value relationships, where usually the keys are all of the same type, and all the values are also of one type. Occasionally they can be useful for bundling data when the key/attribute names are not all known up front, but often this a sign that something’s wrong with your design.

Keep this a class.


回答 1

使用字典,除非您需要类的额外机制。您还可以将a namedtuple用作混合方法:

>>> from collections import namedtuple
>>> request = namedtuple("Request", "environ request_method url_scheme")
>>> request
<class '__main__.Request'>
>>> request.environ = "foo"
>>> request.environ
'foo'

这里的性能差异将是最小的,尽管如果字典速度不快,我会感到惊讶。

Use a dictionary unless you need the extra mechanism of a class. You could also use a namedtuple for a hybrid approach:

>>> from collections import namedtuple
>>> request = namedtuple("Request", "environ request_method url_scheme")
>>> request
<class '__main__.Request'>
>>> request.environ = "foo"
>>> request.environ
'foo'

Performance differences here will be minimal, although I would be surprised if the dictionary wasn’t faster.


回答 2

python 的类下面的字典。类的行为确实会增加一些开销,但是如果没有事件探查器,您将无法注意到它。在这种情况下,我相信您会从课堂中受益,因为:

  • 您所有的逻辑都存在于一个功能中
  • 易于更新并保持封装
  • 如果以后更改任何内容,则可以轻松地使界面保持不变

A class in python is a dict underneath. You do get some overhead with the class behavior, but you won’t be able to notice it without a profiler. In this case, I believe you benefit from the class because:

  • All your logic lives in a single function
  • It is easy to update and stays encapsulated
  • If you change anything later, you can easily keep the interface the same

回答 3

我认为每个人的用法都太主观,我无法理解,所以我只会坚持数字。

我比较了在dict,new_style类和带槽的new_style类中创建和更改变量所需的时间。

这是我用来测试的代码(虽然有点杂乱,但确实可以完成工作。)

import timeit

class Foo(object):

    def __init__(self):

        self.foo1 = 'test'
        self.foo2 = 'test'
        self.foo3 = 'test'

def create_dict():

    foo_dict = {}
    foo_dict['foo1'] = 'test'
    foo_dict['foo2'] = 'test'
    foo_dict['foo3'] = 'test'

    return foo_dict

class Bar(object):
    __slots__ = ['foo1', 'foo2', 'foo3']

    def __init__(self):

        self.foo1 = 'test'
        self.foo2 = 'test'
        self.foo3 = 'test'

tmit = timeit.timeit

print 'Creating...\n'
print 'Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict'))
print 'Class: ' + str(tmit('Foo()', 'from __main__ import Foo'))
print 'Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar'))

print '\nChanging a variable...\n'

print 'Dict: ' + str((tmit('create_dict()[\'foo3\'] = "Changed"', 'from __main__ import create_dict') - tmit('create_dict()', 'from __main__ import create_dict')))
print 'Class: ' + str((tmit('Foo().foo3 = "Changed"', 'from __main__ import Foo') - tmit('Foo()', 'from __main__ import Foo')))
print 'Class with slots: ' + str((tmit('Bar().foo3 = "Changed"', 'from __main__ import Bar') - tmit('Bar()', 'from __main__ import Bar')))

这是输出…

正在建立…

Dict: 0.817466186345
Class: 1.60829183597
Class_with_slots: 1.28776730003

更改变量…

Dict: 0.0735140918748
Class: 0.111714198313
Class_with_slots: 0.10618612142

因此,如果您只是存储变量,则需要速度,并且不需要进行很多计算,因此我建议使用dict(您始终可以使函数看起来像方法)。但是,如果您确实需要类,请记住-始终使用__ slot __

注意:

我测试的“类”有两种 new_style和old_style类。事实证明,old_style类的创建速度更快,但修改速度却较慢(如果要在紧密的循环中创建许多类,则幅度不大,但意义重大(提示:您做错了))。

此外,由于我的计算机较旧且运行缓慢,因此在计算机上创建和更改变量的时间可能会有所不同。确保自己进行测试以查看“真实”结果。

编辑:

后来我测试了namedtuple:我无法修改它,但是创建10000个样本(或类似的东西)花了1.4秒,因此字典确实是最快的。

如果我更改dict函数以包括键和值,并在创建它时返回dict而不是包含dict的变量,则它会给我0.65而不是0.8秒。

class Foo(dict):
    pass

创建就像是一个带有插槽的类,并且更改变量最慢(0.17秒),因此不要使用这些类。求字典(速度)或对象派生的类(“语法糖果”)

I think that the usage of each one is way too subjective for me to get in on that, so i’ll just stick to numbers.

I compared the time it takes to create and to change a variable in a dict, a new_style class and a new_style class with slots.

Here’s the code i used to test it(it’s a bit messy but it does the job.)

import timeit

class Foo(object):

    def __init__(self):

        self.foo1 = 'test'
        self.foo2 = 'test'
        self.foo3 = 'test'

def create_dict():

    foo_dict = {}
    foo_dict['foo1'] = 'test'
    foo_dict['foo2'] = 'test'
    foo_dict['foo3'] = 'test'

    return foo_dict

class Bar(object):
    __slots__ = ['foo1', 'foo2', 'foo3']

    def __init__(self):

        self.foo1 = 'test'
        self.foo2 = 'test'
        self.foo3 = 'test'

tmit = timeit.timeit

print 'Creating...\n'
print 'Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict'))
print 'Class: ' + str(tmit('Foo()', 'from __main__ import Foo'))
print 'Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar'))

print '\nChanging a variable...\n'

print 'Dict: ' + str((tmit('create_dict()[\'foo3\'] = "Changed"', 'from __main__ import create_dict') - tmit('create_dict()', 'from __main__ import create_dict')))
print 'Class: ' + str((tmit('Foo().foo3 = "Changed"', 'from __main__ import Foo') - tmit('Foo()', 'from __main__ import Foo')))
print 'Class with slots: ' + str((tmit('Bar().foo3 = "Changed"', 'from __main__ import Bar') - tmit('Bar()', 'from __main__ import Bar')))

And here is the output…

Creating…

Dict: 0.817466186345
Class: 1.60829183597
Class_with_slots: 1.28776730003

Changing a variable…

Dict: 0.0735140918748
Class: 0.111714198313
Class_with_slots: 0.10618612142

So, if you’re just storing variables, you need speed, and it won’t require you to do many calculations, i recommend using a dict(you could always just make a function that looks like a method). But, if you really need classes, remember – always use __slots__.

Note:

I tested the ‘Class’ with both new_style and old_style classes. It turns out that old_style classes are faster to create but slower to modify(not by much but significant if you’re creating lots of classes in a tight loop (tip: you’re doing it wrong)).

Also the times for creating and changing variables may differ on your computer since mine is old and slow. Make sure you test it yourself to see the ‘real’ results.

Edit:

I later tested the namedtuple: i can’t modify it but to create the 10000 samples (or something like that) it took 1.4 seconds so the dictionary is indeed the fastest.

If i change the dict function to include the keys and values and to return the dict instead of the variable containing the dict when i create it it gives me 0.65 instead of 0.8 seconds.

class Foo(dict):
    pass

Creating is like a class with slots and changing the variable is the slowest (0.17 seconds) so do not use these classes. go for a dict (speed) or for the class derived from object (‘syntax candy’)


回答 4

我同意@adw。我永远不会用字典来代表“对象”(从OO意义上来说)。词典汇总名称/值对。类代表对象。我已经看到了用字典表示对象的代码,目前尚不清楚事物的实际形状是什么。当某些名称/值不存在时会发生什么?是什么限制了客户什么也没花。或者试图把所有东西都花掉。事物的形状应始终明确定义。

使用Python时,重要的是要有纪律性进行构建,因为该语言为作者提供了多种射击方式。

I agree with @adw. I would never represent an “object” (in an OO sense) with a dictionary. Dictionaries aggregate name/value pairs. Classes represent objects. I’ve seen code where the objects are represented with dictionaries and it’s unclear what the actual shape of the thing is. What happens when certain name/values aren’t there? What restricts the client from putting anything at all in. Or trying to get anything at all out. The shape of the thing should always be clearly defined.

When using Python it is important to build with discipline as the language allows many ways for the author to shoot him/herself in the foot.


回答 5

我会推荐一个类,因为它是与请求有关的各种信息。曾经是使用字典的人,我希望存储的数据本质上会更加相似。我倾向于遵循的一个指导原则是,如果我想遍历整个键-值对集合并执行某些操作,则可以使用字典。否则,数据显然比基本的键->值映射具有更多的结构,这意味着类可能是更好的选择。

因此,坚持上课。

I would recommend a class, as it is all sorts of information involved with a request. Were one to use a dictionary, I’d expect the data stored to be far more similar in nature. A guideline I tend to follow myself is that if I may want to loop over the entire set of key->value pairs and do something, I use a dictionary. Otherwise, the data apparently has far more structure than a basic key->value mapping, meaning a class would likely be a better alternative.

Hence, stick with the class.


回答 6

如果您要实现的只是语法糖果obj.bla = 5而不是obj['bla'] = 5,特别是如果您必须重复很多,那么您可能想要使用一些简单的容器类,如martineaus建议中那样。但是,那里的代码非常肿,并且速度很慢。您可以像这样简单:

class AttrDict(dict):
    """ Syntax candy """
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

切换到namedtuples或class的另一个原因__slots__可能是内存使用率。字典比列表类型需要更多的内存,因此可能需要考虑一下。

无论如何,在您的特定情况下,似乎没有任何动力要退出当前的实现。您似乎没有维护数百万个此类对象,因此不需要列表派生类型。而且它实际上包含内的一些功能逻辑__init__,因此您也不应该使用AttrDict

If all that you want to achive is syntax candy like obj.bla = 5 instead of obj['bla'] = 5, especially if you have to repeat that a lot, you maybe want to use some plain container class as in martineaus suggestion. Nevertheless, the code there is quite bloated and unnecessarily slow. You can keep it simple like that:

class AttrDict(dict):
    """ Syntax candy """
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

Another reason to switch to namedtuples or a class with __slots__ could be memory usage. Dicts require significantly more memory than list types, so this could be a point to think about.

Anyways, in your specific case, there doesn’t seem to be any motivation to switch away from your current implementation. You don’t seem to maintain millions of these objects, so no list-derived-types required. And it’s actually containing some functional logic within the __init__, so you also shouldn’t got with AttrDict.


回答 7

也可能有蛋糕也可以吃。换句话说,您可以创建提供类和字典实例功能的东西。请参阅ActiveState的Dɪᴄᴛɪᴏɴᴀʀʏᴡɪᴛʜᴀᴛᴛʀɪʙᴜᴛᴇ-sᴛʏʟᴇss食谱和有关此方法的注释。

如果您决定使用常规类而不是子类,那么我发现T recipesɪᴍᴘʟᴇᴄᴏʟʟᴇᴄᴛᴏʀᴄᴏʟʟᴇᴄᴛᴏʀᴄᴏʟʟᴇᴄᴛᴏʀrecipe recipe ss的食谱(由Alex Martelli 撰写非常灵活,对此类事情很有用看起来就像您在做的(即创建一个相对简单的信息聚合器)。由于它是一个类,因此您可以通过添加方法轻松地进一步扩展其功能。

最后,应该指出,类成员的名称必须是合法的Python标识符,但字典键则不能—因此字典在这方面将提供更大的自由度,因为键可以是任何可散列的东西(甚至可以不是字符串)。

更新资料

一类object(其不具有__dict__)指定的子类SimpleNamespace(它有一个)加入到该types模块的Python 3.3,并且是又一替代。

It may be possible to have your cake and eat it, too. In other words you can create something that provides the functionality of both a class and dictionary instance. See the ActiveState’s Dɪᴄᴛɪᴏɴᴀʀʏ ᴡɪᴛʜ ᴀᴛᴛʀɪʙᴜᴛᴇ-sᴛʏʟᴇ ᴀᴄᴄᴇss recipe and comments on ways of doing that.

If you decide to use a regular class rather than a subclass, I’ve found the Tʜᴇ sɪᴍᴘʟᴇ ʙᴜᴛ ʜᴀɴᴅʏ “ᴄᴏʟʟᴇᴄᴛᴏʀ ᴏғ ᴀ ʙᴜɴᴄʜ ᴏғ ɴᴀᴍᴇᴅ sᴛᴜғғ” ᴄʟᴀss recipe (by Alex Martelli) to be very flexible and useful for the sort of thing it looks like you’re doing (i.e. create a relative simple aggregator of information). Since it’s a class you can easily extend its functionality further by adding methods.

Lastly it should be noted that the names of class members must be legal Python identifiers, but dictionary keys do not—so a dictionary would provide greater freedom in that regard because keys can be anything hashable (even something that’s not a string).

Update

A class object (which doesn’t have a __dict__) subclass named SimpleNamespace (which does have one) was added to the types module Python 3.3, and is yet another alternative.


回答 8

class ClassWithSlotBase:
    __slots__ = ('a', 'b',)

def __init__(self):
    self.a: str = "test"
    self.b: float = 0.0


def test_type_hint(_b: float) -> None:
    print(_b)


class_tmp = ClassWithSlotBase()

test_type_hint(class_tmp.a)

我推荐一堂课。如果使用类,则可以得到如下所示的类型提示。当class是函数的参数时,Class支持自动完成。

在此处输入图片说明

class ClassWithSlotBase:
    __slots__ = ('a', 'b',)

def __init__(self):
    self.a: str = "test"
    self.b: float = 0.0


def test_type_hint(_b: float) -> None:
    print(_b)


class_tmp = ClassWithSlotBase()

test_type_hint(class_tmp.a)

I recommend a class. If you use a class, you can get type hint as shown. And Class support auto complete when class is argument of function.

enter image description here


python内部类的目的是什么?

问题:python内部类的目的是什么?

Python的内部/嵌套类使我感到困惑。没有他们,有什么事情是无法完成的吗?如果是这样,那是什么东西?

Python’s inner/nested classes confuse me. Is there something that can’t be accomplished without them? If so, what is that thing?


回答 0

引用自http://www.geekinterview.com/question_details/64739

内部阶层的优势:

  • 类的逻辑分组:如果一个类仅对另一个类有用,那么将其嵌入该类并将二者保持在一起是合乎逻辑的。嵌套此类“帮助程序类”可使它们的程序包更加简化。
  • 增加封装:考虑两个顶级类A和B,其中B需要访问A的成员,否则将其声明为私有。通过将B类隐藏在AA类中,可以将其成员声明为私有,B可以访问它们。另外,B本身可以对外界隐藏。
  • 更具可读性和可维护性的代码:在顶级类中嵌套小类会使代码更靠近使用位置。

主要优势是组织。可以用内部类实现什么没有他们来完成。

Quoted from http://www.geekinterview.com/question_details/64739:

Advantages of inner class:

  • Logical grouping of classes: If a class is useful to only one other class then it is logical to embed it in that class and keep the two together. Nesting such “helper classes” makes their package more streamlined.
  • Increased encapsulation: Consider two top-level classes A and B where B needs access to members of A that would otherwise be declared private. By hiding class B within class A A’s members can be declared private and B can access them. In addition B itself can be hidden from the outside world.
  • More readable, maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.

The main advantage is organization. Anything that can be accomplished with inner classes can be accomplished without them.


回答 1

没有他们,有什么事情是无法完成的吗?

不。它们绝对等同于通常在顶层定义类,然后将对它的引用复制到外部类中。

我认为“允许”嵌套类没有任何特殊原因,除了明确禁止“禁止”嵌套类没有特殊意义。

如果您正在寻找一个在外部/所有者对象的生命周期内存在的类,并且始终引用外部类的实例(内部类就像Java一样),那么Python的嵌套类就不是问题。但是您可以破解类似的东西:

import weakref, new

class innerclass(object):
    """Descriptor for making inner classes.

    Adds a property 'owner' to the inner class, pointing to the outer
    owner instance.
    """

    # Use a weakref dict to memoise previous results so that
    # instance.Inner() always returns the same inner classobj.
    #
    def __init__(self, inner):
        self.inner= inner
        self.instances= weakref.WeakKeyDictionary()

    # Not thread-safe - consider adding a lock.
    #
    def __get__(self, instance, _):
        if instance is None:
            return self.inner
        if instance not in self.instances:
            self.instances[instance]= new.classobj(
                self.inner.__name__, (self.inner,), {'owner': instance}
            )
        return self.instances[instance]


# Using an inner class
#
class Outer(object):
    @innerclass
    class Inner(object):
        def __repr__(self):
            return '<%s.%s inner object of %r>' % (
                self.owner.__class__.__name__,
                self.__class__.__name__,
                self.owner
            )

>>> o1= Outer()
>>> o2= Outer()
>>> i1= o1.Inner()
>>> i1
<Outer.Inner inner object of <__main__.Outer object at 0x7fb2cd62de90>>
>>> isinstance(i1, Outer.Inner)
True
>>> isinstance(i1, o1.Inner)
True
>>> isinstance(i1, o2.Inner)
False

(这使用了类装饰器,这是Python 2.6和3.0中的新功能。否则,您必须在类定义之后说“ Inner = innerclass(Inner)”。)

Is there something that can’t be accomplished without them?

No. They are absolutely equivalent to defining the class normally at top level, and then copying a reference to it into the outer class.

I don’t think there’s any special reason nested classes are ‘allowed’, other than it makes no particular sense to explicitly ‘disallow’ them either.

If you’re looking for a class that exists within the lifecycle of the outer/owner object, and always has a reference to an instance of the outer class — inner classes as Java does it – then Python’s nested classes are not that thing. But you can hack up something like that thing:

import weakref, new

class innerclass(object):
    """Descriptor for making inner classes.

    Adds a property 'owner' to the inner class, pointing to the outer
    owner instance.
    """

    # Use a weakref dict to memoise previous results so that
    # instance.Inner() always returns the same inner classobj.
    #
    def __init__(self, inner):
        self.inner= inner
        self.instances= weakref.WeakKeyDictionary()

    # Not thread-safe - consider adding a lock.
    #
    def __get__(self, instance, _):
        if instance is None:
            return self.inner
        if instance not in self.instances:
            self.instances[instance]= new.classobj(
                self.inner.__name__, (self.inner,), {'owner': instance}
            )
        return self.instances[instance]


# Using an inner class
#
class Outer(object):
    @innerclass
    class Inner(object):
        def __repr__(self):
            return '<%s.%s inner object of %r>' % (
                self.owner.__class__.__name__,
                self.__class__.__name__,
                self.owner
            )

>>> o1= Outer()
>>> o2= Outer()
>>> i1= o1.Inner()
>>> i1
<Outer.Inner inner object of <__main__.Outer object at 0x7fb2cd62de90>>
>>> isinstance(i1, Outer.Inner)
True
>>> isinstance(i1, o1.Inner)
True
>>> isinstance(i1, o2.Inner)
False

(This uses class decorators, which are new in Python 2.6 and 3.0. Otherwise you’d have to say “Inner= innerclass(Inner)” after the class definition.)


回答 2

您需要包裹一些东西才能理解这一点。在大多数语言中,类定义是对编译器的指令。也就是说,该类是在程序运行之前创建的。在python中,所有语句都是可执行的。这意味着该语句:

class foo(object):
    pass

是一条在运行时执行的语句,如下所示:

x = y + z

这意味着您不仅可以在其他类中创建类,还可以在任意位置创建类。考虑以下代码:

def foo():
    class bar(object):
        ...
    z = bar()

因此,“内部类”的想法实际上不是一种语言构造;这是一个程序员构造。圭多拥有这是怎么围绕很好的总结在这里。但本质上,基本思想是简化了语言的语法。

There’s something you need to wrap your head around to be able to understand this. In most languages, class definitions are directives to the compiler. That is, the class is created before the program is ever run. In python, all statements are executable. That means that this statement:

class foo(object):
    pass

is a statement that is executed at runtime just like this one:

x = y + z

This means that not only can you create classes within other classes, you can create classes anywhere you want to. Consider this code:

def foo():
    class bar(object):
        ...
    z = bar()

Thus, the idea of an “inner class” isn’t really a language construct; it’s a programmer construct. Guido has a very good summary of how this came about here. But essentially, the basic idea is this simplifies the language’s grammar.


回答 3

在类中嵌套类:

  • 嵌套类使类定义变得肿,这使得很难看到发生了什么。

  • 嵌套类会创建耦合,从而使测试更加困难。

  • 在Python中,您可以在文件/模块中放置一个以上的类,这与Java不同,因此该类仍保持与顶级类的距离,甚至可以在类名前加上“ _”,以帮助表示不应将其他类使用它。

嵌套类可以证明有用的地方是函数内

def some_func(a, b, c):
   class SomeClass(a):
      def some_method(self):
         return b
   SomeClass.__doc__ = c
   return SomeClass

该类从函数中捕获值,使您可以动态创建一个类,例如C ++中的模板元编程

Nesting classes within classes:

  • Nested classes bloat the class definition making it harder to see whats going on.

  • Nested classes can create coupling that would make testing more difficult.

  • In Python you can put more than one class in a file/module, unlike Java, so the class still remains close to top level class and could even have the class name prefixed with an “_” to help signify that others shouldn’t be using it.

The place where nested classes can prove useful is within functions

def some_func(a, b, c):
   class SomeClass(a):
      def some_method(self):
         return b
   SomeClass.__doc__ = c
   return SomeClass

The class captures the values from the function allowing you to dynamically create a class like template metaprogramming in C++


回答 4

我了解反对嵌套类的参数,但是在某些情况下有使用它们的情况。想象一下,我正在创建一个双向链接列表类,并且需要创建一个节点类来维护节点。我有两个选择,在DoublyLinkedList类内部创建Node类,或在DoublyLinkedList类外部创建Node类。在这种情况下,我首选第一种选择,因为Node类仅在DoublyLinkedList类内部有意义。虽然没有隐藏/封装的好处,但是可以说Node类是DoublyLinkedList类的一部分,这有一个分组的好处。

I understand the arguments against nested classes, but there is a case for using them in some occasions. Imagine I’m creating a doubly-linked list class, and I need to create a node class for maintaing the nodes. I have two choices, create Node class inside the DoublyLinkedList class, or create the Node class outside the DoublyLinkedList class. I prefer the first choice in this case, because the Node class is only meaningful inside the DoublyLinkedList class. While there’s no hiding/encapsulation benefit, there is a grouping benefit of being able to say the Node class is part of the DoublyLinkedList class.


回答 5

没有他们,有什么事情是无法完成的吗?如果是这样,那是什么东西?

有以下一些事情是不容易完成的相关类的继承

这是相关类A和的极简示例B

class A(object):
    class B(object):
        def __init__(self, parent):
            self.parent = parent

    def make_B(self):
        return self.B(self)


class AA(A):  # Inheritance
    class B(A.B):  # Inheritance, same class name
        pass

这段代码导致了一个相当合理和可预测的行为:

>>> type(A().make_B())
<class '__main__.A.B'>
>>> type(A().make_B().parent)
<class '__main__.A'>
>>> type(AA().make_B())
<class '__main__.AA.B'>
>>> type(AA().make_B().parent)
<class '__main__.AA'>

如果B是顶级类,则不能self.B()在方法中make_B编写B(),而只会写,从而失去与适当类的动态绑定

请注意,在此构造中,您永远不要在class A主体中引用class B。这是parent在课堂上介绍该属性的动机B

当然,可以在没有内部类的情况下重新创建此动态绑定,而这会浪费乏味且易于出错的类。

Is there something that can’t be accomplished without them? If so, what is that thing?

There is something that cannot be easily done without: inheritance of related classes.

Here is a minimalist example with the related classes A and B:

class A(object):
    class B(object):
        def __init__(self, parent):
            self.parent = parent

    def make_B(self):
        return self.B(self)


class AA(A):  # Inheritance
    class B(A.B):  # Inheritance, same class name
        pass

This code leads to a quite reasonable and predictable behaviour:

>>> type(A().make_B())
<class '__main__.A.B'>
>>> type(A().make_B().parent)
<class '__main__.A'>
>>> type(AA().make_B())
<class '__main__.AA.B'>
>>> type(AA().make_B().parent)
<class '__main__.AA'>

If B were a top-level class, you could not write self.B() in the method make_B but would simply write B(), and thus lose the dynamic binding to the adequate classes.

Note that in this construction, you should never refer to class A in the body of class B. This is the motivation for introducing the parent attribute in class B.

Of course, this dynamic binding can be recreated without inner class at the cost of a tedious and error-prone instrumentation of the classes.


回答 6

我使用它的主要用例是防止小模块的扩散,在不需要单独的模块时防止命名空间污染。如果要扩展现有的类,但是该现有的类必须引用另一个应该始终与其耦合的子类。例如,我可能有一个utils.py其中包含许多帮助程序类的模块,这些模块不一定耦合在一起,但我想加强其中一些帮助程序类的耦合。例如,当我实现https://stackoverflow.com/a/8274307/2718295时

utils.py

import json, decimal

class Helper1(object):
    pass

class Helper2(object):
    pass

# Here is the notorious JSONEncoder extension to serialize Decimals to JSON floats
class DecimalJSONEncoder(json.JSONEncoder):

    class _repr_decimal(float): # Because float.__repr__ cannot be monkey patched
        def __init__(self, obj):
            self._obj = obj
        def __repr__(self):
            return '{:f}'.format(self._obj)

    def default(self, obj): # override JSONEncoder.default
        if isinstance(obj, decimal.Decimal):
            return self._repr_decimal(obj)
        # else
        super(self.__class__, self).default(obj)
        # could also have inherited from object and used return json.JSONEncoder.default(self, obj) 

然后,我们可以:

>>> from utils import DecimalJSONEncoder
>>> import json, decimal
>>> json.dumps({'key1': decimal.Decimal('1.12345678901234'), 
... 'key2':'strKey2Value'}, cls=DecimalJSONEncoder)
{"key2": "key2_value", "key_1": 1.12345678901234}

当然,我们可以完全避开继承,json.JSONEnocder而只需覆盖default()即可:

import decimal, json

class Helper1(object):
    pass

def json_encoder_decimal(obj):
    class _repr_decimal(float):
        ...

    if isinstance(obj, decimal.Decimal):
        return _repr_decimal(obj)

    return json.JSONEncoder(obj)


>>> json.dumps({'key1': decimal.Decimal('1.12345678901234')}, default=json_decimal_encoder)
'{"key1": 1.12345678901234}'

但有时只是出于约定,您希望utils由可扩展性的类组成。

这是另一个用例:我希望在OuterClass中创建一个用于可变项的工厂,而不必调用copy

class OuterClass(object):

    class DTemplate(dict):
        def __init__(self):
            self.update({'key1': [1,2,3],
                'key2': {'subkey': [4,5,6]})


    def __init__(self):
        self.outerclass_dict = {
            'outerkey1': self.DTemplate(),
            'outerkey2': self.DTemplate()}



obj = OuterClass()
obj.outerclass_dict['outerkey1']['key2']['subkey'].append(4)
assert obj.outerclass_dict['outerkey2']['key2']['subkey'] == [4,5,6]

我更喜欢这种模式,而@staticmethod不是原本用于工厂功能的装饰器。

The main use case I use this for is the prevent proliferation of small modules and to prevent namespace pollution when separate modules are not needed. If I am extending an existing class, but that existing class must reference another subclass that should always be coupled to it. For example, I may have a utils.py module that has many helper classes in it, that aren’t necessarily coupled together, but I want to reinforce coupling for some of those helper classes. For example, when I implement https://stackoverflow.com/a/8274307/2718295

:utils.py:

import json, decimal

class Helper1(object):
    pass

class Helper2(object):
    pass

# Here is the notorious JSONEncoder extension to serialize Decimals to JSON floats
class DecimalJSONEncoder(json.JSONEncoder):

    class _repr_decimal(float): # Because float.__repr__ cannot be monkey patched
        def __init__(self, obj):
            self._obj = obj
        def __repr__(self):
            return '{:f}'.format(self._obj)

    def default(self, obj): # override JSONEncoder.default
        if isinstance(obj, decimal.Decimal):
            return self._repr_decimal(obj)
        # else
        super(self.__class__, self).default(obj)
        # could also have inherited from object and used return json.JSONEncoder.default(self, obj) 

Then we can:

>>> from utils import DecimalJSONEncoder
>>> import json, decimal
>>> json.dumps({'key1': decimal.Decimal('1.12345678901234'), 
... 'key2':'strKey2Value'}, cls=DecimalJSONEncoder)
{"key2": "key2_value", "key_1": 1.12345678901234}

Of course, we could have eschewed inheriting json.JSONEnocder altogether and just override default():

:

import decimal, json

class Helper1(object):
    pass

def json_encoder_decimal(obj):
    class _repr_decimal(float):
        ...

    if isinstance(obj, decimal.Decimal):
        return _repr_decimal(obj)

    return json.JSONEncoder(obj)


>>> json.dumps({'key1': decimal.Decimal('1.12345678901234')}, default=json_decimal_encoder)
'{"key1": 1.12345678901234}'

But sometimes just for convention, you want utils to be composed of classes for extensibility.

Here’s another use-case: I want a factory for mutables in my OuterClass without having to invoke copy:

class OuterClass(object):

    class DTemplate(dict):
        def __init__(self):
            self.update({'key1': [1,2,3],
                'key2': {'subkey': [4,5,6]})


    def __init__(self):
        self.outerclass_dict = {
            'outerkey1': self.DTemplate(),
            'outerkey2': self.DTemplate()}



obj = OuterClass()
obj.outerclass_dict['outerkey1']['key2']['subkey'].append(4)
assert obj.outerclass_dict['outerkey2']['key2']['subkey'] == [4,5,6]

I prefer this pattern over the @staticmethod decorator you would otherwise use for a factory function.


回答 7

1.两种功能等效的方式

前面显示的两种方法在功能上是相同的。但是,有一些细微的差异,并且在某些情况下您想选择一个而不是另一个。

方式1:嵌套类定义
(=“ Nested class”)

class MyOuter1:
    class Inner:
        def show(self, msg):
            print(msg)

方式2:将模块级别的内部类附加到外部类
(=“ Referenced内部类”)

class _InnerClass:
    def show(self, msg):
        print(msg)

class MyOuter2:
    Inner = _InnerClass

下划线用于遵循PEP8: “内部接口(包,模块,类,函数,属性或其他名称)应-带有一个前导下划线作为前缀”。

2.相似之处

下面的代码片段演示了“嵌套类”与“引用内部类”的功能相似性;它们在检查内部类实例类型的代码中的行为方式相同。不用说,m.inner.anymethod()它们与m1和的行为类似m2

m1 = MyOuter1()
m2 = MyOuter2()

innercls1 = getattr(m1, 'Inner', None)
innercls2 = getattr(m2, 'Inner', None)

isinstance(innercls1(), MyOuter1.Inner)
# True

isinstance(innercls2(), MyOuter2.Inner)
# True

type(innercls1()) == mypackage.outer1.MyOuter1.Inner
# True (when part of mypackage)

type(innercls2()) == mypackage.outer2.MyOuter2.Inner
# True (when part of mypackage)

3.差异

下面列出了“嵌套类”和“引用内部类”的区别。它们并不大,但是有时您希望基于这些选择一个或另一个。

3.1代码封装

使用“嵌套类”可以比使用“引用内部类”更好地封装代码。模块命名空间中的类是全局变量。嵌套类的目的是减少模块中的混乱情况,并将内部类放入外部类中。

当没有人使用*时from packagename import *,少量模块级别的变量可能很好,例如,当使用具有代码完成/智能感知的IDE时。

* 对吗?

3.2代码的可读性

Django文档指示将内部类Meta用于模型元数据。指示框架用户class Foo(models.Model)使用inner 编写一个更清晰的* class Meta

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

而不是“写class _Meta,然后写一个class Foo(models.Model)Meta = _Meta”;

class _Meta:
    ordering = ["horn_length"]
    verbose_name_plural = "oxen"

class Ox(models.Model):
    Meta = _Meta
    horn_length = models.IntegerField()
  • 使用“嵌套类”方法,可以读取嵌套的项目符号点列表,但是使用“引用内部类”方法,则必须向上滚动以查看其定义,_Meta以查看其“子项”(属性)。

  • 如果您的代码嵌套级别增加或由于其他原因导致行很长,则“引用的内部类”方法可能更具可读性。

*当然是口味问题

3.3略有不同的错误消息

这没什么大不了的,只是为了完整性:当访问内部类的不存在属性时,我们会看到截然不同的异常。继续第2节中给出的示例:

innercls1.foo()
# AttributeError: type object 'Inner' has no attribute 'foo'

innercls2.foo()
# AttributeError: type object '_InnerClass' has no attribute 'foo'

这是因为type内部类的s是

type(innercls1())
#mypackage.outer1.MyOuter1.Inner

type(innercls2())
#mypackage.outer2._InnerClass

1. Two functionally equivalent ways

The two ways shown before are functionally identical. However, there are some subtle differences, and there are situations when you would like to choose one over another.

Way 1: Nested class definition
(=”Nested class”)

class MyOuter1:
    class Inner:
        def show(self, msg):
            print(msg)

Way 2: With module level Inner class attached to Outer class
(=”Referenced inner class”)

class _InnerClass:
    def show(self, msg):
        print(msg)

class MyOuter2:
    Inner = _InnerClass

Underscore is used to follow PEP8 “internal interfaces (packages, modules, classes, functions, attributes or other names) should — be prefixed with a single leading underscore.”

2. Similarities

Below code snippet demonstrates the functional similarities of the “Nested class” vs “Referenced inner class”; They would behave the same way in code checking for the type of an inner class instance. Needless to say, the m.inner.anymethod() would behave similarly with m1 and m2

m1 = MyOuter1()
m2 = MyOuter2()

innercls1 = getattr(m1, 'Inner', None)
innercls2 = getattr(m2, 'Inner', None)

isinstance(innercls1(), MyOuter1.Inner)
# True

isinstance(innercls2(), MyOuter2.Inner)
# True

type(innercls1()) == mypackage.outer1.MyOuter1.Inner
# True (when part of mypackage)

type(innercls2()) == mypackage.outer2.MyOuter2.Inner
# True (when part of mypackage)

3. Differences

The differences of “Nested class” and “Referenced inner class” are listed below. They are not big, but sometimes you would like to choose one or the other based on these.

3.1 Code Encapsulation

With “Nested classes” it is possible to encapsulate code better than with “Referenced inner class”. A class in the module namespace is a global variable. The purpose of nested classes is to reduce clutter in the module and put the inner class inside the outer class.

While no-one* is using from packagename import *, low amount of module level variables can be nice for example when using an IDE with code completion / intellisense.

*Right?

3.2 Readability of code

Django documentation instructs to use inner class Meta for model metadata. It is a bit more clearer* to instruct the framework users to write a class Foo(models.Model) with inner class Meta;

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

instead of “write a class _Meta, then write a class Foo(models.Model) with Meta = _Meta“;

class _Meta:
    ordering = ["horn_length"]
    verbose_name_plural = "oxen"

class Ox(models.Model):
    Meta = _Meta
    horn_length = models.IntegerField()
  • With the “Nested class” approach the code can be read a nested bullet point list, but with the “Referenced inner class” method one has to scroll back up to see the definition of _Meta to see its “child items” (attributes).

  • The “Referenced inner class” method can be more readable if your code nesting level grows or the rows are long for some other reason.

* Of course, a matter of taste

3.3 Slightly different error messages

This is not a big deal, but just for completeness: When accessing non-existent attribute for the inner class, we see slighly different exceptions. Continuing the example given in Section 2:

innercls1.foo()
# AttributeError: type object 'Inner' has no attribute 'foo'

innercls2.foo()
# AttributeError: type object '_InnerClass' has no attribute 'foo'

This is because the types of the inner classes are

type(innercls1())
#mypackage.outer1.MyOuter1.Inner

type(innercls2())
#mypackage.outer2._InnerClass

回答 8

我已经使用Python的内部类在unittest函数(即内部def test_something():)中故意创建了错误的子类,以便接近100%的测试覆盖率(例如,通过覆盖某些方法来测试很少触发的日志语句)。

回想起来,它类似于埃德的答案https://stackoverflow.com/a/722036/1101109

一旦删除了所有内部引用,此类内部类便超出范围,并准备进行垃圾回收。例如,获取以下inner.py文件:

class A(object):
    pass

def scope():
    class Buggy(A):
        """Do tests or something"""
    assert isinstance(Buggy(), A)

在OSX Python 2.7.6下得到以下奇怪结果:

>>> from inner import A, scope
>>> A.__subclasses__()
[]
>>> scope()
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A, scope
>>> from inner import A
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A
>>> import gc
>>> gc.collect()
0
>>> gc.collect()  # Yes I needed to call the gc twice, seems reproducible
3
>>> from inner import A
>>> A.__subclasses__()
[]

提示-不要继续尝试使用Django模型,这似乎保留了其他(已缓存?)对我的越野车类的引用。

因此,总的来说,我不建议您将内部类用于此类目的,除非您确实确实认为100%的测试覆盖率并且不能使用其他方法。虽然我觉得很高兴知道,如果使用__subclasses__(),它有时会被内部类污染。无论哪种方式,如果您走了这么远,我都认为到目前为止,我们对Python,私有dunderscores以及所有内容都非常了解。

I have used Python’s inner classes to create deliberately buggy subclasses within unittest functions (i.e. inside def test_something():) in order to get closer to 100% test coverage (e.g. testing very rarely triggered logging statements by overriding some methods).

In retrospect it’s similar to Ed’s answer https://stackoverflow.com/a/722036/1101109

Such inner classes should go out of scope and be ready for garbage collection once all references to them have been removed. For instance, take the following inner.py file:

class A(object):
    pass

def scope():
    class Buggy(A):
        """Do tests or something"""
    assert isinstance(Buggy(), A)

I get the following curious results under OSX Python 2.7.6:

>>> from inner import A, scope
>>> A.__subclasses__()
[]
>>> scope()
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A, scope
>>> from inner import A
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A
>>> import gc
>>> gc.collect()
0
>>> gc.collect()  # Yes I needed to call the gc twice, seems reproducible
3
>>> from inner import A
>>> A.__subclasses__()
[]

Hint – Don’t go on and try doing this with Django models, which seemed to keep other (cached?) references to my buggy classes.

So in general, I wouldn’t recommend using inner classes for this kind of purpose unless you really do value that 100% test coverage and can’t use other methods. Though I think it’s nice to be aware that if you use the __subclasses__(), that it can sometimes get polluted by inner classes. Either way if you followed this far, I think we’re pretty deep into Python at this point, private dunderscores and all.


如何在Python中使用方法重载?

问题:如何在Python中使用方法重载?

我正在尝试在Python中实现方法重载:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow(2)

但是输出是second method 2; 类似地:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow()

Traceback (most recent call last):
  File "my.py", line 9, in <module>
    ob.stackoverflow()
TypeError: stackoverflow() takes exactly 2 arguments (1 given)

我该如何工作?

I am trying to implement method overloading in Python:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow(2)

but the output is second method 2; similarly:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow()

gives

Traceback (most recent call last):
  File "my.py", line 9, in <module>
    ob.stackoverflow()
TypeError: stackoverflow() takes exactly 2 arguments (1 given)

How do I make this work?


回答 0

它是方法重载而不是方法重写。在Python中,您可以通过一个函数来完成全部操作:

class A:

    def stackoverflow(self, i='some_default_value'):    
        print 'only method'

ob=A()
ob.stackoverflow(2)
ob.stackoverflow()

在Python中,不能有两个具有相同名称的方法,而且也不需要。

请参阅Python教程的默认参数值部分。有关避免的常见错误,请参见“最小惊讶”和“可变默认参数 ”。

编辑:有关Python 3.4中新的单调度通用功能的信息,请参阅PEP 443

It’s method overloading not method overriding. And in Python, you do it all in one function:

class A:

    def stackoverflow(self, i='some_default_value'):    
        print 'only method'

ob=A()
ob.stackoverflow(2)
ob.stackoverflow()

You can’t have two methods with the same name in Python — and you don’t need to.

See the Default Argument Values section of the Python tutorial. See “Least Astonishment” and the Mutable Default Argument for a common mistake to avoid.

Edit: See PEP 443 for information about the new single dispatch generic functions in Python 3.4.


回答 1

您还可以使用pythonlangutil

from pythonlangutil.overload import Overload, signature

class A:
    @Overload
    @signature()
    def stackoverflow(self):    
        print 'first method'

    @stackoverflow.overload
    @signature("int")
    def stackoverflow(self, i):
        print 'second method', i

You can also use pythonlangutil:

from pythonlangutil.overload import Overload, signature

class A:
    @Overload
    @signature()
    def stackoverflow(self):    
        print 'first method'

    @stackoverflow.overload
    @signature("int")
    def stackoverflow(self, i):
        print 'second method', i

回答 2

在Python中,您不会那样做。当人们使用Java之类的语言来执行此操作时,他们通常希望使用默认值(如果不需要,则通常需要使用其他名称的方法)。因此,在Python中,您可以具有默认值

class A(object):  # Remember the ``object`` bit when working in Python 2.x

    def stackoverflow(self, i=None):
        if i is None:
            print 'first form'
        else:
            print 'second form'

如您所见,您可以使用它来触发单独的行为,而不仅仅是具有默认值。

>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form

In Python, you don’t do things that way. When people do that in languages like Java, they generally want a default value (if they don’t, they generally want a method with a different name). So, in Python, you can have default values.

class A(object):  # Remember the ``object`` bit when working in Python 2.x

    def stackoverflow(self, i=None):
        if i is None:
            print 'first form'
        else:
            print 'second form'

As you can see, you can use this to trigger separate behaviour rather than merely having a default value.

>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form

回答 3

您可以,永远也不需要,也不需要。

在Python中,一切都是对象。类是事物,所以它们是对象。方法也是如此。

有一个称为A类的对象。它具有称为的属性stackoverflow。它只能具有一个这样的属性。

在编写时def stackoverflow(...): ...,发生的事情是创建一个方法对象,并将其分配给的stackoverflow属性A。如果您编写两个定义,则第二个定义将替换第一个定义,即分配始终起作用。

此外,您也不想编写执行有时用于重载的各种事情的代码。这不是这种语言的工作方式。

不要试图为每种类型的事物定义一个单独的函数(这毫无意义,因为您始终不为函数参数指定类型),而不必担心事物什么而开始思考它们可以做什么

您不仅不能编写一个单独的元组来处理一个元组还是一个列表,而且不想要也不需要

您要做的就是利用它们都是可迭代的事实(例如,您可以编写for element in container:)。(它们与继承没有直接关系这一事实无关紧要。)

You can’t, never need to and don’t really want to.

In Python, everything is an object. Classes are things, so they are objects. So are methods.

There is an object called A which is a class. It has an attribute called stackoverflow. It can only have one such attribute.

When you write def stackoverflow(...): ..., what happens is that you create an object which is the method, and assign it to the stackoverflow attribute of A. If you write two definitions, the second one replaces the first, the same way that assignment always behaves.

You furthermore do not want to write code that does the wilder of the sorts of things that overloading is sometimes used for. That’s not how the language works.

Instead of trying to define a separate function for each type of thing you could be given (which makes little sense since you don’t specify types for function parameters anyway), stop worrying about what things are and start thinking about what they can do.

You not only can’t write a separate one to handle a tuple vs. a list, but also don’t want or need to.

All you do is take advantage of the fact that they are both, for example, iterable (i.e. you can write for element in container:). (The fact that they aren’t directly related by inheritance is irrelevant.)


回答 4

虽然@agf过去使用PEP-3124正确地回答了问题,但我们得到了语法糖。有关装饰器的详细信息 ,请参见键入文档。@overload但是请注意,这实际上只是语法糖,恕我直言,这是所有人们从那时以来一直在参数的话题。我个人认为,具有不同特征的多个功能,使它更具可读性则具有20+的参数都设置为默认值(单个功能None的大部分时间),然后不得不反复折腾使用不已ifelifelse链找出什么调用者实际上希望我们的函数处理提供的参数集。在Python Zen之后,早就应该这样做了

美丽胜于丑陋。

并且可以说也是

简单胜于复杂。

直接来自上面链接的官方Python文档:

from typing import overload
@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> Tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>

While @agf was right with the answer in the past now with PEP-3124 we got our syntax sugar. See typing documentation for details on the @overload decorator but note that this is really just syntax sugar and IMHO this is all people have been arguing about ever since. Personally I agree that having multiple functions with different signatures makes it more readable then having a single function with 20+ arguments all set to a default value (None most of the time) and then having to fiddle around using endless if, elif, else chains to find out what the caller actually wants our function to do with the provided set of arguments. This was long overdue following the Python Zen

Beautiful is better than ugly.

and arguably also

Simple is better than complex.

Straight from the official Python documentation linked above:

from typing import overload
@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> Tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>

回答 5

我用Python 3.2.1写出答案。

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)

这个怎么运作:

  1. overload接受任意数量的可调用对象并将其存储在tuple中functions,然后返回lambda。
  2. lambda接受任意数量的参数,然后返回存储在functions[number_of_unnamed_args_passed]被调用中的调用函数的结果,并带有传递给lambda的参数。

用法:

class A:
    stackoverflow=overload(                    \
        None, \ 
        #there is always a self argument, so this should never get called
        lambda self: print('First method'),      \
        lambda self, i: print('Second method', i) \
    )

I write my answer in Python 3.2.1.

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)

How it works:

  1. overload takes any amount of callables and stores them in tuple functions, then returns lambda.
  2. The lambda takes any amount of arguments, then returns result of calling function stored in functions[number_of_unnamed_args_passed] called with arguments passed to the lambda.

Usage:

class A:
    stackoverflow=overload(                    \
        None, \ 
        #there is always a self argument, so this should never get called
        lambda self: print('First method'),      \
        lambda self, i: print('Second method', i) \
    )

回答 6

我认为您要查找的单词是“超载”。python中没有方法重载。但是,您可以使用默认参数,如下所示。

def stackoverflow(self, i=None):
    if i != None:     
        print 'second method', i
    else:
        print 'first method'

当您传递参数时,它将遵循第一个条件的逻辑并执行第一个print语句。当您不传递任何参数时,它将进入else条件并执行第二个print语句。

I think the word you’re looking for is “overloading”. There is no method overloading in python. You can however use default arguments, as follows.

def stackoverflow(self, i=None):
    if i != None:     
        print 'second method', i
    else:
        print 'first method'

When you pass it an argument it will follow the logic of the first condition and execute the first print statement. When you pass it no arguments, it will go into the else condition and execute the second print statement.


回答 7

我用Python 2.7写下答案:

在Python中,方法重载是不可能的。如果您真的想访问具有不同功能的相同功能,建议您进行方法重写。

class Base(): # Base class
    '''def add(self,a,b):
        s=a+b
        print s'''

    def add(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c

        sum =a+b+c
        print sum

class Derived(Base): # Derived class
    def add(self,a,b): # overriding method
        sum=a+b
        print sum



add_fun_1=Base() #instance creation for Base class
add_fun_2=Derived()#instance creation for Derived class

add_fun_1.add(4,2,5) # function with 3 arguments
add_fun_2.add(4,2)   # function with 2 arguments

I write my answer in Python 2.7:

In Python, method overloading is not possible; if you really want access the same function with different features, I suggest you to go for method overriding.

class Base(): # Base class
    '''def add(self,a,b):
        s=a+b
        print s'''

    def add(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c

        sum =a+b+c
        print sum

class Derived(Base): # Derived class
    def add(self,a,b): # overriding method
        sum=a+b
        print sum



add_fun_1=Base() #instance creation for Base class
add_fun_2=Derived()#instance creation for Derived class

add_fun_1.add(4,2,5) # function with 3 arguments
add_fun_2.add(4,2)   # function with 2 arguments

回答 8

在Python中,重载不是一个可应用的概念。但是,如果您试图创建一种情况,例如,如果要传递一个类型foo为实参的参数,而又要为类型为实参的参数,则希望执行一个初始化程序bar,因为Python中的所有内容都作为对象处理,因此您可以检查传递的对象的类类型的名称,并根据该条件编写条件处理。

class A:
   def __init__(self, arg)
      # Get the Argument's class type as a String
      argClass = arg.__class__.__name__

      if argClass == 'foo':
         print 'Arg is of type "foo"'
         ...
      elif argClass == 'bar':
         print 'Arg is of type "bar"'
         ...
      else
         print 'Arg is of a different type'
         ...

根据需要,可以通过不同的方法将此概念应用于多个不同的方案。

In Python, overloading is not an applied concept. However, if you are trying to create a case where, for instance, you want one initializer to be performed if passed an argument of type foo and another initializer for an argument of type bar then, since everything in Python is handled as object, you can check the name of the passed object’s class type and write conditional handling based on that.

class A:
   def __init__(self, arg)
      # Get the Argument's class type as a String
      argClass = arg.__class__.__name__

      if argClass == 'foo':
         print 'Arg is of type "foo"'
         ...
      elif argClass == 'bar':
         print 'Arg is of type "bar"'
         ...
      else
         print 'Arg is of a different type'
         ...

This concept can be applied to multiple different scenarios through different methods as needed.


回答 9

在Python中,您可以使用默认参数来执行此操作。

class A:

    def stackoverflow(self, i=None):    
        if i == None:
            print 'first method'
        else:
            print 'second method',i

In Python, you’d do this with a default argument.

class A:

    def stackoverflow(self, i=None):    
        if i == None:
            print 'first method'
        else:
            print 'second method',i

回答 10

刚刚遇到这个https://github.com/bintoro/overloading.py的人可能感兴趣。

从链接的存储库的自述文件中:

重载是一个基于运行时参数的类型和数量提供功能分派的模块。

调用重载函数时,调度程序将提供的参数与可用函数签名进行比较,并调用提供最准确匹配的实现。

特征

注册时的功能验证和详细的解决规则可确保在运行时具有唯一的,定义明确的结果。实现功能解析缓存以获得出色的性能。在函数签名中支持可选参数(默认值)。解决最佳匹配时,同时评估位置参数和关键字参数。支持后备功能和共享代码的执行。支持参数多态性。支持类和继承,包括类方法和静态方法。

Just came across this https://github.com/bintoro/overloading.py for anybody who may be interested.

From the linked repository’s readme:

overloading is a module that provides function dispatching based on the types and number of runtime arguments.

When an overloaded function is invoked, the dispatcher compares the supplied arguments to available function signatures and calls the implementation that provides the most accurate match.

Features

Function validation upon registration and detailed resolution rules guarantee a unique, well-defined outcome at runtime. Implements function resolution caching for great performance. Supports optional parameters (default values) in function signatures. Evaluates both positional and keyword arguments when resolving the best match. Supports fallback functions and execution of shared code. Supports argument polymorphism. Supports classes and inheritance, including classmethods and staticmethods.


回答 11

Python不支持Java或C ++之类的方法重载。我们可能会重载这些方法,但只能使用最新定义的方法。

# First sum method.
# Takes two argument and print their sum
def sum(a, b):
    s = a + b
    print(s)

# Second sum method
# Takes three argument and print their sum
def sum(a, b, c):
    s = a + b + c
    print(s)

# Uncommenting the below line shows an error    
# sum(4, 5)

# This line will call the second sum method
sum(4, 5, 5)

我们需要提供可选参数或* args,以便在调用时提供不同数量的args。

来自https://www.geeksforgeeks.org/python-method-overloading/

Python does not support method overloading like Java or C++. We may overload the methods but can only use the latest defined method.

# First sum method.
# Takes two argument and print their sum
def sum(a, b):
    s = a + b
    print(s)

# Second sum method
# Takes three argument and print their sum
def sum(a, b, c):
    s = a + b + c
    print(s)

# Uncommenting the below line shows an error    
# sum(4, 5)

# This line will call the second sum method
sum(4, 5, 5)

We need to provide optional arguments or *args in order to provide different number of args on calling.

Courtesy from https://www.geeksforgeeks.org/python-method-overloading/


回答 12

Python 3.x包含标准的类型库,该库允许使用@overload装饰器来重载方法。不幸的是,这是为了使代码更具可读性,因为@overload装饰的方法将需要后面跟一个处理不同参数的非装饰方法。在这里可以找到更多信息但以您的示例为例:

from typing import overload
from typing import Any, Optional
class A(object):
    @overload
    def stackoverflow(self) -> None:    
        print('first method')
    @overload
    def stackoverflow(self, i: Any) -> None:
        print('second method', i)
    def stackoverflow(self, i: Optional[Any] = None) -> None:
        if not i:
            print('first method')
        else:
            print('second method', i)

ob=A()
ob.stackoverflow(2)

Python 3.x includes standard typing library which allows for method overloading with the use of @overload decorator. Unfortunately, this is to make the code more readable, as the @overload decorated methods will need to be followed by a non-decorated method that handles different arguments. More can be found here here but for your example:

from typing import overload
from typing import Any, Optional
class A(object):
    @overload
    def stackoverflow(self) -> None:    
        print('first method')
    @overload
    def stackoverflow(self, i: Any) -> None:
        print('second method', i)
    def stackoverflow(self, i: Optional[Any] = None) -> None:
        if not i:
            print('first method')
        else:
            print('second method', i)

ob=A()
ob.stackoverflow(2)

回答 13

在MathMethod.py文件中

from multipledispatch import dispatch
@dispatch(int,int)
def Add(a,b):
   return a+b 
@dispatch(int,int,int)  
def Add(a,b,c):
   return a+b+c 
@dispatch(int,int,int,int)    
def Add(a,b,c,d):
   return a+b+c+d

在Main.py文件中

import MathMethod as MM 
print(MM.Add(200,1000,1000,200))

我们可以通过使用multidispatch重载方法

In MathMethod.py file

from multipledispatch import dispatch
@dispatch(int,int)
def Add(a,b):
   return a+b 
@dispatch(int,int,int)  
def Add(a,b,c):
   return a+b+c 
@dispatch(int,int,int,int)    
def Add(a,b,c,d):
   return a+b+c+d

In Main.py file

import MathMethod as MM 
print(MM.Add(200,1000,1000,200))

We can overload method by using multipledispatch


回答 14

Python在PEP-3124中添加了@overload装饰器,以通过类型检查为重载提供语法糖-而不是仅仅进行覆盖。

PEP-3124中通过@overload重载的代码示例

from overloading import overload
from collections import Iterable

def flatten(ob):
    """Flatten an object to its component iterables"""
    yield ob

@overload
def flatten(ob: Iterable):
    for o in ob:
        for ob in flatten(o):
            yield ob

@overload
def flatten(ob: basestring):
    yield ob

由@ overload-decorator转换为:

def flatten(ob):
    if isinstance(ob, basestring) or not isinstance(ob, Iterable):
        yield ob
    else:
        for o in ob:
            for ob in flatten(o):
                yield ob

Python added the @overload decorator with PEP-3124 to provide syntactic sugar for overloading via type inspection – instead of just working with overwriting.

Code example on overloading via @overload from PEP-3124

from overloading import overload
from collections import Iterable

def flatten(ob):
    """Flatten an object to its component iterables"""
    yield ob

@overload
def flatten(ob: Iterable):
    for o in ob:
        for ob in flatten(o):
            yield ob

@overload
def flatten(ob: basestring):
    yield ob

is transformed by the @overload-decorator to:

def flatten(ob):
    if isinstance(ob, basestring) or not isinstance(ob, Iterable):
        yield ob
    else:
        for o in ob:
            for ob in flatten(o):
                yield ob

AttributeError:“ datetime”模块没有属性“ strptime”

问题:AttributeError:“ datetime”模块没有属性“ strptime”

这是我的Transaction课:

class Transaction(object):
    def __init__(self, company, num, price, date, is_buy):
        self.company = company
        self.num = num
        self.price = price
        self.date = datetime.strptime(date, "%Y-%m-%d")
        self.is_buy = is_buy

当我尝试运行该date功能时:

tr = Transaction('AAPL', 600, '2013-10-25')
print tr.date

我收到以下错误:

   self.date = datetime.strptime(self.d, "%Y-%m-%d")
 AttributeError: 'module' object has no attribute 'strptime'

我该如何解决?

Here is my Transaction class:

class Transaction(object):
    def __init__(self, company, num, price, date, is_buy):
        self.company = company
        self.num = num
        self.price = price
        self.date = datetime.strptime(date, "%Y-%m-%d")
        self.is_buy = is_buy

And when I’m trying to run the date function:

tr = Transaction('AAPL', 600, '2013-10-25')
print tr.date

I’m getting the following error:

   self.date = datetime.strptime(self.d, "%Y-%m-%d")
 AttributeError: 'module' object has no attribute 'strptime'

How can I fix that?


回答 0

如果我不得不猜测,您这样做:

import datetime

在代码的顶部。这意味着您必须执行以下操作:

datetime.datetime.strptime(date, "%Y-%m-%d")

访问该strptime方法。或者,您可以将import语句更改为此:

from datetime import datetime

并按原样访问它。

制作该datetime模块的人员还命名了他们的Classdatetime

#module  class    method
datetime.datetime.strptime(date, "%Y-%m-%d")

If I had to guess, you did this:

import datetime

at the top of your code. This means that you have to do this:

datetime.datetime.strptime(date, "%Y-%m-%d")

to access the strptime method. Or, you could change the import statement to this:

from datetime import datetime

and access it as you are.

The people who made the datetime module also named their class datetime:

#module  class    method
datetime.datetime.strptime(date, "%Y-%m-%d")

回答 1

使用正确的调用:strptime是类的datetime.datetime类方法,不是datetime模块中的函数。

self.date = datetime.datetime.strptime(self.d, "%Y-%m-%d")

正如乔恩·克莱门茨(Jon Clements)在评论中提到的那样,有人这样做了from datetime import datetime,这会将datetime名称绑定到datetime类上,并使您的初始代码正常工作。

要确定您将来遇到的情况,请查看导入语句

  • import datetime:这就是模块(这就是您现在所拥有的)。
  • from datetime import datetime:那是类。

Use the correct call: strptime is a classmethod of the datetime.datetime class, it’s not a function in the datetime module.

self.date = datetime.datetime.strptime(self.d, "%Y-%m-%d")

As mentioned by Jon Clements in the comments, some people do from datetime import datetime, which would bind the datetime name to the datetime class, and make your initial code work.

To identify which case you’re facing (in the future), look at your import statements

  • import datetime: that’s the module (that’s what you have right now).
  • from datetime import datetime: that’s the class.

回答 2

我遇到了同样的问题,这不是您告诉的解决方案。因此,我将“从datetime导入datetime”更改为“ import datetime”。之后,借助“ datetime.datetime”,我可以正确获取整个模块。我想这是对该问题的正确答案。

I got the same problem and it is not the solution that you told. So I changed the “from datetime import datetime” to “import datetime”. After that with the help of “datetime.datetime” I can get the whole modules correctly. I guess this is the correct answer to that question.