标签归档:methods

类方法生成“ TypeError:…为关键字参数获得了多个值……”

问题:类方法生成“ TypeError:…为关键字参数获得了多个值……”

如果我用关键字参数定义一个类方法,则:

class foo(object):
  def foodo(thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

调用该方法将生成TypeError

myfoo = foo()
myfoo.foodo(thing="something")

...
TypeError: foodo() got multiple values for keyword argument 'thing'

这是怎么回事?

If I define a class method with a keyword argument thus:

class foo(object):
  def foodo(thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

calling the method generates a TypeError:

myfoo = foo()
myfoo.foodo(thing="something")

...
TypeError: foodo() got multiple values for keyword argument 'thing'

What’s going on?


回答 0

问题在于,传递给python中类方法的第一个参数始终是在其上调用该方法的类实例的副本,通常标记为self。如果这样声明了该类:

class foo(object):
  def foodo(self, thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

它的行为符合预期。

说明:

如果没有self作为第一个参数,则在myfoo.foodo(thing="something")执行时,将foodo使用arguments调用该方法(myfoo, thing="something")myfoo然后将该实例分配给thing(因为thing是第一个声明的参数),但是python也会尝试分配"something"thing,因此是Exception。

为了演示,请尝试使用原始代码运行它:

myfoo.foodo("something")
print
print myfoo

您将输出如下:

<__main__.foo object at 0x321c290>
a thong is something

<__main__.foo object at 0x321c290>

您可以看到“事物”已被分配对类“ foo”的实例“ myfoo”的引用。文档的此部分说明了函数参数的工作原理。

The problem is that the first argument passed to class methods in python is always a copy of the class instance on which the method is called, typically labelled self. If the class is declared thus:

class foo(object):
  def foodo(self, thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

it behaves as expected.

Explanation:

Without self as the first parameter, when myfoo.foodo(thing="something") is executed, the foodo method is called with arguments (myfoo, thing="something"). The instance myfoo is then assigned to thing (since thing is the first declared parameter), but python also attempts to assign "something" to thing, hence the Exception.

To demonstrate, try running this with the original code:

myfoo.foodo("something")
print
print myfoo

You’ll output like:

<__main__.foo object at 0x321c290>
a thong is something

<__main__.foo object at 0x321c290>

You can see that ‘thing’ has been assigned a reference to the instance ‘myfoo’ of the class ‘foo’. This section of the docs explains how function arguments work a bit more.


回答 1

感谢您的指导性帖子。我只想说明一下,如果您收到“ TypeError:foodo()为关键字参数’thing’获得多个值”,则可能是您错误地将“ self”作为参数传递的调用该函数(可能是因为您从类声明中复制了该行-急时这是一个常见错误)。

Thanks for the instructive posts. I’d just like to keep a note that if you’re getting “TypeError: foodo() got multiple values for keyword argument ‘thing'”, it may also be that you’re mistakenly passing the ‘self’ as a parameter when calling the function (probably because you copied the line from the class declaration – it’s a common error when one’s in a hurry).


回答 2

这可能很明显,但可能会对从未见过的人有所帮助。如果您错误地通过位置和名称显式地分配了参数,则对于常规函数也会发生这种情况。

>>> def foodo(thing=None, thong='not underwear'):
...     print thing if thing else "nothing"
...     print 'a thong is',thong
...
>>> foodo('something', thing='everything')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foodo() got multiple values for keyword argument 'thing'

This might be obvious, but it might help someone who has never seen it before. This also happens for regular functions if you mistakenly assign a parameter by position and explicitly by name.

>>> def foodo(thing=None, thong='not underwear'):
...     print thing if thing else "nothing"
...     print 'a thong is',thong
...
>>> foodo('something', thing='everything')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foodo() got multiple values for keyword argument 'thing'

回答 3

只需向功能添加“ staticmethod”装饰器即可解决问题

class foo(object):
    @staticmethod
    def foodo(thing=None, thong='not underwear'):
        print thing if thing else "nothing" 
        print 'a thong is',thong

just add ‘staticmethod’ decorator to function and problem is fixed

class foo(object):
    @staticmethod
    def foodo(thing=None, thong='not underwear'):
        print thing if thing else "nothing" 
        print 'a thong is',thong

回答 4

我想再添加一个答案:

当您尝试在调用函数中尝试传递位置顺序错误的位置参数以及关键字参数时,就会发生这种情况。

there is difference between parameter and argument您可以在此处详细了解python中的参数和参数

def hello(a,b=1, *args):
   print(a, b, *args)


hello(1, 2, 3, 4,a=12)

因为我们有三个参数:

a是位置参数

b = 1是关键字和默认参数

* args是可变长度参数

因此我们首先将a作为位置参数赋值,这意味着我们必须按位置顺序向位置参数提供值,这里顺序很重要。但是我们将参数1传递给in调用函数中的位置,然后还将值提供给a,将其视为关键字参数。现在一个有两个值:

一个是位置值:a = 1

第二个是关键字值,a = 12

我们必须更改hello(1, 2, 3, 4,a=12)为,hello(1, 2, 3, 4,12) 所以现在a将仅获得一个位置值,即1,b将获得值2,其余值将获得* args(可变长度参数)

附加信息

如果我们希望* args应该得到2,3,4而a应该得到1和b应该得到12

那么我们可以这样做
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)

还有更多:

def hello(a,*c,b=1,**kwargs):
    print(b)
    print(c)
    print(a)
    print(kwargs)

hello(1,2,1,2,8,9,c=12)

输出:

1

(2, 1, 2, 8, 9)

1

{'c': 12}

I want to add one more answer :

It happens when you try to pass positional parameter with wrong position order along with keyword argument in calling function.

there is difference between parameter and argument you can read in detail about here Arguments and Parameter in python

def hello(a,b=1, *args):
   print(a, b, *args)


hello(1, 2, 3, 4,a=12)

since we have three parameters :

a is positional parameter

b=1 is keyword and default parameter

*args is variable length parameter

so we first assign a as positional parameter , means we have to provide value to positional argument in its position order, here order matter. but we are passing argument 1 at the place of a in calling function and then we are also providing value to a , treating as keyword argument. now a have two values :

one is positional value: a=1

second is keyworded value which is a=12

Solution

We have to change hello(1, 2, 3, 4,a=12) to hello(1, 2, 3, 4,12) so now a will get only one positional value which is 1 and b will get value 2 and rest of values will get *args (variable length parameter)

additional information

if we want that *args should get 2,3,4 and a should get 1 and b should get 12

then we can do like this
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)

Something more :

def hello(a,*c,b=1,**kwargs):
    print(b)
    print(c)
    print(a)
    print(kwargs)

hello(1,2,1,2,8,9,c=12)

output :

1

(2, 1, 2, 8, 9)

1

{'c': 12}

回答 5

如果您传递的关键字自变量的键之一与位置自变量相似(具有相同的字符串名称),则也会发生此错误。

>>> class Foo():
...     def bar(self, bar, **kwargs):
...             print(bar)
... 
>>> kwgs = {"bar":"Barred", "jokes":"Another key word argument"}
>>> myfoo = Foo()
>>> myfoo.bar("fire", **kwgs)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar() got multiple values for argument 'bar'
>>> 

“开火”已被纳入“酒吧”论点。但是在kwargs中还存在另一个“禁止”论点。

您必须先将关键字参数从kwargs中删除,然后再将其传递给方法。

This error can also happen if you pass a key word argument for which one of the keys is similar (has same string name) to a positional argument.

>>> class Foo():
...     def bar(self, bar, **kwargs):
...             print(bar)
... 
>>> kwgs = {"bar":"Barred", "jokes":"Another key word argument"}
>>> myfoo = Foo()
>>> myfoo.bar("fire", **kwgs)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar() got multiple values for argument 'bar'
>>> 

“fire” has been accepted into the ‘bar’ argument. And yet there is another ‘bar’ argument present in kwargs.

You would have to remove the keyword argument from the kwargs before passing it to the method.


回答 6

如果您使用jquery ajax的URL反向到不包含’request’参数的函数,则这也可能在Django中发生

$.ajax({
  url: '{{ url_to_myfunc }}',
});


def myfunc(foo, bar):
    ...

Also this can happen in Django if you are using jquery ajax to url that reverses to a function that doesn’t contain ‘request’ parameter

$.ajax({
  url: '{{ url_to_myfunc }}',
});


def myfunc(foo, bar):
    ...

如何在Python中获取实例变量?

问题:如何在Python中获取实例变量?

Python中是否有内置方法来获取所有类的实例变量的数组?例如,如果我有以下代码:

class hi:
  def __init__(self):
    self.ii = "foo"
    self.kk = "bar"

有没有办法让我做到这一点:

>>> mystery_method(hi)
["ii", "kk"]

编辑:我最初是错误地要求类变量。

Is there a built-in method in Python to get an array of all a class’ instance variables? For example, if I have this code:

class hi:
  def __init__(self):
    self.ii = "foo"
    self.kk = "bar"

Is there a way for me to do this:

>>> mystery_method(hi)
["ii", "kk"]

Edit: I originally had asked for class variables erroneously.


回答 0

每个对象都有一个__dict__变量,其中包含所有变量及其值。

试试这个

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()

Every object has a __dict__ variable containing all the variables and its values in it.

Try this

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()

回答 1

使用vars()

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2

vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']

Use vars()

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2

vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']

回答 2

通常,仅给定一个类就不能获得实例属性,至少不能不实例化该类。但是,您可以获取给定实例的实例属性,也可以获取给定类的类属性。请参阅“检查”模块。您无法获得实例属性的列表,因为实例实际上可以将任何东西作为属性,而且-如您的示例中所示-创建它们的通常方法是只在__init__方法中对其进行分配。

exceptions是您的类使用插槽,插槽是类允许实例具有的固定属性列表。插槽在http://www.python.org/2.2.3/descrintro.html中进行了说明,但是插槽存在各种陷阱。它们会影响内存布局,因此多重继承可能会出现问题,并且一般而言,继承也必须考虑插槽。

You normally can’t get instance attributes given just a class, at least not without instantiating the class. You can get instance attributes given an instance, though, or class attributes given a class. See the ‘inspect’ module. You can’t get a list of instance attributes because instances really can have anything as attribute, and — as in your example — the normal way to create them is to just assign to them in the __init__ method.

An exception is if your class uses slots, which is a fixed list of attributes that the class allows instances to have. Slots are explained in http://www.python.org/2.2.3/descrintro.html, but there are various pitfalls with slots; they affect memory layout, so multiple inheritance may be problematic, and inheritance in general has to take slots into account, too.


回答 3

Vars()和dict方法都将适用于OP发布的示例,但不适用于“松散”定义的对象,例如:

class foo:
  a = 'foo'
  b = 'bar'

要打印所有不可调用的属性,可以使用以下功能:

def printVars(object):
    for i in [v for v in dir(object) if not callable(getattr(object,v))]:
        print '\n%s:' % i
        exec('print object.%s\n\n') % i

Both the Vars() and dict methods will work for the example the OP posted, but they won’t work for “loosely” defined objects like:

class foo:
  a = 'foo'
  b = 'bar'

To print all non-callable attributes, you can use the following function:

def printVars(object):
    for i in [v for v in dir(object) if not callable(getattr(object,v))]:
        print '\n%s:' % i
        exec('print object.%s\n\n') % i

回答 4

您还可以使用以下方法测试对象是否具有特定变量:

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")

You can also test if an object has a specific variable with:

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")

回答 5

您的示例显示了“实例变量”,而不是真正的类变量。

查找hi_obj.__class__.__dict__.items()类变量,以及其他其他类成员,例如成员函数和包含的模块。

class Hi( object ):
    class_var = ( 23, 'skidoo' ) # class variable
    def __init__( self ):
        self.ii = "foo" # instance variable
        self.jj = "bar"

类变量由该类的所有实例共享。

Your example shows “instance variables”, not really class variables.

Look in hi_obj.__class__.__dict__.items() for the class variables, along with other other class members like member functions and the containing module.

class Hi( object ):
    class_var = ( 23, 'skidoo' ) # class variable
    def __init__( self ):
        self.ii = "foo" # instance variable
        self.jj = "bar"

Class variables are shared by all instances of the class.


回答 6

建议

>>> print vars.__doc__
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

换句话说,它实际上只是包装__dict__

Suggest

>>> print vars.__doc__
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

In otherwords, it essentially just wraps __dict__


回答 7

尽管不是直接回答OP问题,但是有一种很不错的方法可以找出函数范围内的变量。看一下这段代码:

>>> def f(x, y):
    z = x**2 + y**2
    sqrt_z = z**.5
    return sqrt_z

>>> f.func_code.co_varnames
('x', 'y', 'z', 'sqrt_z')
>>> 

func_code属性中包含各种有趣的东西。它可以让您做一些很酷的事情。这是我如何使用此示例:

def exec_command(self, cmd, msg, sig):

    def message(msg):
        a = self.link.process(self.link.recieved_message(msg))
        self.exec_command(*a)

    def error(msg):
        self.printer.printInfo(msg)

    def set_usrlist(msg):
        self.client.connected_users = msg

    def chatmessage(msg):
        self.printer.printInfo(msg)

    if not locals().has_key(cmd): return
    cmd = locals()[cmd]

    try:
        if 'sig' in cmd.func_code.co_varnames and \
                       'msg' in cmd.func_code.co_varnames: 
            cmd(msg, sig)
        elif 'msg' in cmd.func_code.co_varnames: 
            cmd(msg)
        else:
            cmd()
    except Exception, e:
        print '\n-----------ERROR-----------'
        print 'error: ', e
        print 'Error proccessing: ', cmd.__name__
        print 'Message: ', msg
        print 'Sig: ', sig
        print '-----------ERROR-----------\n'

Although not directly an answer to the OP question, there is a pretty sweet way of finding out what variables are in scope in a function. take a look at this code:

>>> def f(x, y):
    z = x**2 + y**2
    sqrt_z = z**.5
    return sqrt_z

>>> f.func_code.co_varnames
('x', 'y', 'z', 'sqrt_z')
>>> 

The func_code attribute has all kinds of interesting things in it. It allows you todo some cool stuff. Here is an example of how I have have used this:

def exec_command(self, cmd, msg, sig):

    def message(msg):
        a = self.link.process(self.link.recieved_message(msg))
        self.exec_command(*a)

    def error(msg):
        self.printer.printInfo(msg)

    def set_usrlist(msg):
        self.client.connected_users = msg

    def chatmessage(msg):
        self.printer.printInfo(msg)

    if not locals().has_key(cmd): return
    cmd = locals()[cmd]

    try:
        if 'sig' in cmd.func_code.co_varnames and \
                       'msg' in cmd.func_code.co_varnames: 
            cmd(msg, sig)
        elif 'msg' in cmd.func_code.co_varnames: 
            cmd(msg)
        else:
            cmd()
    except Exception, e:
        print '\n-----------ERROR-----------'
        print 'error: ', e
        print 'Error proccessing: ', cmd.__name__
        print 'Message: ', msg
        print 'Sig: ', sig
        print '-----------ERROR-----------\n'

回答 8

建立在dmark的答案上以获取以下内容,如果您希望获得sprintf的等效功能,这将很有用,并希望能对某人有所帮助…

def sprint(object):
    result = ''
    for i in [v for v in dir(object) if not callable(getattr(object, v)) and v[0] != '_']:
        result += '\n%s:' % i + str(getattr(object, i, ''))
    return result

built on dmark’s answer to get the following, which is useful if you want the equiv of sprintf and hopefully will help someone…

def sprint(object):
    result = ''
    for i in [v for v in dir(object) if not callable(getattr(object, v)) and v[0] != '_']:
        result += '\n%s:' % i + str(getattr(object, i, ''))
    return result

回答 9

有时您想根据公共/私有变量来过滤列表。例如

def pub_vars(self):
    """Gives the variable names of our instance we want to expose
    """
    return [k for k in vars(self) if not k.startswith('_')]

Sometimes you want to filter the list based on public/private vars. E.g.

def pub_vars(self):
    """Gives the variable names of our instance we want to expose
    """
    return [k for k in vars(self) if not k.startswith('_')]

在Python中,什么时候应该使用函数而不是方法?

问题:在Python中,什么时候应该使用函数而不是方法?

Python的Zen指出,只有一种方法可以做事情-但我经常遇到决定何时使用函数以及何时使用方法的问题。

让我们举一个简单的例子-ChessBoard对象。假设我们需要某种方式使董事会上所有合法的King举动均可用。我们是否编写ChessBoard.get_king_moves()或get_king_moves(chess_board)?

这是我看过的一些相关问题:

我得到的答案基本上没有定论:

为什么Python使用方法来实现某些功能(例如list.index()),却使用其他方法(例如len(list))呢?

主要原因是历史。函数用于那些对一组类型通用的操作,即使对于根本没有方法的对象(例如元组),这些操作也可以使用。使用Python的功能特性(map(),apply()等)时,具有可以轻松应用于对象的不定形集合的函数也很方便。

实际上,将len(),max(),min()实现为内置函数实际上比将它们实现为每种类型的方法要少。人们可能会质疑个别情况,但这是Python的一部分,现在进行这样的基本更改为时已晚。必须保留功能以避免大量代码损坏。

尽管很有趣,但是上面并没有真正说明采用哪种策略。

这是原因之一-使用自定义方法,开发人员可以自由选择其他方法名称,例如getLength(),length(),getlength()或其他名称。Python强制执行严格的命名,以便可以使用通用函数len()。

稍微有趣一点。我认为函数在某种意义上是接口的Pythonic版本。

最后,来自Guido本人

谈论能力/接口使我想到了一些“流氓”特殊方法名称。在《语言参考》中,它说:“类可以通过定义具有特殊名称的方法来实现某些由特殊语法调用的操作(例如算术运算或下标和切片)。” 但是,所有这些带有特殊名称的方法(例如__len__或)__unicode__似乎都是为内置函数的利益提供的,而不是为了支持语法。大概在基于接口的Python中,这些方法将在ABC上变成常规命名的方法,因此 __len__将成为

class container:
  ...
  def len(self):
    raise NotImplemented

虽然,再想一想,我不明白为什么所有的句法运算都不会仅仅在特定的ABC上调用适当的通常命名的方法。“ <”举例来说,大概会调用“ object.lessthan”(或者是“ comparable.lessthan“)。因此,另一个好处是能够使Python摆脱这种乱七八糟的名字,对我而言这似乎是HCI的改进

嗯 我不确定我是否同意(图:-)。

我首先要解释“ Python基本原理”的两个方面。

首先,出于HCI的原因,我选择了len(x)而不是x.len()(def __len__()后来出现了)。实际上,两个HCI相互交织在一起:

(a)对于某些运算,前缀表示法比后缀读得更好-前缀(和infix!)操作在数学中具有悠久的传统,喜欢在视觉上帮助数学家思考问题的表示法。比较与我们改写像公式简单x*(a+b)x*a + x*b使用原始OO符号做同样的事情的笨拙。

(b)当我读到说的代码时,len(x)知道那是在问某物的长度。这告诉我两件事:结果是整数,参数是某种容器。相反,当我阅读本文时x.len(),我必须已经知道这x是一种实现接口或从具有standard的类继承的容器len()。当未实现映射的类具有get()keys() 方法,或者不是文件的某些具有方法时,我们有时会感到困惑write()

用另一种方式说同样的事情,我将’len’视为内置 操作。我不想失去那个。我不能肯定地说出您是否是那样的意思,但是“ def len(self):…”当然听起来像您想将其降级为普通方法。我对此坚决为-1。

我答应解释的Python基本原理的第二点是为什么我选择了特殊的外观__special__而不是仅仅 选择外观的原因special。我期待类可能要覆盖的许多操作,一些标准(例如__add____getitem__),某些不是那么标准(例如,泡菜__reduce__很长一段时间都不支持C代码)。我不希望这些特殊操作使用普通的方法名称,因为那样的话,预先存在的类或用户没有为所有特殊方法存储百科全书的用户编写的类可能会意外地定义它们并非要实现的操作,可能会造成灾难性的后果。伊万·科斯蒂奇(IvanKrstić)在他的信息中对此进行了更为简洁的解释,在我将所有这些内容写完之后,这些信息才得以体现。

—Guido van Rossum(主页:http ://www.python.org/~guido/ )

我对此的理解是,在某些情况下,前缀表示法更有意义(即,从语言的角度来看,Duck.quack比quack(Duck)更有意义。)而且,该函数还允许使用“接口”。

在这种情况下,我的猜测是仅基于Guido的第一点实现get_king_moves。但这仍然存在很多悬而未决的问题,例如使用类似的push和pop方法实现堆栈和队列类-它们应该是函数还是方法?(在这里我会猜测功能,因为我真的很想发信号通知推送界面)

TLDR:有人可以解释决定何时使用函数还是方法的策略是什么?

The Zen of Python states that there should only be one way to do things- yet frequently I run into the problem of deciding when to use a function versus when to use a method.

Let’s take a trivial example- a ChessBoard object. Let’s say we need some way to get all the legal King moves available on the board. Do we write ChessBoard.get_king_moves() or get_king_moves(chess_board)?

Here are some related questions I looked at:

The answers I got were largely inconclusive:

Why does Python use methods for some functionality (e.g. list.index()) but functions for other (e.g. len(list))?

The major reason is history. Functions were used for those operations that were generic for a group of types and which were intended to work even for objects that didn’t have methods at all (e.g. tuples). It is also convenient to have a function that can readily be applied to an amorphous collection of objects when you use the functional features of Python (map(), apply() et al).

In fact, implementing len(), max(), min() as a built-in function is actually less code than implementing them as methods for each type. One can quibble about individual cases but it’s a part of Python, and it’s too late to make such fundamental changes now. The functions have to remain to avoid massive code breakage.

While interesting, the above doesn’t really say much as to what strategy to adopt.

This is one of the reasons – with custom methods, developers would be free to choose a different method name, like getLength(), length(), getlength() or whatsoever. Python enforces strict naming so that the common function len() can be used.

Slightly more interesting. My take is that functions are in a sense, the Pythonic version of interfaces.

Lastly, from Guido himself:

Talking about the Abilities/Interfaces made me think about some of our “rogue” special method names. In the Language Reference, it says, “A class can implement certain operations that are invoked by special syntax (such as arithmetic operations or subscripting and slicing) by defining methods with special names.” But there are all these methods with special names like __len__ or __unicode__ which seem to be provided for the benefit of built-in functions, rather than for support of syntax. Presumably in an interface-based Python, these methods would turn into regularly-named methods on an ABC, so that __len__ would become

class container:
  ...
  def len(self):
    raise NotImplemented

Though, thinking about it some more, I don’t see why all syntactic operations wouldn’t just invoke the appropriate normally-named method on a specific ABC. “<“, for instance, would presumably invoke “object.lessthan” (or perhaps “comparable.lessthan“). So another benefit would be the ability to wean Python away from this mangled-name oddness, which seems to me an HCI improvement.

Hm. I’m not sure I agree (figure that :-).

There are two bits of “Python rationale” that I’d like to explain first.

First of all, I chose len(x) over x.len() for HCI reasons (def __len__() came much later). There are two intertwined reasons actually, both HCI:

(a) For some operations, prefix notation just reads better than postfix — prefix (and infix!) operations have a long tradition in mathematics which likes notations where the visuals help the mathematician thinking about a problem. Compare the easy with which we rewrite a formula like x*(a+b) into x*a + x*b to the clumsiness of doing the same thing using a raw OO notation.

(b) When I read code that says len(x) I know that it is asking for the length of something. This tells me two things: the result is an integer, and the argument is some kind of container. To the contrary, when I read x.len(), I have to already know that x is some kind of container implementing an interface or inheriting from a class that has a standard len(). Witness the confusion we occasionally have when a class that is not implementing a mapping has a get() or keys() method, or something that isn’t a file has a write() method.

Saying the same thing in another way, I see ‘len’ as a built-in operation. I’d hate to lose that. I can’t say for sure whether you meant that or not, but ‘def len(self): …’ certainly sounds like you want to demote it to an ordinary method. I’m strongly -1 on that.

The second bit of Python rationale I promised to explain is the reason why I chose special methods to look __special__ and not merely special. I was anticipating lots of operations that classes might want to override, some standard (e.g. __add__ or __getitem__), some not so standard (e.g. pickle’s __reduce__ for a long time had no support in C code at all). I didn’t want these special operations to use ordinary method names, because then pre-existing classes, or classes written by users without an encyclopedic memory for all the special methods, would be liable to accidentally define operations they didn’t mean to implement, with possibly disastrous consequences. Ivan Krstić explained this more concise in his message, which arrived after I’d written all this up.

— –Guido van Rossum (home page: http://www.python.org/~guido/)

My understanding of this is that in certain cases, prefix notation just makes more sense (ie, Duck.quack makes more sense than quack(Duck) from a linguistic standpoint.) and again, the functions allow for “interfaces”.

In such a case, my guess would be to implement get_king_moves based solely on Guido’s first point. But that still leaves a lot of open questions regarding say, implementing a stack and queue class with similar push and pop methods- should they be functions or methods? (here I would guess functions, because I really want to signal a push-pop interface)

TLDR: Can someone explain what the strategy for deciding when to use functions vs. methods should be?


回答 0

我的一般规则是- 是在对象上执行还是由对象执行操作?

如果是由对象完成的,则应该是成员操作。如果它也可以应用于其他事物,或者由对象的其他事物完成,那么它应该是一个函数(或其他事物的成员)。

引入编程时,传统上(尽管实现不正确)以现实世界中的对象(例如汽车)来描述对象。您提到了一只鸭子,所以让我们开始吧。

class duck: 
    def __init__(self):pass
    def eat(self, o): pass 
    def crap(self) : pass
    def die(self)
    ....

在“对象是真实事物”类比的上下文中,为对象可以执行的任何操作添加类方法是“正确的”。所以说我想杀死一只鸭子,是否要在鸭子上添加.kill()?不,据我所知,动物不会自杀。因此,如果我想杀死一只鸭子,我应该这样做:

def kill(o):
    if isinstance(o, duck):
        o.die()
    elif isinstance(o, dog):
        print "WHY????"
        o.die()
    elif isinstance(o, nyancat):
        raise Exception("NYAN "*9001)
    else:
       print "can't kill it."

远离这种类比,为什么我们要使用方法和类?因为我们要包含数据并希望以某种方式构造我们的代码,以便将来可以重用和扩展它。这使我们想到了面向对象设计非常重要的封装概念。

封装原理实际上就是它的含义:作为设计人员,您应该隐藏有关实现和类内部的所有内容,对于任何用户或其他开发人员而言,都不一定要访问它。因为我们处理类的实例,所以这简化为“ 对该实例至关重要的操作”。如果操作不是实例特定的,则它不应是成员函数。

TL; DR:@Bryan说了什么。如果它在实例上运行并且需要访问类实例内部的数据,则它应该是成员函数。

My general rule is this – is the operation performed on the object or by the object?

if it is done by the object, it should be a member operation. If it could apply to other things too, or is done by something else to the object then it should be a function (or perhaps a member of something else).

When introducing programming, it is traditional (albeit implementation incorrect) to describe objects in terms of real-world objects such as cars. You mention a duck, so let’s go with that.

class duck: 
    def __init__(self):pass
    def eat(self, o): pass 
    def crap(self) : pass
    def die(self)
    ....

In the context of the “objects are real things” analogy, it is “correct” to add a class method for anything which the object can do. So say I want to kill off a duck, do I add a .kill() to the duck? No… as far as I know animals do not commit suicide. Therefore if I want to kill a duck I should do this:

def kill(o):
    if isinstance(o, duck):
        o.die()
    elif isinstance(o, dog):
        print "WHY????"
        o.die()
    elif isinstance(o, nyancat):
        raise Exception("NYAN "*9001)
    else:
       print "can't kill it."

Moving away from this analogy, why do we use methods and classes? Because we want to contain data and hopefully structure our code in a manner such that it will be reusable and extensible in the future. This brings us to the notion of encapsulation which is so dear to OO design.

The encapsulation principal is really what this comes down to: as a designer you should hide everything about the implementation and class internals which it is not absolutely necessarily for any user or other developer to access. Because we deal with instances of classes, this reduces to “what operations are crucial on this instance“. If an operation is not instance specific, then it should not be a member function.

TL;DR: what @Bryan said. If it operates on an instance and needs to access data which is internal to the class instance, it should be a member function.


回答 1

在需要以下情况时,请使用类:

1)从实现细节中隔离调用代码-利用抽象封装

2)当您想替代其他对象时-利用多态性

3)当您想为相似的对象重用代码时-利用继承

将函数用于对许多不同的对象类型有意义的调用-例如,内置的lenrepr函数适用于多种对象。

话虽如此,选择有时取决于口味。考虑一下最适合常规通话的方式和可读性。例如,这将是更好的(x.sin()**2 + y.cos()**2).sqrt()还是sqrt(sin(x)**2 + cos(y)**2)

Use a class when you want to:

1) Isolate calling code from implementation details — taking advantage of abstraction and encapsulation.

