【问题标题】:Empty class object in PythonPython中的空类对象
【发布时间】:2011-06-01 15:50:56
【问题描述】:

我正在教授一个关于面向对象编程的 Python 课程,并且在我复习如何解释类​​时,我看到了一个空的类定义:

class Employee:
    pass

然后该示例继续为此类的对象定义名称和其他属性:

john = Employee()
john.full_name = "john doe"

有趣!

我想知道是否有办法为这样的类的实例动态定义函数?类似:

john.greet() = print 'Hello, World!'

这在我的 Python 解释器中不起作用,但还有其他方法吗?

【问题讨论】:

标签: python oop empty-class


【解决方案1】:

类或多或少是对象属性dict 的精美包装器。当您实例化一个类时,您可以分配给它的属性,这些属性将存储在foo.__dict__;同样,您可以在foo.__dict__ 中查找您已经编写的任何属性。

这意味着您可以做一些简洁的动态操作,例如:

class Employee: pass
def foo(self): pass
Employee.foo = foo

以及分配给特定实例。 (编辑:添加self参数)

【讨论】:

  • 您的示例将无法按预期工作:john.foo() 将引发TypeError,因为没有self 参数. Putting a function on a class turns it to a method, so it needs to take a self. On the other hand, if you assign a function to a instance, it remains a function and has no access to the instance self`,这通常没有用.
  • @Jochen:你当然是对的。塔!致 OP:如果您了解出了什么问题以及为什么要修复它,它可能会有所帮助!
  • @Jochen,感谢您为此添加了一些颜色。如果定义的函数只是对象特定的(我认为),访问self 的重要性/有用性有多大。换句话说,这个函数不是为所有类型为 Employee 的对象定义的(除非你使用@katrielalex 的示例并使用 ClassName 定义它),而只是为类的实例(如我在 OP 中的“john”示例中)
  • @Ramy:除非你有一个真的真的很好的理由,否则你永远不应该这样做。在不修改其基类的情况下动态更改实例会给您带来各种麻烦,因为将违反各种应该成立的假设。 (例如,如果你用一个只为john 略有不同的方法覆盖了基类中的一个方法,那么这个错误将是一个要追查的皇家 PITA)相反,只需将所有方法放在基类上。
【解决方案2】:

试试lambda:

john.greet = lambda : print( 'hello world!' )

你能做到的:

john.greet()

编辑:感谢 Thomas K 的注释 - 这适用于 Python 3.2 而不适用于 Python2,其中 print 似乎是 statement。但这适用于lambdas,没有语句(对吗?抱歉,我只知道python3.2 (:)

【讨论】:

  • 这实际上不起作用:lambdas 不能包含语句。
  • @katrielalex - 在我的 python 3.2 上完美运行(当然,为print 添加了括号)。什么状态?
  • @Kirii:在 Python 2 中,print 是一个语句。您添加括号是因为在 Python 3 中,它变成了一个函数。
  • @Thomas K - 啊,谢谢!我不知道,print 是 Python2 中的语句。
  • 由于 OP 想要动态定义一个函数,print 示例可能不是最好的。 +1
【解决方案3】:

您还可以使用collection 标准模块中的“命名元组”。命名元组的工作方式类似于“普通”元组,但元素具有名称,您可以使用“点语法”访问元素。来自collection docs

>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22)     # instantiate with positional or keyword arguments
>>> p[0] + p[1]             # indexable like the plain tuple (11, 22)
33
>>> x, y = p                # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y               # fields also accessible by name
33
>>> p                       # readable __repr__ with a name=value style
Point(x=11, y=22)

【讨论】:

    【解决方案4】:

    你可以使用 AttrDict

    >>> from attrdict import AttrDict
    >>> my_object = AttrDict()
    >>> my_object.my_attribute = 'blah'
    >>> print my_object.my_attribute
    blah
    >>> 
    

    从 PyPI 安装 attrdict:

    pip install attrdict 
    

    它在其他情况下也很有用 - 例如当您需要对 dict 键进行属性访问时。

    【讨论】:

    • 当然,依赖之神的更多依赖
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-03
    • 2012-05-31
    相关资源
    最近更新 更多