2) When you want to be substitutable for other objects — taking advantage of polymorphism.

3) When you want to reuse code for similar objects — taking advantage of inheritance.

Use a function for calls that make sense across many different object types — for example, the builtin len and repr functions apply to many kinds of objects.

That being said, the choice sometimes comes down to a matter of taste. Think in terms of what is most convenient and readable for typical calls. For example, which would be better (x.sin()**2 + y.cos()**2).sqrt() or sqrt(sin(x)**2 + cos(y)**2)?


回答 2

这是一条简单的经验法则:如果代码作用于对象的单个实例,请使用一种方法。甚至更好:除非有充分的理由将其编写为函数,否则请使用一种方法。

在您的特定示例中,您希望它看起来像这样:

chessboard = Chessboard()
...
chessboard.get_king_moves()

不要过度考虑。始终使用方法,直到您对自己说“将此方法定义为没有意义”为止,在这种情况下,您可以创建函数。

Here’s a simple rule of thumb: if the code acts upon a single instance of an object, use a method. Even better: use a method unless there is a compelling reason to write it as a function.

In your specific example, you want it to look like this:

chessboard = Chessboard()
...
chessboard.get_king_moves()

Don’t over think it. Always use methods until the point comes where you say to yourself “it doesn’t make sense to make this a method”, in which case you can make a function.


回答 3

我通常认为一个物体像一个人。

属性是人物的姓名,身高,鞋子的大小等。

方法功能是人可以执行的操作。

如果该操作只能由任何其他人完成,而又不需要该特定人独有的任何东西(并且无需更改该特定人的任何东西),那么它就是一个函数,应该这样编写。

如果某项操作正在对该人进行操作(例如进餐,散步等),或者需要该人独特的操作(例如跳舞,写书等),则应采用一种方法

当然,将其转换为您正在使用的特定对象并不总是一件容易的事,但是我发现这是思考它的好方法。

I usually think of an object like a person.

Attributes are the person’s name, height, shoe size, etc.

Methods and functions are operations that the person can perform.

If the operation could be done by just any ol’ person, without requiring anything unique to this one specific person (and without changing anything on this one specific person), then it’s a function and should be written as such.

If an operation is acting upon the person (e.g. eating, walking, …) or requires something unique to this person to get involved (like dancing, writing a book, …), then it should be a method.

Of course, it is not always trivial to translate this into the specific object you’re working with, but I find it is a good way to think of it.


回答 4

通常,我使用类来为某件事实现一组逻辑功能,以便在程序的其余部分中,我可以对事物进行推理,而不必担心构成其实现的所有小问题。

凡是是那核心抽象的一部分“你可以用做什么事情 ”通常应该是一个方法。这通常包括可以改变一切的事情,作为内部数据状态通常被认为是私人,而不是“你可以用做什么逻辑思想的一部分的事情 ”。

当您进行更高级别的操作时,特别是如果它们涉及多个事物,我发现它们通常最自然地表示为函数,前提是它们可以从事物的公共抽象中构建而无需特殊的内部访问(除非它们re方法)。这具有很大的优势,当我决定完全重写我工作方式的内部结构(无需更改接口)时,我只有一小部分核心方法可以重写,然后使用这些方法编写所有外部函数将工作。我发现坚持认为与类X有关的所有操作都是类X上的方法会导致类过于复杂。

这取决于我正在编写的代码。对于某些程序,我将它们建模为对象的集合,这些对象的相互作用引起了程序的行为。在这里,最重要的功能紧密耦合到单个对象,因此是在方法中实现的,其中包含实用功能。对于其他程序,最重要的东西是一组操作数据的函数,而类仅用于实现由这些函数操纵的自然“鸭子类型”。

Generally I use classes to implement a logical set of capabilities for some thing, so that in the rest of my program I can reason about the thing, not having to worry about all the little concerns that make up its implementation.

Anything that’s part of that core abstraction of “what you can do with a thing” should usually be a method. This generally includes everything that can alter a thing, as the internal data state is usually considered private and not part of the logical idea of “what you can do with a thing“.

When you come to higher level operations, especially if they involve multiple things, I find they are usually most naturally expressed as functions, if they can be built out of the public abstraction of a thing without needing special access to the internals (unless they’re methods of some other object). This has the big advantage that when I decide to completely rewrite the internals of how my thing works (without changing the interface), I just have a small core set of methods to rewrite, and then all the external functions written in terms of those methods will Just Work. I find that insisting that all operations to do with class X are methods on class X leads to over-complicated classes.

It depends on the code I’m writing though. For some programs I model them as a collection of objects whose interactions give rise to the behavior of the program; here most important functionality is closely coupled to a single object, and so is implemented in methods, with a scattering of utility functions. For other programs the most important stuff is a set of functions that manipulate data, and classes are in use only to implement the natural “duck types” that are manipulated by the functions.


回答 5

您可能会说,“面对模棱两可,拒绝猜测的诱惑”。

但是,这甚至不是猜测。您绝对可以确保两种方法的结果相同,因为它们可以解决您的问题。

我相信,采用多种方式实现目标只是一件好事。与其他用户一样,我要谦虚地告诉您,就语言而言,采用“味道更好” /感觉更直观的方法。

You may say that, “in the face of ambiguity, refuse the temptation to guess”.

However, it’s not even a guess. You’re absolutely sure that the outcomes of both approaches are the same in that they solve your problem.

I believe it is only a good thing to have multiple ways to accomplishing goals. I’d humbly tell you, as other users did already, to employ whichever “tastes better” / feels more intuitive, in terms of language.


Python:绑定未绑定方法?

问题:Python:绑定未绑定方法?

在Python中,有没有办法绑定未绑定的方法而不调用它?

我正在编写一个wxPython程序,对于某个类,我决定将所有按钮的数据分组为一个类级别的元组列表是很不错的,如下所示:

class MyWidget(wx.Window):
    buttons = [("OK", OnOK),
               ("Cancel", OnCancel)]

    # ...

    def Setup(self):
        for text, handler in MyWidget.buttons:

            # This following line is the problem line.
            b = wx.Button(parent, label=text).Bind(wx.EVT_BUTTON, handler)

问题是,因为所有的值handler都是未绑定方法,所以我的程序爆炸得很厉害,我哭了。

我正在网上寻找解决方案,该方案应该是一个相对简单,可解决的问题。不幸的是我找不到任何东西。现在,我正在functools.partial解决此问题,但是没有人知道是否存在一种干净,健康,Pythonic的方式将未绑定的方法绑定到实例并继续传递它而不调用它吗?

In Python, is there a way to bind an unbound method without calling it?

I am writing a wxPython program, and for a certain class I decided it’d be nice to group the data of all of my buttons together as a class-level list of tuples, like so:

class MyWidget(wx.Window):
    buttons = [("OK", OnOK),
               ("Cancel", OnCancel)]

    # ...

    def Setup(self):
        for text, handler in MyWidget.buttons:

            # This following line is the problem line.
            b = wx.Button(parent, label=text).Bind(wx.EVT_BUTTON, handler)

The problem is, since all of the values of handler are unbound methods, my program explodes in a spectacular blaze and I weep.

I was looking around online for a solution to what seems like should be a relatively straightforward, solvable problem. Unfortunately I couldn’t find anything. Right now, I’m using functools.partial to work around this, but does anyone know if there’s a clean-feeling, healthy, Pythonic way to bind an unbound method to an instance and continue passing it around without calling it?


回答 0

所有函数也是描述符,因此您可以通过调用它们的__get__方法来绑定它们:

bound_handler = handler.__get__(self, MyWidget)

这是R. Hettinger 关于描述符的出色指南


作为一个独立的例子,请参考Keith的 评论

def bind(instance, func, as_name=None):
    """
    Bind the function *func* to *instance*, with either provided name *as_name*
    or the existing name of *func*. The provided *func* should accept the 
    instance as the first argument, i.e. "self".
    """
    if as_name is None:
        as_name = func.__name__
    bound_method = func.__get__(instance, instance.__class__)
    setattr(instance, as_name, bound_method)
    return bound_method

class Thing:
    def __init__(self, val):
        self.val = val

something = Thing(21)

def double(self):
    return 2 * self.val

bind(something, double)
something.double()  # returns 42

All functions are also descriptors, so you can bind them by calling their __get__ method:

bound_handler = handler.__get__(self, MyWidget)

Here’s R. Hettinger’s excellent guide to descriptors.


As a self-contained example pulled from Keith’s comment:

def bind(instance, func, as_name=None):
    """
    Bind the function *func* to *instance*, with either provided name *as_name*
    or the existing name of *func*. The provided *func* should accept the 
    instance as the first argument, i.e. "self".
    """
    if as_name is None:
        as_name = func.__name__
    bound_method = func.__get__(instance, instance.__class__)
    setattr(instance, as_name, bound_method)
    return bound_method

class Thing:
    def __init__(self, val):
        self.val = val

something = Thing(21)

def double(self):
    return 2 * self.val

bind(something, double)
something.double()  # returns 42

回答 1

可以使用types.MethodType干净地完成此操作。例:

import types

def f(self): print self

class C(object): pass

meth = types.MethodType(f, C(), C) # Bind f to an instance of C
print meth # prints <bound method C.f of <__main__.C object at 0x01255E90>>

This can be done cleanly with types.MethodType. Example:

import types

def f(self): print self

class C(object): pass

meth = types.MethodType(f, C(), C) # Bind f to an instance of C
print meth # prints <bound method C.f of <__main__.C object at 0x01255E90>>

回答 2

创建一个带有self的闭包在技术上不会绑定该函数,但这是解决相同(或非常相似)潜在问题的另一种方法。这是一个简单的例子:

self.method = (lambda self: lambda args: self.do(args))(self)

Creating a closure with self in it will not technically bind the function, but it is an alternative way of solving the same (or very similar) underlying problem. Here’s a trivial example:

self.method = (lambda self: lambda args: self.do(args))(self)

回答 3

这将绑定selfhandler

bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)

这是通过将self第一个参数传递给函数来实现的。object.function()只是语法糖function(object)

This will bind self to handler:

bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)

This works by passing self as the first argument to the function. object.function() is just syntactic sugar for function(object).


回答 4

晚了,但是我来这里有一个类似的问题:我有一个类方法和一个实例,并且想要将该实例应用于该方法。

冒着过于简化OP问题的风险,我最终做了一些不太神秘的事情,这可能会对到这里来的其他人有用(注意:我正在使用Python 3 – YMMV工作)。

考虑这个简单的类:

class Foo(object):

    def __init__(self, value):
        self._value = value

    def value(self):
        return self._value

    def set_value(self, value):
        self._value = value

这是您可以使用的方法:

>>> meth = Foo.set_value   # the method
>>> a = Foo(12)            # a is an instance with value 12
>>> meth(a, 33)            # apply instance and method
>>> a.value()              # voila - the method was called
33

Late to the party, but I came here with a similar question: I have a class method and an instance, and want to apply the instance to the method.

At the risk of oversimplifying the OP’s question, I ended up doing something less mysterious that may be useful to others who arrive here (caveat: I’m working in Python 3 — YMMV).

Consider this simple class:

class Foo(object):

    def __init__(self, value):
        self._value = value

    def value(self):
        return self._value

    def set_value(self, value):
        self._value = value

Here’s what you can do with it:

>>> meth = Foo.set_value   # the method
>>> a = Foo(12)            # a is an instance with value 12
>>> meth(a, 33)            # apply instance and method
>>> a.value()              # voila - the method was called
33

Python __call__特殊方法的实际示例

问题:Python __call__特殊方法的实际示例

我知道__call__调用类的实例时会触发类中的方法。但是,我不知道何时可以使用这种特殊方法,因为一个人可以简单地创建一个新方法并执行在__call__方法中完成的相同操作,而无需调用实例,而可以调用该方法。

如果有人给我这种特殊方法的实际用法,我将不胜感激。

I know that __call__ method in a class is triggered when the instance of a class is called. However, I have no idea when I can use this special method, because one can simply create a new method and perform the same operation done in __call__ method and instead of calling the instance, you can call the method.

I would really appreciate it if someone gives me a practical usage of this special method.


回答 0

Django表单模块__call__很好地使用了方法来实现用于表单验证的一致API。您可以在Django中将自己的验证器作为函数编写。

def custom_validator(value):
    #your validation logic

Django有一些默认的内置验证器,例如电子邮件验证器,URL验证器等,它们大体上属于RegEx验证器。为了清晰地实现这些,Django求助于可调用类(而不是函数)。它在RegexValidator中实现默认的Regex验证逻辑,然后扩展这些类以进行其他验证。

class RegexValidator(object):
    def __call__(self, value):
        # validation logic

class URLValidator(RegexValidator):
    def __call__(self, value):
        super(URLValidator, self).__call__(value)
        #additional logic

class EmailValidator(RegexValidator):
    # some logic

现在,可以使用相同的语法调用自定义函数和内置的EmailValidator。

for v in [custom_validator, EmailValidator()]:
    v(value) # <-----

如您所见,Django中的此实现类似于其他人在下面的答案中解释的实现。可以通过其他任何方式实现吗?您可以,但是恕我直言,对于像Django这样的大型框架,它不那么易读或易于扩展。

Django forms module uses __call__ method nicely to implement a consistent API for form validation. You can write your own validator for a form in Django as a function.

def custom_validator(value):
    #your validation logic

Django has some default built-in validators such as email validators, url validators etc., which broadly fall under the umbrella of RegEx validators. To implement these cleanly, Django resorts to callable classes (instead of functions). It implements default Regex Validation logic in a RegexValidator and then extends these classes for other validations.

class RegexValidator(object):
    def __call__(self, value):
        # validation logic

class URLValidator(RegexValidator):
    def __call__(self, value):
        super(URLValidator, self).__call__(value)
        #additional logic

class EmailValidator(RegexValidator):
    # some logic

Now both your custom function and built-in EmailValidator can be called with the same syntax.

for v in [custom_validator, EmailValidator()]:
    v(value) # <-----

As you can see, this implementation in Django is similar to what others have explained in their answers below. Can this be implemented in any other way? You could, but IMHO it will not be as readable or as easily extensible for a big framework like Django.


回答 1

本示例使用备忘录,基本上将值存储在表(在这种情况下为字典)中,因此您以后可以查找它们,而无需重新计算它们。

在这里,我们使用带有__call__方法的简单类(通过可调用对象)来计算阶乘,而不是包含静态变量的阶乘函数(这在Python中是不可能的)。

class Factorial:
    def __init__(self):
        self.cache = {}
    def __call__(self, n):
        if n not in self.cache:
            if n == 0:
                self.cache[n] = 1
            else:
                self.cache[n] = n * self.__call__(n-1)
        return self.cache[n]

fact = Factorial()

现在,您拥有一个fact可以调用的对象,就像其他所有函数一样。例如

for i in xrange(10):                                                             
    print("{}! = {}".format(i, fact(i)))

# output
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880

而且它也是有状态的。

This example uses memoization, basically storing values in a table (dictionary in this case) so you can look them up later instead of recalculating them.

Here we use a simple class with a __call__ method to calculate factorials (through a callable object) instead of a factorial function that contains a static variable (as that’s not possible in Python).

class Factorial:
    def __init__(self):
        self.cache = {}
    def __call__(self, n):
        if n not in self.cache:
            if n == 0:
                self.cache[n] = 1
            else:
                self.cache[n] = n * self.__call__(n-1)
        return self.cache[n]

fact = Factorial()

Now you have a fact object which is callable, just like every other function. For example

for i in xrange(10):                                                             
    print("{}! = {}".format(i, fact(i)))

# output
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880

And it is also stateful.


回答 2

我发现它很有用,因为它允许我创建易于使用的API(您有一些需要一些特定参数的可调用对象),并且易于实现,因为您可以使用面向对象的实践。

以下是我昨天编写的代码,该代码使hashlib.foo散列整个文件而不是字符串的方法的版本变了:

# filehash.py
import hashlib


class Hasher(object):
    """
    A wrapper around the hashlib hash algorithms that allows an entire file to
    be hashed in a chunked manner.
    """
    def __init__(self, algorithm):
        self.algorithm = algorithm

    def __call__(self, file):
        hash = self.algorithm()
        with open(file, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), ''):
                hash.update(chunk)
        return hash.hexdigest()


md5    = Hasher(hashlib.md5)
sha1   = Hasher(hashlib.sha1)
sha224 = Hasher(hashlib.sha224)
sha256 = Hasher(hashlib.sha256)
sha384 = Hasher(hashlib.sha384)
sha512 = Hasher(hashlib.sha512)

此实现使我能够以类似于功能的方式使用hashlib.foo功能:

from filehash import sha1
print sha1('somefile.txt')

当然,我可以用其他方式实现它,但是在这种情况下,这似乎是一种简单的方法。

I find it useful because it allows me to create APIs that are easy to use (you have some callable object that requires some specific arguments), and are easy to implement because you can use Object Oriented practices.

The following is code I wrote yesterday that makes a version of the hashlib.foo methods that hash entire files rather than strings:

# filehash.py
import hashlib


class Hasher(object):
    """
    A wrapper around the hashlib hash algorithms that allows an entire file to
    be hashed in a chunked manner.
    """
    def __init__(self, algorithm):
        self.algorithm = algorithm

    def __call__(self, file):
        hash = self.algorithm()
        with open(file, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), ''):
                hash.update(chunk)
        return hash.hexdigest()


md5    = Hasher(hashlib.md5)
sha1   = Hasher(hashlib.sha1)
sha224 = Hasher(hashlib.sha224)
sha256 = Hasher(hashlib.sha256)
sha384 = Hasher(hashlib.sha384)
sha512 = Hasher(hashlib.sha512)

This implementation allows me to use the functions in a similar fashion to the hashlib.foo functions:

from filehash import sha1
print sha1('somefile.txt')

Of course I could have implemented it a different way, but in this case it seemed like a simple approach.


回答 3

__call__还用于在python中实现装饰器类。在这种情况下,当调用带有装饰器的方法时,将调用类的实例。

class EnterExitParam(object):

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

    def __call__(self, f):
        def new_f():
            print("Entering", f.__name__)
            print("p1=", self.p1)
            f()
            print("Leaving", f.__name__)
        return new_f


@EnterExitParam("foo bar")
def hello():
    print("Hello")


if __name__ == "__main__":
    hello()

__call__ is also used to implement decorator classes in python. In this case the instance of the class is called when the method with the decorator is called.

class EnterExitParam(object):

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

    def __call__(self, f):
        def new_f():
            print("Entering", f.__name__)
            print("p1=", self.p1)
            f()
            print("Leaving", f.__name__)
        return new_f


@EnterExitParam("foo bar")
def hello():
    print("Hello")


if __name__ == "__main__":
    hello()

回答 4

是的,当您知道要处理对象时,完全有可能(在很多情况下建议使用)显式方法调用。但是,有时您要处理期望可调用对象的代码-通常是函数,但是由于__call__您可以构建更复杂的对象,实例数据和更多方法来委派仍可调用的重复性任务等。

另外,有时您同时将对象用于复杂的任务(编写专用类是有意义的)和对象将用于简单任务(已存在于函数中,或者更容易编写为函数)使用。要拥有一个通用的接口,您要么必须编写用期望的接口包装这些函数的微型类,要么保留这些函数并使更复杂的对象可调用。让我们以线程为例。Thread来自标准库模块threading对象需要一个可调用的target参数(即在新线程中执行的操作)。对于可调用对象,您不仅可以使用函数,还可以传递其他对象,例如相对复杂的工作程序,该工作程序从其他线程获取要执行的任务并依次执行:

class Worker(object):
    def __init__(self, *args, **kwargs):
        self.queue = queue.Queue()
        self.args = args
        self.kwargs = kwargs

    def add_task(self, task):
        self.queue.put(task)

    def __call__(self):
        while True:
            next_action = self.queue.get()
            success = next_action(*self.args, **self.kwargs)
            if not success:
               self.add_task(next_action)

这只是我脑中浮现的一个例子,但我认为它已经足够复杂,足以保证上课。仅使用函数很难做到这一点,至少它需要返回两个函数,并且这种情况正在逐渐变得复杂。一个可以重命名__call__到别的东西,并通过绑定方法,但是这使得代码稍微不太明显的创建线程,并且不会增加任何价值。

Yes, when you know you’re dealing with objects, it’s perfectly possible (and in many cases advisable) to use an explicit method call. However, sometimes you deal with code that expects callable objects – typically functions, but thanks to __call__ you can build more complex objects, with instance data and more methods to delegate repetitive tasks, etc. that are still callable.

Also, sometimes you’re using both objects for complex tasks (where it makes sense to write a dedicated class) and objects for simple tasks (that already exist in functions, or are more easily written as functions). To have a common interface, you either have to write tiny classes wrapping those functions with the expected interface, or you keep the functions functions and make the more complex objects callable. Let’s take threads as example. The Thread objects from the standard libary module threading want a callable as target argument (i.e. as action to be done in the new thread). With a callable object, you are not restricted to functions, you can pass other objects as well, such as a relatively complex worker that gets tasks to do from other threads and executes them sequentially:

class Worker(object):
    def __init__(self, *args, **kwargs):
        self.queue = queue.Queue()
        self.args = args
        self.kwargs = kwargs

    def add_task(self, task):
        self.queue.put(task)

    def __call__(self):
        while True:
            next_action = self.queue.get()
            success = next_action(*self.args, **self.kwargs)
            if not success:
               self.add_task(next_action)

This is just an example off the top of my head, but I think it is already complex enough to warrant the class. Doing this only with functions is hard, at least it requires returning two functions and that’s slowly getting complex. One could rename __call__ to something else and pass a bound method, but that makes the code creating the thread slightly less obvious, and doesn’t add any value.


回答 5

基于类的装饰器__call__用来引用包装的函数。例如:

class Deco(object):
    def __init__(self,f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print args
        print kwargs
        self.f(*args, **kwargs)

Artima.com上的各种选项都有很好的描述

Class-based decorators use __call__ to reference the wrapped function. E.g.:

class Deco(object):
    def __init__(self,f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print args
        print kwargs
        self.f(*args, **kwargs)

There is a good description of the various options here at Artima.com


回答 6

IMHO __call__方法和闭包为我们提供了一种在Python中创建STRATEGY设计模式的自然方法。我们定义了一系列算法,将每个算法封装在一起,使其可互换,最后我们可以执行一组通用步骤,例如,计算文件的哈希值。

IMHO __call__ method and closures give us a natural way to create STRATEGY design pattern in Python. We define a family of algorithms, encapsulate each one, make them interchangeable and in the end we can execute a common set of steps and, for example, calculate a hash for a file.


回答 7

我只是偶然发现了一种我认为很美的__call__()音乐会__getattr__()。它允许您在对象内部隐藏JSON / HTTP /(however_serialized)API的多个级别。

__getattr__()部分负责迭代地返回相同类的修改后的实例,并一次填充一个以上的属性。然后,在用尽所有信息之后,__call__()接管您传入的所有参数。

例如,使用该模型,您可以进行调用,例如api.v2.volumes.ssd.update(size=20),最终导致对的PUT请求https://some.tld/api/v2/volumes/ssd/update

特定的代码是OpenStack中特定卷后端的块存储驱动程序,您可以在此处查看:https : //github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py

编辑:更新了链接以指向主修订。

I just stumbled upon a usage of __call__() in concert with __getattr__() which I think is beautiful. It allows you to hide multiple levels of a JSON/HTTP/(however_serialized) API inside an object.

The __getattr__() part takes care of iteratively returning a modified instance of the same class, filling in one more attribute at a time. Then, after all information has been exhausted, __call__() takes over with whatever arguments you passed in.

Using this model, you can for example make a call like api.v2.volumes.ssd.update(size=20), which ends up in a PUT request to https://some.tld/api/v2/volumes/ssd/update.

The particular code is a block storage driver for a certain volume backend in OpenStack, you can check it out here: https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py

EDIT: Updated the link to point to master revision.


回答 8

指定一个__metaclass__并覆盖该__call__方法,并让指定的元类的__new__方法返回该类的实例,中提琴表示您具有带有方法的“函数”。

Specify a __metaclass__ and override the __call__ method, and have the specified meta classes’ __new__ method return an instance of the class, viola you have a “function” with methods.


回答 9

我们可以使用__call__method来将其他类方法用作静态方法。

    class _Callable:
        def __init__(self, anycallable):
            self.__call__ = anycallable

    class Model:

        def get_instance(conn, table_name):

            """ do something"""

        get_instance = _Callable(get_instance)

    provs_fac = Model.get_instance(connection, "users")             

We can use __call__ method to use other class methods as static methods.

    class _Callable:
        def __init__(self, anycallable):
            self.__call__ = anycallable

    class Model:

        def get_instance(conn, table_name):

            """ do something"""

        get_instance = _Callable(get_instance)

    provs_fac = Model.get_instance(connection, "users")             

回答 10

一个常见的示例是__call__in functools.partial,这是一个简化的版本(Python> = 3.5):

class partial:
    """New function with partial application of the given arguments and keywords."""

    def __new__(cls, func, *args, **kwargs):
        if not callable(func):
            raise TypeError("the first argument must be callable")
        self = super().__new__(cls)

        self.func = func
        self.args = args
        self.kwargs = kwargs
        return self

    def __call__(self, *args, **kwargs):
        return self.func(*self.args, *args, **self.kwargs, **kwargs)

用法:

def add(x, y):
    return x + y

inc = partial(add, y=1)
print(inc(41))  # 42

One common example is the __call__ in functools.partial, here is a simplified version (with Python >= 3.5):

class partial:
    """New function with partial application of the given arguments and keywords."""

    def __new__(cls, func, *args, **kwargs):
        if not callable(func):
            raise TypeError("the first argument must be callable")
        self = super().__new__(cls)

        self.func = func
        self.args = args
        self.kwargs = kwargs
        return self

    def __call__(self, *args, **kwargs):
        return self.func(*self.args, *args, **self.kwargs, **kwargs)

Usage:

def add(x, y):
    return x + y

inc = partial(add, y=1)
print(inc(41))  # 42

回答 11

函数调用运算符。

class Foo:
    def __call__(self, a, b, c):
        # do something

x = Foo()
x(1, 2, 3)

__call__方法可用于重新定义的/重新初始化相同的对象。通过将参数传递给对象,还有助于将类的实例/对象用作函数。

The function call operator.

class Foo:
    def __call__(self, a, b, c):
        # do something

x = Foo()
x(1, 2, 3)

The __call__ method can be used to redefined/re-initialize the same object. It also facilitates the use of instances/objects of a class as functions by passing arguments to the objects.


回答 12

我发现使用可调用对象的好地方,那些定义__call__(),是使用Python中的函数式编程功能时,比如map()filter()reduce()

在普通函数或lambda函数上使用可调用对象的最佳时间是逻辑复杂且需要保留某些状态或使用其他未传递给__call__()函数的信息时。

以下是一些代码,它们使用可调用对象和,根据文件名的扩展名过滤文件名filter()

可调用:

import os

class FileAcceptor(object):
    def __init__(self, accepted_extensions):
        self.accepted_extensions = accepted_extensions

    def __call__(self, filename):
        base, ext = os.path.splitext(filename)
        return ext in self.accepted_extensions

class ImageFileAcceptor(FileAcceptor):
    def __init__(self):
        image_extensions = ('.jpg', '.jpeg', '.gif', '.bmp')
        super(ImageFileAcceptor, self).__init__(image_extensions)

用法:

filenames = [
    'me.jpg',
    'me.txt',
    'friend1.jpg',
    'friend2.bmp',
    'you.jpeg',
    'you.xml']

acceptor = ImageFileAcceptor()
image_filenames = filter(acceptor, filenames)
print image_filenames

输出:

['me.jpg', 'friend1.jpg', 'friend2.bmp', 'you.jpeg']

I find a good place to use callable objects, those that define __call__(), is when using the functional programming capabilities in Python, such as map(), filter(), reduce().

The best time to use a callable object over a plain function or a lambda function is when the logic is complex and needs to retain some state or uses other info that in not passed to the __call__() function.

Here’s some code that filters file names based upon their filename extension using a callable object and filter().

Callable:

import os

class FileAcceptor(object):
    def __init__(self, accepted_extensions):
        self.accepted_extensions = accepted_extensions

    def __call__(self, filename):
        base, ext = os.path.splitext(filename)
        return ext in self.accepted_extensions

class ImageFileAcceptor(FileAcceptor):
    def __init__(self):
        image_extensions = ('.jpg', '.jpeg', '.gif', '.bmp')
        super(ImageFileAcceptor, self).__init__(image_extensions)

Usage:

filenames = [
    'me.jpg',
    'me.txt',
    'friend1.jpg',
    'friend2.bmp',
    'you.jpeg',
    'you.xml']

acceptor = ImageFileAcceptor()
image_filenames = filter(acceptor, filenames)
print image_filenames

Output:

['me.jpg', 'friend1.jpg', 'friend2.bmp', 'you.jpeg']

回答 13

现在为时已晚,但我举一个例子。假设您有一Vector堂课和一Point堂课。两者都x, y作为位置参数。假设您要创建一个函数来移动要放在矢量上的点。

4个解决方案

  • put_point_on_vec(point, vec)

  • 使其成为vector类的方法。例如 my_vec.put_point(point)

  • 使它成为Point该类的一个方法。my_point.put_on_vec(vec)
  • Vector工具__call__,因此您可以像my_vec_instance(point)

这实际上是我正在研究的一些示例的一部分,该指南针对用数学解释的Dunder方法指南(我迟早要发布)。

我离开了移动点本身的逻辑,因为这不是这个问题的目的

This is too late but I’m giving an example. Imagine you have a Vector class and a Point class. Both take x, y as positional args. Let’s imagine you want to create a function that moves the point to be put on the vector.

4 Solutions

  • put_point_on_vec(point, vec)

  • Make it a method on the vector class. e.g my_vec.put_point(point)

  • Make it a method on the Point class. my_point.put_on_vec(vec)
  • Vector implements __call__, So you can use it like my_vec_instance(point)

This is actually part of some examples I’m working on for a guide for dunder methods explained with Maths that I’m gonna release sooner or later.

I left the logic of moving the point itself because this is not what this question is about


获取嵌套字典值的Python安全方法

问题:获取嵌套字典值的Python安全方法

我有一本嵌套的字典。只有一种方法可以安全地获取价值吗?

try:
    example_dict['key1']['key2']
except KeyError:
    pass

也许python有像get()嵌套字典这样的方法?

I have a nested dictionary. Is there only one way to get values out safely?

try:
    example_dict['key1']['key2']
except KeyError:
    pass

Or maybe python has a method like get() for nested dictionary ?


回答 0

您可以使用get两次:

example_dict.get('key1', {}).get('key2')

None如果存在key1key2不存在,它将返回。

请注意,这仍可能引发AttributeErrorif example_dict['key1']存在但不是dict(或带有get方法的类似dict的对象)。try..except如果发布的代码无法订阅,则会引发一个TypeError代替example_dict['key1']

另一个区别是try...except在第一个丢失的键之后立即发生短路。get呼叫链没有。


如果您希望保留语法,example_dict['key1']['key2']但不希望它引发KeyErrors,则可以使用Hasher配方

class Hasher(dict):
    # https://stackoverflow.com/a/3405143/190597
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

example_dict = Hasher()
print(example_dict['key1'])
# {}
print(example_dict['key1']['key2'])
# {}
print(type(example_dict['key1']['key2']))
# <class '__main__.Hasher'>

请注意,如果缺少密钥,这将返回一个空的哈希器。

因为Hasher是的子类,所以dict您可以像使用一样使用Hasher dict。可以使用所有相同的方法和语法,而Hashers只是以不同方式对待丢失的密钥。

您可以将常规dict转换成Hasher这样:

hasher = Hasher(example_dict)

并轻松将其转换Hasher为常规dict

regular_dict = dict(hasher)

另一种选择是在帮助函数中隐藏丑陋:

def safeget(dct, *keys):
    for key in keys:
        try:
            dct = dct[key]
        except KeyError:
            return None
    return dct

因此,其余代码可以保持相对可读性:

safeget(example_dict, 'key1', 'key2')

You could use get twice:

example_dict.get('key1', {}).get('key2')

This will return None if either key1 or key2 does not exist.

Note that this could still raise an AttributeError if example_dict['key1'] exists but is not a dict (or a dict-like object with a get method). The try..except code you posted would raise a TypeError instead if example_dict['key1'] is unsubscriptable.

Another difference is that the try...except short-circuits immediately after the first missing key. The chain of get calls does not.


If you wish to preserve the syntax, example_dict['key1']['key2'] but do not want it to ever raise KeyErrors, then you could use the Hasher recipe:

class Hasher(dict):
    # https://stackoverflow.com/a/3405143/190597
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

example_dict = Hasher()
print(example_dict['key1'])
# {}
print(example_dict['key1']['key2'])
# {}
print(type(example_dict['key1']['key2']))
# <class '__main__.Hasher'>

Note that this returns an empty Hasher when a key is missing.

Since Hasher is a subclass of dict you can use a Hasher in much the same way you could use a dict. All the same methods and syntax is available, Hashers just treat missing keys differently.

You can convert a regular dict into a Hasher like this:

hasher = Hasher(example_dict)

and convert a Hasher to a regular dict just as easily:

regular_dict = dict(hasher)

Another alternative is to hide the ugliness in a helper function:

def safeget(dct, *keys):
    for key in keys:
        try:
            dct = dct[key]
        except KeyError:
            return None
    return dct

So the rest of your code can stay relatively readable:

safeget(example_dict, 'key1', 'key2')

回答 1

您还可以使用python reduce

def deep_get(dictionary, *keys):
    return reduce(lambda d, key: d.get(key) if d else None, keys, dictionary)

You could also use python reduce:

def deep_get(dictionary, *keys):
    return reduce(lambda d, key: d.get(key) if d else None, keys, dictionary)

回答 2

通过将此处所有这些答案与我所做的微小更改结合起来,我认为此功能将很有用。其安全,快速,易于维护。

def deep_get(dictionary, keys, default=None):
    return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)

范例:

>>> from functools import reduce
>>> def deep_get(dictionary, keys, default=None):
...     return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
...
>>> person = {'person':{'name':{'first':'John'}}}
>>> print (deep_get(person, "person.name.first"))
John
>>> print (deep_get(person, "person.name.lastname"))
None
>>> print (deep_get(person, "person.name.lastname", default="No lastname"))
No lastname
>>>

By combining all of these answer here and small changes that I made, I think this function would be useful. its safe, quick, easily maintainable.

def deep_get(dictionary, keys, default=None):
    return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)

Example :

>>> from functools import reduce
>>> def deep_get(dictionary, keys, default=None):
...     return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
...
>>> person = {'person':{'name':{'first':'John'}}}
>>> print (deep_get(person, "person.name.first"))
John
>>> print (deep_get(person, "person.name.lastname"))
None
>>> print (deep_get(person, "person.name.lastname", default="No lastname"))
No lastname
>>>

回答 3

以Yoav的答案为基础,这是一种更为安全的方法:

def deep_get(dictionary, *keys):
    return reduce(lambda d, key: d.get(key, None) if isinstance(d, dict) else None, keys, dictionary)

Building up on Yoav’s answer, an even safer approach:

def deep_get(dictionary, *keys):
    return reduce(lambda d, key: d.get(key, None) if isinstance(d, dict) else None, keys, dictionary)

回答 4

递归解决方案。它不是最有效的,但是我发现它比其他示例更具可读性,并且不依赖于functools。

def deep_get(d, keys):
    if not keys or d is None:
        return d
    return deep_get(d.get(keys[0]), keys[1:])

d = {'meta': {'status': 'OK', 'status_code': 200}}
deep_get(d, ['meta', 'status_code'])     # => 200
deep_get(d, ['garbage', 'status_code'])  # => None

更精致的版本

def deep_get(d, keys, default=None):
    """
    Example:
        d = {'meta': {'status': 'OK', 'status_code': 200}}
        deep_get(d, ['meta', 'status_code'])          # => 200
        deep_get(d, ['garbage', 'status_code'])       # => None
        deep_get(d, ['meta', 'garbage'], default='-') # => '-'
    """
    assert type(keys) is list
    if d is None:
        return default
    if not keys:
        return d
    return deep_get(d.get(keys[0]), keys[1:], default)

A recursive solution. It’s not the most efficient but I find it a bit more readable than the other examples and it doesn’t rely on functools.

def deep_get(d, keys):
    if not keys or d is None:
        return d
    return deep_get(d.get(keys[0]), keys[1:])

Example

d = {'meta': {'status': 'OK', 'status_code': 200}}
deep_get(d, ['meta', 'status_code'])     # => 200
deep_get(d, ['garbage', 'status_code'])  # => None

A more polished version

def deep_get(d, keys, default=None):
    """
    Example:
        d = {'meta': {'status': 'OK', 'status_code': 200}}
        deep_get(d, ['meta', 'status_code'])          # => 200
        deep_get(d, ['garbage', 'status_code'])       # => None
        deep_get(d, ['meta', 'garbage'], default='-') # => '-'
    """
    assert type(keys) is list
    if d is None:
        return default
    if not keys:
        return d
    return deep_get(d.get(keys[0]), keys[1:], default)

回答 5

虽然reduce方法简洁明了,但我认为一个简单的循环更容易理解。我还包括一个默认参数。

def deep_get(_dict, keys, default=None):
    for key in keys:
        if isinstance(_dict, dict):
            _dict = _dict.get(key, default)
        else:
            return default
    return _dict

为了了解还原型单缸衬套的工作原理,我做了以下工作。但最终循环方法对我来说似乎更直观。

def deep_get(_dict, keys, default=None):

    def _reducer(d, key):
        if isinstance(d, dict):
            return d.get(key, default)
        return default

    return reduce(_reducer, keys, _dict)

用法

nested = {'a': {'b': {'c': 42}}}

print deep_get(nested, ['a', 'b'])
print deep_get(nested, ['a', 'b', 'z', 'z'], default='missing')

While the reduce approach is neat and short, I think a simple loop is easier to grok. I’ve also included a default parameter.

def deep_get(_dict, keys, default=None):
    for key in keys:
        if isinstance(_dict, dict):
            _dict = _dict.get(key, default)
        else:
            return default
    return _dict

As an exercise to understand how the reduce one-liner worked, I did the following. But ultimately the loop approach seems more intuitive to me.

def deep_get(_dict, keys, default=None):

    def _reducer(d, key):
        if isinstance(d, dict):
            return d.get(key, default)
        return default

    return reduce(_reducer, keys, _dict)

Usage

nested = {'a': {'b': {'c': 42}}}

print deep_get(nested, ['a', 'b'])
print deep_get(nested, ['a', 'b', 'z', 'z'], default='missing')

回答 6

我建议你试试python-benedict

它是一个dict子类,提供键路径支持等等。

安装: pip install python-benedict

from benedict import benedict

example_dict = benedict(example_dict, keypath_separator='.')

现在您可以使用keypath访问嵌套值:

val = example_dict['key1.key2']

# using 'get' method to avoid a possible KeyError:
val = example_dict.get('key1.key2')

或使用键列表访问嵌套值:

val = example_dict['key1', 'key2']

# using get to avoid a possible KeyError:
val = example_dict.get(['key1', 'key2'])

它在GitHub上经过了良好的测试和开源

https://github.com/fabiocaccamo/python-benedict

I suggest you to try python-benedict.

It is a dict subclass that provides keypath support and much more.

Installation: pip install python-benedict

from benedict import benedict

example_dict = benedict(example_dict, keypath_separator='.')

now you can access nested values using keypath:

val = example_dict['key1.key2']

# using 'get' method to avoid a possible KeyError:
val = example_dict.get('key1.key2')

or access nested values using keys list:

val = example_dict['key1', 'key2']

# using get to avoid a possible KeyError:
val = example_dict.get(['key1', 'key2'])

It is well tested and open-source on GitHub:

https://github.com/fabiocaccamo/python-benedict

Note: I am the author of this project


回答 7

一个简单的类,可以包装字典并根据键进行检索:

class FindKey(dict):
    def get(self, path, default=None):
        keys = path.split(".")
        val = None

        for key in keys:
            if val:
                if isinstance(val, list):
                    val = [v.get(key, default) if v else None for v in val]
                else:
                    val = val.get(key, default)
            else:
                val = dict.get(self, key, default)

            if not val:
                break

        return val

例如:

person = {'person':{'name':{'first':'John'}}}
FindDict(person).get('person.name.first') # == 'John'

如果键不存在,则None默认情况下返回。您可以使用包装器中的default=键覆盖它FindDict,例如`:

FindDict(person, default='').get('person.name.last') # == doesn't exist, so ''

A simple class that can wrap a dict, and retrieve based on a key:

class FindKey(dict):
    def get(self, path, default=None):
        keys = path.split(".")
        val = None

        for key in keys:
            if val:
                if isinstance(val, list):
                    val = [v.get(key, default) if v else None for v in val]
                else:
                    val = val.get(key, default)
            else:
                val = dict.get(self, key, default)

            if not val:
                break

        return val

For example:

person = {'person':{'name':{'first':'John'}}}
FindDict(person).get('person.name.first') # == 'John'

If the key doesn’t exist, it returns None by default. You can override that using a default= key in the FindDict wrapper — for example`:

FindDict(person, default='').get('person.name.last') # == doesn't exist, so ''

回答 8

对于第二级密钥检索,可以执行以下操作:

key2_value = (example_dict.get('key1') or {}).get('key2')

for a second level key retrieving, you can do this:

key2_value = (example_dict.get('key1') or {}).get('key2')

回答 9

看到属性后,我进行了以下操作以dict使用点表示法安全地获取嵌套值。这对我dicts有用,因为我是反序列化的MongoDB对象,所以我知道键名不包含.。另外,在我的上下文中,我可以指定一个None我的数据中没有的虚假后备值(),因此在调用该函数时可以避免使用try / except模式。

from functools import reduce # Python 3
def deepgetitem(obj, item, fallback=None):
    """Steps through an item chain to get the ultimate value.

    If ultimate value or path to value does not exist, does not raise
    an exception and instead returns `fallback`.

    >>> d = {'snl_final': {'about': {'_icsd': {'icsd_id': 1}}}}
    >>> deepgetitem(d, 'snl_final.about._icsd.icsd_id')
    1
    >>> deepgetitem(d, 'snl_final.about._sandbox.sbx_id')
    >>>
    """
    def getitem(obj, name):
        try:
            return obj[name]
        except (KeyError, TypeError):
            return fallback
    return reduce(getitem, item.split('.'), obj)

After seeing this for deeply getting attributes, I made the following to safely get nested dict values using dot notation. This works for me because my dicts are deserialized MongoDB objects, so I know the key names don’t contain .s. Also, in my context, I can specify a falsy fallback value (None) that I don’t have in my data, so I can avoid the try/except pattern when calling the function.

from functools import reduce # Python 3
def deepgetitem(obj, item, fallback=None):
    """Steps through an item chain to get the ultimate value.

    If ultimate value or path to value does not exist, does not raise
    an exception and instead returns `fallback`.

    >>> d = {'snl_final': {'about': {'_icsd': {'icsd_id': 1}}}}
    >>> deepgetitem(d, 'snl_final.about._icsd.icsd_id')
    1
    >>> deepgetitem(d, 'snl_final.about._sandbox.sbx_id')
    >>>
    """
    def getitem(obj, name):
        try:
            return obj[name]
        except (KeyError, TypeError):
            return fallback
    return reduce(getitem, item.split('.'), obj)

回答 10

同一件事的另一个函数也返回一个布尔值,表示是否找到了密钥,并处理一些意外错误。

'''
json : json to extract value from if exists
path : details.detail.first_name
            empty path represents root

returns a tuple (boolean, object)
        boolean : True if path exists, otherwise False
        object : the object if path exists otherwise None

'''
def get_json_value_at_path(json, path=None, default=None):

    if not bool(path):
        return True, json
    if type(json) is not dict :
        raise ValueError(f'json={json}, path={path} not supported, json must be a dict')
    if type(path) is not str and type(path) is not list:
        raise ValueError(f'path format {path} not supported, path can be a list of strings like [x,y,z] or a string like x.y.z')

    if type(path) is str:
        path = path.strip('.').split('.')
    key = path[0]
    if key in json.keys():
        return get_json_value_at_path(json[key], path[1:], default)
    else:
        return False, default

用法示例:

my_json = {'details' : {'first_name' : 'holla', 'last_name' : 'holla'}}
print(get_json_value_at_path(my_json, 'details.first_name', ''))
print(get_json_value_at_path(my_json, 'details.phone', ''))

(真的,“ holla”)

(错误,“”)

Yet another function for the same thing, also returns a boolean to represent whether the key was found or not and handles some unexpected errors.

'''
json : json to extract value from if exists
path : details.detail.first_name
            empty path represents root

returns a tuple (boolean, object)
        boolean : True if path exists, otherwise False
        object : the object if path exists otherwise None

'''
def get_json_value_at_path(json, path=None, default=None):

    if not bool(path):
        return True, json
    if type(json) is not dict :
        raise ValueError(f'json={json}, path={path} not supported, json must be a dict')
    if type(path) is not str and type(path) is not list:
        raise ValueError(f'path format {path} not supported, path can be a list of strings like [x,y,z] or a string like x.y.z')

    if type(path) is str:
        path = path.strip('.').split('.')
    key = path[0]
    if key in json.keys():
        return get_json_value_at_path(json[key], path[1:], default)
    else:
        return False, default

example usage:

my_json = {'details' : {'first_name' : 'holla', 'last_name' : 'holla'}}
print(get_json_value_at_path(my_json, 'details.first_name', ''))
print(get_json_value_at_path(my_json, 'details.phone', ''))

(True, ‘holla’)

(False, ”)


回答 11

您可以使用pydash:

import pydash as _

_.get(example_dict, 'key1.key2', default='Default')

https://pydash.readthedocs.io/en/latest/api.html

You can use pydash:

import pydash as _

_.get(example_dict, 'key1.key2', default='Default')

https://pydash.readthedocs.io/en/latest/api.html


回答 12

我发现在自己的代码中有用的unutbu答案的改编:

example_dict.setdefaut('key1', {}).get('key2')

如果它没有key1,它将为key1生成一个字典条目,以便避免KeyError。如果您想像我一样以包含该键对的嵌套字典作为结尾,这似乎是最简单的解决方案。

An adaptation of unutbu’s answer that I found useful in my own code:

example_dict.setdefaut('key1', {}).get('key2')

It generates a dictionary entry for key1 if it does not have that key already so that you avoid the KeyError. If you want to end up a nested dictionary that includes that key pairing anyway like I did, this seems like the easiest solution.


回答 13

由于如果缺少一个键会引发一个键错误是一件合理的事情,因此我们甚至无法检查它并使其成为单个:

def get_dict(d, kl):
  cur = d[kl[0]]
  return get_dict(cur, kl[1:]) if len(kl) > 1 else cur

Since raising an key error if one of keys is missing is a reasonable thing to do, we can even not check for it and get it as single as that:

def get_dict(d, kl):
  cur = d[kl[0]]
  return get_dict(cur, kl[1:]) if len(kl) > 1 else cur

回答 14

reduce使它与列表一起使用的方法几乎没有改进。还使用数据路径作为由点而不是数组分隔的字符串。

def deep_get(dictionary, path):
    keys = path.split('.')
    return reduce(lambda d, key: d[int(key)] if isinstance(d, list) else d.get(key) if d else None, keys, dictionary)

Little improvement to reduce approach to make it work with list. Also using data path as string divided by dots instead of array.

def deep_get(dictionary, path):
    keys = path.split('.')
    return reduce(lambda d, key: d[int(key)] if isinstance(d, list) else d.get(key) if d else None, keys, dictionary)

回答 15

我使用的解决方案类似于double get,但具有使用if else逻辑避免TypeError的附加功能:

    value = example_dict['key1']['key2'] if example_dict.get('key1') and example_dict['key1'].get('key2') else default_value

但是,字典嵌套得越多,麻烦就越多。

A solution I’ve used that is similar to the double get but with the additional ability to avoid a TypeError using if else logic:

    value = example_dict['key1']['key2'] if example_dict.get('key1') and example_dict['key1'].get('key2') else default_value

However, the more nested the dictionary the more cumbersome this becomes.


回答 16

对于嵌套字典/ JSON查找,可以使用dictor

点安装独裁者

字典对象

{
    "characters": {
        "Lonestar": {
            "id": 55923,
            "role": "renegade",
            "items": [
                "space winnebago",
                "leather jacket"
            ]
        },
        "Barfolomew": {
            "id": 55924,
            "role": "mawg",
            "items": [
                "peanut butter jar",
                "waggy tail"
            ]
        },
        "Dark Helmet": {
            "id": 99999,
            "role": "Good is dumb",
            "items": [
                "Shwartz",
                "helmet"
            ]
        },
        "Skroob": {
            "id": 12345,
            "role": "Spaceballs CEO",
            "items": [
                "luggage"
            ]
        }
    }
}

要获得Lonestar的商品,只需提供一个点分隔的路径,即

import json
from dictor import dictor

with open('test.json') as data: 
    data = json.load(data)

print dictor(data, 'characters.Lonestar.items')

>> [u'space winnebago', u'leather jacket']

您可以提供备用值,以防路径中的键不存在

您还有更多选择,例如忽略字母大写和使用”以外的其他字符。作为路径分隔符

https://github.com/perfecto25/dictor

For nested dictionary/JSON lookups, you can use dictor

pip install dictor

dict object

{
    "characters": {
        "Lonestar": {
            "id": 55923,
            "role": "renegade",
            "items": [
                "space winnebago",
                "leather jacket"
            ]
        },
        "Barfolomew": {
            "id": 55924,
            "role": "mawg",
            "items": [
                "peanut butter jar",
                "waggy tail"
            ]
        },
        "Dark Helmet": {
            "id": 99999,
            "role": "Good is dumb",
            "items": [
                "Shwartz",
                "helmet"
            ]
        },
        "Skroob": {
            "id": 12345,
            "role": "Spaceballs CEO",
            "items": [
                "luggage"
            ]
        }
    }
}

to get Lonestar’s items, simply provide a dot-separated path, ie

import json
from dictor import dictor

with open('test.json') as data: 
    data = json.load(data)

print dictor(data, 'characters.Lonestar.items')

>> [u'space winnebago', u'leather jacket']

you can provide fallback value in case the key isnt in path

theres tons more options you can do, like ignore letter casing and using other characters besides ‘.’ as a path separator,

https://github.com/perfecto25/dictor


回答 17

我几乎没有改变这个答案。我添加了检查是否正在使用带有数字的列表。所以现在我们可以使用任何一种方式。deep_get(allTemp, [0], {})deep_get(getMinimalTemp, [0, minimalTemperatureKey], 26)

def deep_get(_dict, keys, default=None):
    def _reducer(d, key):
        if isinstance(d, dict):
            return d.get(key, default)
        if isinstance(d, list):
            return d[key] if len(d) > 0 else default
        return default
    return reduce(_reducer, keys, _dict)

I little changed this answer. I added checking if we’re using list with numbers. So now we can use it whichever way. deep_get(allTemp, [0], {}) or deep_get(getMinimalTemp, [0, minimalTemperatureKey], 26) etc

def deep_get(_dict, keys, default=None):
    def _reducer(d, key):
        if isinstance(d, dict):
            return d.get(key, default)
        if isinstance(d, list):
            return d[key] if len(d) > 0 else default
        return default
    return reduce(_reducer, keys, _dict)

回答 18

已经有了很多好的答案,但是我想出了一个名为get的函数,类似于JavaScript领域中的lodash get,它还支持按索引进入列表:

def get(value, keys, default_value = None):
'''
    Useful for reaching into nested JSON like data
    Inspired by JavaScript lodash get and Clojure get-in etc.
'''
  if value is None or keys is None:
      return None
  path = keys.split('.') if isinstance(keys, str) else keys
  result = value
  def valid_index(key):
      return re.match('^([1-9][0-9]*|[0-9])$', key) and int(key) >= 0
  def is_dict_like(v):
      return hasattr(v, '__getitem__') and hasattr(v, '__contains__')
  for key in path:
      if isinstance(result, list) and valid_index(key) and int(key) < len(result):
          result = result[int(key)] if int(key) < len(result) else None
      elif is_dict_like(result) and key in result:
          result = result[key]
      else:
          result = default_value
          break
  return result

def test_get():
  assert get(None, ['foo']) == None
  assert get({'foo': 1}, None) == None
  assert get(None, None) == None
  assert get({'foo': 1}, []) == {'foo': 1}
  assert get({'foo': 1}, ['foo']) == 1
  assert get({'foo': 1}, ['bar']) == None
  assert get({'foo': 1}, ['bar'], 'the default') == 'the default'
  assert get({'foo': {'bar': 'hello'}}, ['foo', 'bar']) == 'hello'
  assert get({'foo': {'bar': 'hello'}}, 'foo.bar') == 'hello'
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.0.bar') == 'hello'
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.1') == None
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.1.bar') == None
  assert get(['foo', 'bar'], '1') == 'bar'
  assert get(['foo', 'bar'], '2') == None

There are already lots of good answers but I have come up with a function called get similar to lodash get in JavaScript land that also supports reaching into lists by index:

def get(value, keys, default_value = None):
'''
    Useful for reaching into nested JSON like data
    Inspired by JavaScript lodash get and Clojure get-in etc.
'''
  if value is None or keys is None:
      return None
  path = keys.split('.') if isinstance(keys, str) else keys
  result = value
  def valid_index(key):
      return re.match('^([1-9][0-9]*|[0-9])$', key) and int(key) >= 0
  def is_dict_like(v):
      return hasattr(v, '__getitem__') and hasattr(v, '__contains__')
  for key in path:
      if isinstance(result, list) and valid_index(key) and int(key) < len(result):
          result = result[int(key)] if int(key) < len(result) else None
      elif is_dict_like(result) and key in result:
          result = result[key]
      else:
          result = default_value
          break
  return result

def test_get():
  assert get(None, ['foo']) == None
  assert get({'foo': 1}, None) == None
  assert get(None, None) == None
  assert get({'foo': 1}, []) == {'foo': 1}
  assert get({'foo': 1}, ['foo']) == 1
  assert get({'foo': 1}, ['bar']) == None
  assert get({'foo': 1}, ['bar'], 'the default') == 'the default'
  assert get({'foo': {'bar': 'hello'}}, ['foo', 'bar']) == 'hello'
  assert get({'foo': {'bar': 'hello'}}, 'foo.bar') == 'hello'
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.0.bar') == 'hello'
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.1') == None
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.1.bar') == None
  assert get(['foo', 'bar'], '1') == 'bar'
  assert get(['foo', 'bar'], '2') == None

未绑定方法f()必须以fibo_实例作为第一个参数调用(取而代之的是class classobj实例)

问题:未绑定方法f()必须以fibo_实例作为第一个参数调用(取而代之的是class classobj实例)

在Python中,我尝试在类中运行方法,但出现错误:

Traceback (most recent call last):
  File "C:\Users\domenico\Desktop\py\main.py", line 8, in <module>
    fibo.f()
  TypeError: unbound method f() must be called with fibo instance 
  as first argument (got nothing instead)

代码:(swineflu.py)

class fibo:
    a=0
    b=0

    def f(self,a=0):
        print fibo.b+a
        b=a;
        return self(a+1)

脚本main.py

import swineflu

f = swineflu
fibo = f.fibo

fibo.f()            #TypeError is thrown here

这个错误是什么意思?是什么导致此错误?

In Python, I’m trying to run a method in a class and I get an error:

Traceback (most recent call last):
  File "C:\Users\domenico\Desktop\py\main.py", line 8, in <module>
    fibo.f()
  TypeError: unbound method f() must be called with fibo instance 
  as first argument (got nothing instead)

Code: (swineflu.py)

class fibo:
    a=0
    b=0

    def f(self,a=0):
        print fibo.b+a
        b=a;
        return self(a+1)

Script main.py

import swineflu

f = swineflu
fibo = f.fibo

fibo.f()            #TypeError is thrown here

What does this error mean? What is causing this error?


回答 0

好的,首先,您不必以其他名称引用模块。您已经有一个参考(来自import),您可以使用它。如果您想使用其他名称,请使用import swineflu as f

其次,您将获得对该类的引用,而不是实例化该类。

所以这应该是:

import swineflu

fibo = swineflu.fibo()  # get an instance of the class
fibo.f()                # call the method f of the instance

绑定的方法是一个被附加到对象的实例。的未结合的方法是,当然,一个是附连到一个实例。该错误通常意味着您是在类而不是实例上调用该方法,这正是在这种情况下发生的事情,因为您尚未实例化该类。

OK, first of all, you don’t have to get a reference to the module into a different name; you already have a reference (from the import) and you can just use it. If you want a different name just use import swineflu as f.

Second, you are getting a reference to the class rather than instantiating the class.

So this should be:

import swineflu

fibo = swineflu.fibo()  # get an instance of the class
fibo.f()                # call the method f of the instance

A bound method is one that is attached to an instance of an object. An unbound method is, of course, one that is not attached to an instance. The error usually means you are calling the method on the class rather than on an instance, which is exactly what was happening in this case because you hadn’t instantiated the class.


回答 1

如何用尽可能少的行来重现此错误:

>>> class C:
...   def f(self):
...     print "hi"
...
>>> C.f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as 
first argument (got nothing instead)

由于TypeError而失败,因为您没有首先实例化该类,您有两种选择:1:将方法设为静态以便可以以静态方式运行它;或者2:实例化您的类以便获得实例上,以运行该方法。

看来您想以静态方式运行方法,请执行以下操作:

>>> class C:
...   @staticmethod
...   def f():
...     print "hi"
...
>>> C.f()
hi

或者,您可能的意思是使用这样的实例化实例:

>>> class C:
...   def f(self):
...     print "hi"
...
>>> c1 = C()
>>> c1.f()
hi
>>> C().f()
hi

如果这使您感到困惑,请提出以下问题:

  1. 静态方法的行为与普通方法的行为有什么区别?
  2. 实例化类是什么意思?
  3. 静态方法的运行方式与普通方法之间的差异。
  4. 类和对象之间的差异。

How to reproduce this error with as few lines as possible:

>>> class C:
...   def f(self):
...     print "hi"
...
>>> C.f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as 
first argument (got nothing instead)

It fails because of TypeError because you didn’t instantiate the class first, you have two choices: 1: either make the method static so you can run it in a static way, or 2: instantiate your class so you have an instance to grab onto, to run the method.

It looks like you want to run the method in a static way, do this:

>>> class C:
...   @staticmethod
...   def f():
...     print "hi"
...
>>> C.f()
hi

Or, what you probably meant is to use the instantiated instance like this:

>>> class C:
...   def f(self):
...     print "hi"
...
>>> c1 = C()
>>> c1.f()
hi
>>> C().f()
hi

If this confuses you, ask these questions:

  1. What is the difference between the behavior of a static method vs the behavior of a normal method?
  2. What does it mean to instantiate a class?
  3. Differences between how static methods are run vs normal methods.
  4. Differences between class and object.

回答 2

fibo = f.fibo引用类本身。您可能希望fibo = f.fibo()(请注意括号)成为该类的实例,之后fibo.f()应该可以成功完成。

f.fibo.f()之所以失败,是因为您本质上f(self, a=0)没有打电话就打电话self; self当您拥有该类的实例时,它会自动“绑定”。

fibo = f.fibo references the class itself. You probably wanted fibo = f.fibo() (note the parentheses) to make an instance of the class, after which fibo.f() should succeed correctly.

f.fibo.f() fails because you are essentially calling f(self, a=0) without supplying self; self is “bound” automatically when you have an instance of the class.


回答 3

f是(实例)方法。但是,您是通过调用它的fibo.f,那里fibo是类对象。因此,f是unbound(不绑定到任何类实例)。

如果你做了

a = fibo()
a.f()

然后将f其绑定到(实例a)。

f is an (instance) method. However, you are calling it via fibo.f, where fibo is the class object. Hence, f is unbound (not bound to any class instance).

If you did

a = fibo()
a.f()

then that f is bound (to the instance a).


回答 4

import swineflu

x = swineflu.fibo()   # create an object `x` of class `fibo`, an instance of the class
x.f()                 # call the method `f()`, bound to `x`. 

是入门Python类的好教程。

import swineflu

x = swineflu.fibo()   # create an object `x` of class `fibo`, an instance of the class
x.f()                 # call the method `f()`, bound to `x`. 

Here is a good tutorial to get started with classes in Python.


回答 5

在Python 2中(3具有不同的语法):

如果无法在需要调用其方法之一之前实例化Parent类,该怎么办?

使用super(ChildClass, self).method()访问父方法。

class ParentClass(object):
    def method_to_call(self, arg_1):
        print arg_1

class ChildClass(ParentClass):
    def do_thing(self):
        super(ChildClass, self).method_to_call('my arg')

In Python 2 (3 has different syntax):

What if you can’t instantiate your Parent class before you need to call one of its methods?

Use super(ChildClass, self).method() to access parent methods.

class ParentClass(object):
    def method_to_call(self, arg_1):
        print arg_1

class ChildClass(ParentClass):
    def do_thing(self):
        super(ChildClass, self).method_to_call('my arg')

回答 6

在python 2和3版本中的差异:

如果您已经在具有相同名称的类中使用默认方法,并且重新声明为相同名称,则当您要实例化该实例时,它将作为该类实例的未绑定方法调用出现。

如果您想要类方法,但是您将它们声明为实例方法。

实例方法是在创建类的实例时使用的方法。

一个例子是

   def user_group(self):   #This is an instance method
        return "instance method returning group"

类标签方法:

   @classmethod
   def user_group(groups):   #This is an class-label method
        return "class method returning group"

在python 2和3版本中,要在python 3中编写的类@classmethod有所不同,它会自动将其作为类标签方法获取,而无需编写@classmethod,我认为这可能对您有所帮助。

Differences in In python 2 and 3 version:

If you already have a default method in a class with same name and you re-declare as a same name it will appear as unbound-method call of that class instance when you wanted to instantiated it.

If you wanted class methods, but you declared them as instance methods instead.

An instance method is a method that is used when to create an instance of the class.

An example would be

   def user_group(self):   #This is an instance method
        return "instance method returning group"

Class label method:

   @classmethod
   def user_group(groups):   #This is an class-label method
        return "class method returning group"

In python 2 and 3 version differ the class @classmethod to write in python 3 it automatically get that as a class-label method and don’t need to write @classmethod I think this might help you.


回答 7

试试这个。对于python 2.7.12,我们需要定义构造函数,或者需要向每个方法添加self,然后定义一个称为object的类的实例。

import cv2

class calculator:

#   def __init__(self):

def multiply(self, a, b):
    x= a*b
    print(x)

def subtract(self, a,b):
    x = a-b
    print(x)

def add(self, a,b):
    x = a+b
    print(x)

def div(self, a,b):
    x = a/b
    print(x)

 calc = calculator()
 calc.multiply(2,3)
 calc.add(2,3)
 calc.div(10,5)
 calc.subtract(2,3)

Try this. For python 2.7.12 we need to define constructor or need to add self to each methods followed by defining an instance of an class called object.

import cv2

class calculator:

#   def __init__(self):

def multiply(self, a, b):
    x= a*b
    print(x)

def subtract(self, a,b):
    x = a-b
    print(x)

def add(self, a,b):
    x = a+b
    print(x)

def div(self, a,b):
    x = a/b
    print(x)

 calc = calculator()
 calc.multiply(2,3)
 calc.add(2,3)
 calc.div(10,5)
 calc.subtract(2,3)

为什么Python代码使用len()函数而不是length方法?

问题:为什么Python代码使用len()函数而不是length方法?

我知道python具有len()用于确定字符串大小的函数,但是我想知道为什么它不是字符串对象的方法。

更新资料

好吧,我意识到我很尴尬地犯了错误。__len__()实际上是字符串对象的方法。在字符串对象上使用len函数在Python中看到面向对象的代码似乎很奇怪。此外,看到__len__名字而不是len 也很奇怪。

I know that python has a len() function that is used to determine the size of a string, but I was wondering why it’s not a method of the string object.

Update

Ok, I realized I was embarrassingly mistaken. __len__() is actually a method of a string object. It just seems weird to see object oriented code in Python using the len function on string objects. Furthermore, it’s also weird to see __len__ as the name instead of just len.


回答 0

字符串确实有一个length方法: __len__()

Python中的协议是在具有一定长度并使用内置len()函数的对象上实现此方法,该内置函数会为您调用该方法,类似于您实现__iter__()和使用内置iter()函数的方法(或在后面调用方法)的场景)在可迭代的对象上。

有关更多信息,请参见模拟容器类型

这是有关Python协议主题的好书:Python和最小惊讶原则

Strings do have a length method: __len__()

The protocol in Python is to implement this method on objects which have a length and use the built-in len() function, which calls it for you, similar to the way you would implement __iter__() and use the built-in iter() function (or have the method called behind the scenes for you) on objects which are iterable.

See Emulating container types for more information.

Here’s a good read on the subject of protocols in Python: Python and the Principle of Least Astonishment


回答 1

吉姆对这个问题的回答可能会有所帮助。我在这里复制。引用Guido van Rossum:

首先,出于HCI的原因,我选择len(x)而不是x.len()(def __len __()来得很晚)。实际上,两个HCI相互交织在一起:

(a)对于某些运算,前缀表示法比后缀读得更好-前缀(和infix!)运算符在数学中有很长的传统,喜欢在视觉上帮助数学家思考问题的表示法。将我们将x *(a + b)之类的公式重写为x a + x b 的简便性与使用原始OO符号做相同事情的笨拙性进行比较。

(b)当我读到说len(x)的代码时,我知道它是在问某物的长度。这告诉我两件事:结果是整数,参数是某种容器。相反,当我阅读x.len()时,我必须已经知道x是某种实现接口或从具有标准len()的类继承的容器。当未实现映射的类具有get()或keys()方法,或者非文件类具有write()方法时,我们有时会感到困惑。

用另一种方式说同样的事情,我将“ len”视为内置操作。我不想失去那个。/…/

Jim’s answer to this question may help; I copy it here. Quoting Guido van Rossum:

First of all, I chose len(x) over x.len() for HCI reasons (def __len__() came much later). There are two intertwined reasons actually, both HCI:

(a) For some operations, prefix notation just reads better than postfix — prefix (and infix!) operations have a long tradition in mathematics which likes notations where the visuals help the mathematician thinking about a problem. Compare the easy with which we rewrite a formula like x*(a+b) into xa + xb to the clumsiness of doing the same thing using a raw OO notation.

(b) When I read code that says len(x) I know that it is asking for the length of something. This tells me two things: the result is an integer, and the argument is some kind of container. To the contrary, when I read x.len(), I have to already know that x is some kind of container implementing an interface or inheriting from a class that has a standard len(). Witness the confusion we occasionally have when a class that is not implementing a mapping has a get() or keys() method, or something that isn’t a file has a write() method.

Saying the same thing in another way, I see ‘len‘ as a built-in operation. I’d hate to lose that. /…/


回答 2

有一种len方法:

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>

There is a len method:

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>

回答 3

Python是一种务实的编程语言,并为原因len()是一个功能,而不是一个方法strlistdict等务实。

len()内置函数直接处理的内置类型:CPython的执行len()实际返回的值ob_size字段中PyVarObject的C结构代表任意可变大小的内置存储器中的对象。这是很多比调用一个方法快-无属性的查找需要发生。获取集合中的项目数是一种常见的操作,必须对这些基本类型多样为提高工作效率strlistarray.array等。

但是,为了提高一致性,当应用len(o)到用户定义的类型时,Python会o.__len__()作为后备调用。 __len____abs__和所有其他特殊的记录方法的Python数据模型可以很容易地创建对象,其行为像内置插件,使表现力和高度一致的API,我们称之为“Python化”。

通过实现特殊的方法,您的对象可以支持迭代,重载infix运算符,在with块中管理上下文等。您可以将数据模型视为一种使用Python语言本身作为框架的方式,您可以在其中无缝集成所创建的对象。

第二个原因,通过报价从吉多·范罗苏姆等支撑这一个,是它更容易阅读和写len(s)s.len()

该表示法len(s)与带有前缀表示法的一元运算符一致,例如abs(n)len()的使用频率比更高abs(),并且应该易于编写。

可能还有一个历史原因:在Python之前的ABC语言中(在其设计中很有影响力),有一个一元运算符,#s其含义为len(s)

Python is a pragmatic programming language, and the reasons for len() being a function and not a method of str, list, dict etc. are pragmatic.

The len() built-in function deals directly with built-in types: the CPython implementation of len() actually returns the value of the ob_size field in the PyVarObject C struct that represents any variable-sized built-in object in memory. This is much faster than calling a method — no attribute lookup needs to happen. Getting the number of items in a collection is a common operation and must work efficiently for such basic and diverse types as str, list, array.array etc.

However, to promote consistency, when applying len(o) to a user-defined type, Python calls o.__len__() as a fallback. __len__, __abs__ and all the other special methods documented in the Python Data Model make it easy to create objects that behave like the built-ins, enabling the expressive and highly consistent APIs we call “Pythonic”.

By implementing special methods your objects can support iteration, overload infix operators, manage contexts in with blocks etc. You can think of the Data Model as a way of using the Python language itself as a framework where the objects you create can be integrated seamlessly.

A second reason, supported by quotes from Guido van Rossum like this one, is that it is easier to read and write len(s) than s.len().

The notation len(s) is consistent with unary operators with prefix notation, like abs(n). len() is used way more often than abs(), and it deserves to be as easy to write.

There may also be a historical reason: in the ABC language which preceded Python (and was very influential in its design), there was a unary operator written as #s which meant len(s).


回答 4

met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.

回答 5

这里有一些很好的答案,因此在我给出自己的名字之前,我想重点介绍一下我在这里读过的一些宝石(无红宝石双关语)。

  • Python并不是纯粹的OOP语言,它是一种通用的多范式语言,它使程序员能够使用他们最熟悉的范式和/或最适合其解决方案的范式。
  • Python具有一流的功能,因此len实际上是一个对象。另一方面,Ruby没有一流的功能。因此,len函数对象具有自己的方法,可以通过运行进行检查dir(len)

如果您不喜欢此代码在自己的代码中的工作方式,那么使用首选方法重新实现容器是很简单的(请参见下面的示例)。

>>> class List(list):
...     def len(self):
...         return len(self)
...
>>> class Dict(dict):
...     def len(self):
...         return len(self)
...
>>> class Tuple(tuple):
...     def len(self):
...         return len(self)
...
>>> class Set(set):
...     def len(self):
...         return len(self)
...
>>> my_list = List([1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'])
>>> my_dict = Dict({'key': 'value', 'site': 'stackoverflow'})
>>> my_set = Set({1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'})
>>> my_tuple = Tuple((1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'))
>>> my_containers = Tuple((my_list, my_dict, my_set, my_tuple))
>>>
>>> for container in my_containers:
...     print container.len()
...
15
2
15
15

There are some great answers here, and so before I give my own I’d like to highlight a few of the gems (no ruby pun intended) I’ve read here.

  • Python is not a pure OOP language — it’s a general purpose, multi-paradigm language that allows the programmer to use the paradigm they are most comfortable with and/or the paradigm that is best suited for their solution.
  • Python has first-class functions, so len is actually an object. Ruby, on the other hand, doesn’t have first class functions. So the len function object has it’s own methods that you can inspect by running dir(len).

If you don’t like the way this works in your own code, it’s trivial for you to re-implement the containers using your preferred method (see example below).

>>> class List(list):
...     def len(self):
...         return len(self)
...
>>> class Dict(dict):
...     def len(self):
...         return len(self)
...
>>> class Tuple(tuple):
...     def len(self):
...         return len(self)
...
>>> class Set(set):
...     def len(self):
...         return len(self)
...
>>> my_list = List([1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'])
>>> my_dict = Dict({'key': 'value', 'site': 'stackoverflow'})
>>> my_set = Set({1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'})
>>> my_tuple = Tuple((1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'))
>>> my_containers = Tuple((my_list, my_dict, my_set, my_tuple))
>>>
>>> for container in my_containers:
...     print container.len()
...
15
2
15
15

回答 6

你也可以说

>> x = 'test'
>> len(x)
4

使用Python 2.7.3。

You can also say

>> x = 'test'
>> len(x)
4

Using Python 2.7.3.


回答 7

这里的其余答案缺少一些内容:len函数检查__len__方法是否返回非负数intlen作为函数的事实意味着类无法重写此行为以避免检查。因此,len(obj)给出了不能达到的安全级别obj.len()

例:

>>> class A:
...     def __len__(self):
...         return 'foo'
...
>>> len(A())
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    len(A())
TypeError: 'str' object cannot be interpreted as an integer
>>> class B:
...     def __len__(self):
...         return -1
... 
>>> len(B())
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    len(B())
ValueError: __len__() should return >= 0

当然,可以len通过将其重新分配为全局变量来“覆盖” 函数,但是比起覆盖类中方法的代码,这样做的代码明显更可疑。

Something missing from the rest of the answers here: the len function checks that the __len__ method returns a non-negative int. The fact that len is a function means that classes cannot override this behaviour to avoid the check. As such, len(obj) gives a level of safety that obj.len() cannot.

Example:

>>> class A:
...     def __len__(self):
...         return 'foo'
...
>>> len(A())
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    len(A())
TypeError: 'str' object cannot be interpreted as an integer
>>> class B:
...     def __len__(self):
...         return -1
... 
>>> len(B())
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    len(B())
ValueError: __len__() should return >= 0

Of course, it is possible to “override” the len function by reassigning it as a global variable, but code which does this is much more obviously suspicious than code which overrides a method in a class.


回答 8

不是吗

>>> "abc".__len__()
3

It doesn’t?

>>> "abc".__len__()
3

为什么需要在Python方法中显式包含“ self”参数?

问题:为什么需要在Python方法中显式包含“ self”参数?

在Python中的类上定义方法时,它看起来像这样:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

但是在某些其他语言(例如C#)中,您可以使用“ this”关键字来引用该方法所绑定的对象,而无需在方法原型中将其声明为参数。

这是Python中的一种故意的语言设计决策,还是有一些实现细节需要传递“ self”作为参数?

When defining a method on a class in Python, it looks something like this:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

But in some other languages, such as C#, you have a reference to the object that the method is bound to with the “this” keyword without declaring it as an argument in the method prototype.

Was this an intentional language design decision in Python or are there some implementation details that require the passing of “self” as an argument?


回答 0

我喜欢引用Peters的Python Zen。“显式比隐式好。”

在Java和C ++中,this.可以推断出’ ‘,除非您拥有无法推断的变量名。因此,您有时需要它,有时则不需要。

Python选择使这种事情变得明确,而不是基于规则。

另外,由于没有暗示或假设,因此公开了部分实现。 self.__class__self.__dict__以及其他“内部”结构也很明显。

I like to quote Peters’ Zen of Python. “Explicit is better than implicit.”

In Java and C++, ‘this.‘ can be deduced, except when you have variable names that make it impossible to deduce. So you sometimes need it and sometimes don’t.

Python elects to make things like this explicit rather than based on a rule.

Additionally, since nothing is implied or assumed, parts of the implementation are exposed. self.__class__, self.__dict__ and other “internal” structures are available in an obvious way.


回答 1

这是为了最小化方法和函数之间的差异。它使您可以轻松地在元类中生成方法,或在运行时将方法添加到预先存在的类中。

例如

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

据我所知,这也使python运行时的实现更加容易。

It’s to minimize the difference between methods and functions. It allows you to easily generate methods in metaclasses, or add methods at runtime to pre-existing classes.

e.g.

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

It also (as far as I know) makes the implementation of the python runtime easier.


回答 2

我建议人们应该阅读Guido van Rossum关于此主题的博客为什么必须保留显性自我

当修饰一个方法定义时,我们不知道是否要自动给它一个“自我”参数:修饰器可以将函数变成静态方法(没有“自我”)或类方法(其中有一个有趣的自我,它引用一个类而不是一个实例),或者可以做一些完全不同的事情(编写在纯Python中实现“ @classmethod”或“ @staticmethod”的装饰器是微不足道的)。没有办法不知道装饰器的作用,是否赋予被定义的方法一个隐式的“自我”参数。

我拒绝诸如特殊外壳“ @classmethod”和“ @staticmethod”之类的hack。

I suggest that one should read Guido van Rossum’s blog on this topic – Why explicit self has to stay.

When a method definition is decorated, we don’t know whether to automatically give it a ‘self’ parameter or not: the decorator could turn the function into a static method (which has no ‘self’), or a class method (which has a funny kind of self that refers to a class instead of an instance), or it could do something completely different (it’s trivial to write a decorator that implements ‘@classmethod’ or ‘@staticmethod’ in pure Python). There’s no way without knowing what the decorator does whether to endow the method being defined with an implicit ‘self’ argument or not.

I reject hacks like special-casing ‘@classmethod’ and ‘@staticmethod’.


回答 3

Python不会强迫您使用“自我”。您可以根据需要命名。您只需要记住,方法定义标头中的第一个参数是对该对象的引用。

Python doesn’t force you on using “self”. You can give it whatever name you want. You just have to remember that the first argument in a method definition header is a reference to the object.


回答 4

还允许您执行此操作:(简而言之,调用Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5)将返回12,但将以最疯狂的方式返回。

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

当然,用Java和C#这样的语言很难想象这一点。通过使自引用明确,您可以自由地通过该自引用引用任何对象。而且,在更静态的语言中很难用这种在运行时玩类的方式-并不是说它一定是好是坏。只是外在的自我允许所有这些疯狂存在。

此外,想象一下:我们想自定义方法的行为(用于概要分析或某种疯狂的黑魔法)。这可以使我们思考:如果我们拥有一个Method可以覆盖或控制其行为的类怎么办?

好吧,这是:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

而现在:InnocentClass().magic_method()将像预期的那样运行。该方法将与的innocent_self参数绑定InnocentClass,并与magic_selfMagicMethod实例的绑定。奇怪吗?就像有2个关键字this1以及this2Java和C#这样的语言一样。像这样的魔术使框架能够执行原本会更加冗长的工作。

同样,我不想评论这种东西的道德。我只是想展示在没有明确的自我参考的情况下很难做的事情。

Also allows you to do this: (in short, invoking Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) will return 12, but will do so in the craziest of ways.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Of course, this is harder to imagine in languages like Java and C#. By making the self reference explicit, you’re free to refer to any object by that self reference. Also, such a way of playing with classes at runtime is harder to do in the more static languages – not that’s it’s necessarily good or bad. It’s just that the explicit self allows all this craziness to exist.

Moreover, imagine this: We’d like to customize the behavior of methods (for profiling, or some crazy black magic). This can lead us to think: what if we had a class Method whose behavior we could override or control?

Well here it is:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

And now: InnocentClass().magic_method() will act like expected. The method will be bound with the innocent_self parameter to InnocentClass, and with the magic_self to the MagicMethod instance. Weird huh? It’s like having 2 keywords this1 and this2 in languages like Java and C#. Magic like this allows frameworks to do stuff that would otherwise be much more verbose.

Again, I don’t want to comment on the ethics of this stuff. I just wanted to show things that would be harder to do without an explicit self reference.


回答 5

我认为,除了“ Python之禅”之外,真正的原因还在于,函数是Python中的一等公民。

本质上使它们成为对象。现在的根本问题是,如果您的函数也是对象,那么在面向对象的范例中,当消息本身是对象时,如何将消息发送给对象?

看起来像一个鸡蛋问题,为了减少这种矛盾,唯一可能的方法是将执行上下文传递给方法或对其进行检测。但是由于python可以具有嵌套函数,因此将不可能做到这一点,因为内部函数的执行上下文将发生变化。

这意味着唯一可能的解决方案是显式传递“ self”(执行的上下文)。

因此,我认为Zen来得晚了,这是一个实现问题。

I think the real reason besides “The Zen of Python” is that Functions are first class citizens in Python.

Which essentially makes them an Object. Now The fundamental issue is if your functions are object as well then, in Object oriented paradigm how would you send messages to Objects when the messages themselves are objects ?

Looks like a chicken egg problem, to reduce this paradox, the only possible way is to either pass a context of execution to methods or detect it. But since python can have nested functions it would be impossible to do so as the context of execution would change for inner functions.

This means the only possible solution is to explicitly pass ‘self’ (The context of execution).

So i believe it is a implementation problem the Zen came much later.


回答 6

我认为这与PEP 227有关:

类范围内的名称不可访问。名称在最里面的函数范围内解析。如果类定义出现在嵌套作用域链中,则解析过程将跳过类定义。此规则可防止类属性和局部变量访问之间发生奇怪的交互。如果在类定义中发生了名称绑定操作,它将在结果类对象上创建一个属性。要在方法或方法中嵌套的函数中访问此变量,必须通过self或通过类名使用属性引用。

I think it has to do with PEP 227:

Names in class scope are not accessible. Names are resolved in the innermost enclosing function scope. If a class definition occurs in a chain of nested scopes, the resolution process skips class definitions. This rule prevents odd interactions between class attributes and local variable access. If a name binding operation occurs in a class definition, it creates an attribute on the resulting class object. To access this variable in a method, or in a function nested within a method, an attribute reference must be used, either via self or via the class name.


回答 7

Python中的self所述,Demystified

像obj.meth(args)之类的东西都变成Class.meth(obj,args)。调用过程是自动的,而接收过程不是(它的显式)。这就是类中函数的第一个参数必须是对象本身的原因。

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from origin"""
        return (self.x**2 + self.y**2) ** 0.5

调用:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init()定义了三个参数,但我们只传递了两个(6和8)。同样,distance()要求传递一个但零个参数。

为什么Python不抱怨此参数编号不匹配

通常,当我们调用带有某些参数的方法时,通过将方法的对象放在第一个参数之前来调用相应的类函数。因此,像obj.meth(args)之类的东西都会变成Class.meth(obj,args)。调用过程是自动的,而接收过程不是(它的显式)。

这就是类中函数的第一个参数必须是对象本身的原因。将此参数写为self只是一种约定。它不是关键字,在Python中没有特殊含义。我们可以使用其他名称(例如这样),但我强烈建议您不要使用。对于大多数开发人员来说,使用除self之外的其他名称并不受欢迎,这会降低代码的可读性(“可读性计数”)。

在第一个示例中,self.x是实例属性,而x是局部变量。它们不相同,并且位于不同的命名空间中。

自我在这里停留

许多人建议将self用作Python的关键字,例如C ++和Java。这将消除方法中形式参数列表中显式自我的多余使用。尽管这个想法看起来很有希望,但它不会发生。至少在不久的将来不会。主要原因是向后兼容。这是Python的创建者本人写的博客,解释了为何必须保留显式自我。

As explained in self in Python, Demystified

anything like obj.meth(args) becomes Class.meth(obj, args). The calling process is automatic while the receiving process is not (its explicit). This is the reason the first parameter of a function in class must be the object itself.

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from origin"""
        return (self.x**2 + self.y**2) ** 0.5

Invocations:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init() defines three parameters but we just passed two (6 and 8). Similarly distance() requires one but zero arguments were passed.

Why is Python not complaining about this argument number mismatch?

Generally, when we call a method with some arguments, the corresponding class function is called by placing the method’s object before the first argument. So, anything like obj.meth(args) becomes Class.meth(obj, args). The calling process is automatic while the receiving process is not (its explicit).

This is the reason the first parameter of a function in class must be the object itself. Writing this parameter as self is merely a convention. It is not a keyword and has no special meaning in Python. We could use other names (like this) but I strongly suggest you not to. Using names other than self is frowned upon by most developers and degrades the readability of the code (“Readability counts”).

In, the first example self.x is an instance attribute whereas x is a local variable. They are not the same and lie in different namespaces.

Self Is Here To Stay

Many have proposed to make self a keyword in Python, like this in C++ and Java. This would eliminate the redundant use of explicit self from the formal parameter list in methods. While this idea seems promising, it’s not going to happen. At least not in the near future. The main reason is backward compatibility. Here is a blog from the creator of Python himself explaining why the explicit self has to stay.


回答 8

还有一个非常简单的答案:根据python的禅定,“显式优于隐式”。

There is also another very simple answer: according to the zen of python, “explicit is better than implicit”.


TypeError:method()接受1个位置参数,但给出了2个

问题:TypeError:method()接受1个位置参数,但给出了2个

如果我有课…

class MyClass:

    def method(arg):
        print(arg)

…我用来创建对象的…

my_object = MyClass()

我这样称呼method("foo")

>>> my_object.method("foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 1 positional argument (2 given)

…为什么当我只给出一个参数时,Python告诉我给它两个参数?

If I have a class…

class MyClass:

    def method(arg):
        print(arg)

…which I use to create an object…

my_object = MyClass()

…on which I call method("foo") like so…

>>> my_object.method("foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 1 positional argument (2 given)

…why does Python tell me I gave it two arguments, when I only gave one?


回答 0

在Python中,这是:

my_object.method("foo")

…是语法糖,口译员在后台将其翻译为:

MyClass.method(my_object, "foo")

您可以看到,它确实有两个参数-从调用者的角度来看,只是第一个参数是隐式的。

这是因为大多数方法会对被调用的对象进行某些处理,因此需要某种方法在该方法内部引用该对象。按照惯例,第一个参数self在方法定义内调用:

class MyNewClass:

    def method(self, arg):
        print(self)
        print(arg)

如果您呼叫method("foo")的实例MyNewClass,它会按预期运作:

>>> my_new_object = MyNewClass()
>>> my_new_object.method("foo")
<__main__.MyNewClass object at 0x29045d0>
foo

有时(但不经常),您实际上不在乎您的方法所绑定的对象,在这种情况下,您可以使用内置函数来修饰该方法,staticmethod()例如:

class MyOtherClass:

    @staticmethod
    def method(arg):
        print(arg)

…在这种情况下,您无需self在方法定义中添加参数,它仍然有效:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo

In Python, this:

my_object.method("foo")

…is syntactic sugar, which the interpreter translates behind the scenes into:

MyClass.method(my_object, "foo")

…which, as you can see, does indeed have two arguments – it’s just that the first one is implicit, from the point of view of the caller.

This is because most methods do some work with the object they’re called on, so there needs to be some way for that object to be referred to inside the method. By convention, this first argument is called self inside the method definition:

class MyNewClass:

    def method(self, arg):
        print(self)
        print(arg)

If you call method("foo") on an instance of MyNewClass, it works as expected:

>>> my_new_object = MyNewClass()
>>> my_new_object.method("foo")
<__main__.MyNewClass object at 0x29045d0>
foo

Occasionally (but not often), you really don’t care about the object that your method is bound to, and in that circumstance, you can decorate the method with the builtin staticmethod() function to say so:

class MyOtherClass:

    @staticmethod
    def method(arg):
        print(arg)

…in which case you don’t need to add a self argument to the method definition, and it still works:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo

回答 1

遇到此类错误时要考虑的其他事项:

我遇到了这个错误消息,发现这篇文章很有帮助。事实证明,我重写了__init__()存在对象继承的位置。

继承的示例相当长,因此我将跳到一个不使用继承的更简单的示例:

class MyBadInitClass:
    def ___init__(self, name):
        self.name = name

    def name_foo(self, arg):
        print(self)
        print(arg)
        print("My name is", self.name)


class MyNewClass:
    def new_foo(self, arg):
        print(self)
        print(arg)


my_new_object = MyNewClass()
my_new_object.new_foo("NewFoo")
my_bad_init_object = MyBadInitClass(name="Test Name")
my_bad_init_object.name_foo("name foo")

结果是:

<__main__.MyNewClass object at 0x033C48D0>
NewFoo
Traceback (most recent call last):
  File "C:/Users/Orange/PycharmProjects/Chapter9/bad_init_example.py", line 41, in <module>
    my_bad_init_object = MyBadInitClass(name="Test Name")
TypeError: object() takes no parameters

PyCharm没有抓住这种错别字。Notepad ++也没有(其他编辑器/ IDE也可能)。

当然,这是一个“不带任何参数”的TypeError,与期望得到一个的“得到两个”没有太大区别,就Python中的对象初始化而言。

解决主题:在语法上正确的情况下将使用重载初始化程序,但在语法上正确的情况下将被使用,而是使用内置初始化程序。该对象不会期望/处理此问题,并且会引发错误。

如果出现sytax错误:修复很简单,只需编辑自定义init语句即可:

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

Something else to consider when this type of error is encountered:

I was running into this error message and found this post helpful. Turns out in my case I had overridden an __init__() where there was object inheritance.

The inherited example is rather long, so I’ll skip to a more simple example that doesn’t use inheritance:

class MyBadInitClass:
    def ___init__(self, name):
        self.name = name

    def name_foo(self, arg):
        print(self)
        print(arg)
        print("My name is", self.name)


class MyNewClass:
    def new_foo(self, arg):
        print(self)
        print(arg)


my_new_object = MyNewClass()
my_new_object.new_foo("NewFoo")
my_bad_init_object = MyBadInitClass(name="Test Name")
my_bad_init_object.name_foo("name foo")

Result is:

<__main__.MyNewClass object at 0x033C48D0>
NewFoo
Traceback (most recent call last):
  File "C:/Users/Orange/PycharmProjects/Chapter9/bad_init_example.py", line 41, in <module>
    my_bad_init_object = MyBadInitClass(name="Test Name")
TypeError: object() takes no parameters

PyCharm didn’t catch this typo. Nor did Notepad++ (other editors/IDE’s might).

Granted, this is a “takes no parameters” TypeError, it isn’t much different than “got two” when expecting one, in terms of object initialization in Python.

Addressing the topic: An overloading initializer will be used if syntactically correct, but if not it will be ignored and the built-in used instead. The object won’t expect/handle this and the error is thrown.

In the case of the sytax error: The fix is simple, just edit the custom init statement:

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

回答 2

简单来说。

在Python中,您应该将self参数作为第一个参数添加到类中所有已定义的方法中:

class MyClass:
  def method(self, arg):
    print(arg)

然后,您可以根据自己的直觉使用您的方法:

>>> my_object = MyClass()
>>> my_object.method("foo")
foo

这应该可以解决您的问题:)

为了更好地理解,您还可以阅读以下问题的答案:自我的目的是什么?

In simple words.

In Python you should add self argument as the first argument to all defined methods in classes:

class MyClass:
  def method(self, arg):
    print(arg)

Then you can use your method according to your intuition:

>>> my_object = MyClass()
>>> my_object.method("foo")
foo

This should solve your problem :)

For a better understanding, you can also read the answers to this question: What is the purpose of self?


回答 3

Python的新手**,以错误的方式使用Python的功能时遇到了这个问题。尝试从某处调用此定义:

def create_properties_frame(self, parent, **kwargs):

使用没有双星的通话会导致问题:

self.create_properties_frame(frame, kw_gsp)

TypeError:create_properties_frame()接受2个位置参数,但给出了3个

解决方案是**在参数中添加:

self.create_properties_frame(frame, **kw_gsp)

Newcomer to Python, I had this issue when I was using the Python’s ** feature in a wrong way. Trying to call this definition from somewhere:

def create_properties_frame(self, parent, **kwargs):

using a call without a double star was causing the problem:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properties_frame() takes 2 positional arguments but 3 were given

The solution is to add ** to the argument:

self.create_properties_frame(frame, **kw_gsp)

回答 4

当您未指定参数No __init__()或任何其他寻找方法时,就会发生这种情况。

例如:

class Dog:
    def __init__(self):
        print("IN INIT METHOD")

    def __unicode__(self,):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")

obj=Dog("JIMMY",1,2,3,"WOOF")

当您运行上述程序时,它给您这样的错误:

TypeError:__init __()接受1个位置参数,但给出了6个

我们如何摆脱这件事?

只需传递参数,__init__()寻找什么方法

class Dog:
    def __init__(self, dogname, dob_d, dob_m, dob_y, dogSpeakText):
        self.name_of_dog = dogname
        self.date_of_birth = dob_d
        self.month_of_birth = dob_m
        self.year_of_birth = dob_y
        self.sound_it_make = dogSpeakText

    def __unicode__(self, ):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")


obj = Dog("JIMMY", 1, 2, 3, "WOOF")
print(id(obj))

It occurs when you don’t specify the no of parameters the __init__() or any other method looking for.

For example:

class Dog:
    def __init__(self):
        print("IN INIT METHOD")

    def __unicode__(self,):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")

obj=Dog("JIMMY",1,2,3,"WOOF")

When you run the above programme, it gives you an error like that:

TypeError: __init__() takes 1 positional argument but 6 were given

How we can get rid of this thing?

Just pass the parameters, what __init__() method looking for

class Dog:
    def __init__(self, dogname, dob_d, dob_m, dob_y, dogSpeakText):
        self.name_of_dog = dogname
        self.date_of_birth = dob_d
        self.month_of_birth = dob_m
        self.year_of_birth = dob_y
        self.sound_it_make = dogSpeakText

    def __unicode__(self, ):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")


obj = Dog("JIMMY", 1, 2, 3, "WOOF")
print(id(obj))

回答 5

您实际上应该创建一个类:

class accum:
    def __init__(self):
        self.acc = 0
    def accumulator(self, var2add, end):
        if not end:
            self.acc+=var2add
    return self.acc

You should actually create a class:

class accum:
    def __init__(self):
        self.acc = 0
    def accumulator(self, var2add, end):
        if not end:
            self.acc+=var2add
    return self.acc

回答 6

就我而言,我忘记添加 ()

我正在这样调用方法

obj = className.myMethod

但是应该是这样

obj = className.myMethod()

In my case, I forgot to add the ()

I was calling the method like this

obj = className.myMethod

But it should be is like this

obj = className.myMethod()

回答 7

cls参数传递到@classmethod以解决此问题。

@classmethod
def test(cls):
    return ''

Pass cls parameter into @classmethod to resolve this problem.

@classmethod
def test(cls):
    return ''