【问题标题】:How to Create a Python Method in Execution Time?如何在执行时创建 Python 方法?
【发布时间】:2017-06-19 17:25:36
【问题描述】:

以下代码运行良好,并展示了一种在执行时创建属性和方法的方法:

class Pessoa:
    pass
p = Pessoa( )
p.nome = 'fulano'

if hasattr(p, 'nome'):
    print(p) 
p.get_name = lambda self:'Sr.{}'.format(self.nome)

但是,我认为我创建方法的方式不正确。还有另一种动态创建方法的方法吗?

【问题讨论】:

  • 反引号是怎么回事?另外,x 是什么?
  • 什么是x? (您的意思是p?)您想添加方法to the class 以供所有对象使用还是只添加to a specific instance
  • 有人删除了反勾号,我只是修复了x,假设它是p。可以删除第一条和第三条评论。第二个,指向比我更好但更长的答案,可能应该进行编辑。

标签: python python-3.x


【解决方案1】:

以下是我如何向从库中导入的类添加方法。如果我修改了库,我将在下一次库升级时丢失更改。我无法创建新的派生类,因为我无法告诉库使用我修改后的实例。所以我通过添加缺少的方法来修补现有的类:

# Import the standard classes of the shapely library
import shapely.geometry

# Define a function that returns the points of the outer 
# and the inner polygons of a Polygon
def _coords_ext_int_polygon(self):
    exterior_coords = [self.exterior.coords[:]]
    interior_coords = [interior.coords[:] for interior in self.interiors]
    return exterior_coords, interior_coords

# Define a function that returns the points of the outer 
# and the inner polygons of a MultiPolygon
def _coords_ext_int_multi_polygon(self):
    if self.is_empty:
        return [], []
    exterior_coords = []
    interior_coords = []
    for part in self:
        i, e = part.coords_ext_int()
        exterior_coords += i
        interior_coords += e
    return exterior_coords, interior_coords

# Define a function that saves outer and inner points to a .pt file
def _export_to_pt_file(self, file_name=r'C:\WizardTemp\test.pt'):
    '''create a .pt file in the format that pleases thinkdesign'''
    e, i = self.coords_ext_int()
    with open(file_name, 'w') as f:
        for rings in (e, i):
            for ring in rings:
                for x, y in ring:
                    f.write('{} {} 0\n'.format(x, y))

# Add the functions to the definition of the classes
# by assigning the functions to new class members
shapely.geometry.Polygon.coords_ext_int = _coords_ext_int_polygon
shapely.geometry.Polygon.export_to_pt_file = _export_to_pt_file

shapely.geometry.MultiPolygon.coords_ext_int = _coords_ext_int_multi_polygon
shapely.geometry.MultiPolygon.export_to_pt_file = _export_to_pt_file

请注意,相同的函数定义可以分配给两个不同的类。

编辑

在我的示例中,我没有向我的类添加方法,而是向我安装的开源库 shapely 添加方法。

在您的帖子中,您使用p.get_name = ... 将成员添加到对象实例p。我先定义一个函数_xxx(),然后用class.xxx = _xxx将它添加到类定义中。

我不知道你的用例,但通常你将变量添加到实例中,然后将方法添加到类定义中,这就是我向你展示如何将方法添加到类定义而不是实例的原因。

Shapely 管理几何对象并提供计算多边形面积、相互添加或减去多边形以及许多其他非常酷的东西的方法。

我的问题是我需要一些开箱即用的方法。

在我的示例中,我创建了自己的方法,该方法返回外部轮廓的点列表和内部轮廓的点列表。我做了两种方法,一种用于Polygon 类,另一种用于MultiPolygon 类。

我还需要一种将所有点导出为.pt 文件格式的方法。在这种情况下,我只制作了一种适用于 PolygonMultiPolygon 类的方法。

此代码位于名为shapely_monkeypatch.py 的模块中(请参阅monkey patch)。导入模块时,定义了名称以_ 开头的函数,然后将它们分配给名称不带_ 的现有类。 (Python 中的约定是使用_ 来命名仅供内部使用的变量或函数。)

【讨论】:

  • 对不起,我在这里完全感到困惑。这是什么?
  • 我在代码中添加了一些注释并添加了一些解释。让我知道是否清楚。
【解决方案2】:

在 Python 3 中有两种动态创建方法的方法:

  • 在类本身上创建一个方法:只需将一个函数分配给一个成员;类的所有对象都可以访问它,即使它们是在创建方法之前创建的:

    >>> class A:          # create a class
        def __init__(self, v):
            self.val = v
    
    
    >>> a = A(1)             # create an instance
    >>> def double(self):    # define a plain function
        self.val *= 2
    
    >>> A.double = double    # makes it a method on the class
    >>> a.double()           # use it...
    >>> a.val
    2
    
  • 在类的实例上创建一个方法。由于types 模块,这在 Python 3 中成为可能:

    >>> def add(self, x):    # create a plain function
        self.val += x
    
    
    >>> a.add = types.MethodType(add, a)  # make it a method on an instance
    >>> a.add(2)
    >>> a.val
    4
    >>> b = A(1)
    >>> b.add(2)                 # chokes on another instance
    Traceback (most recent call last):
      File "<pyshell#55>", line 1, in <module>
        b.add(2)
    AttributeError: 'A' object has no attribute 'add'
    >>> type(a.add)               # it is a true method on a instance
    <class 'method'>
    >>> type(a.double)
    <class 'method'>
    

方法 1(在类上)的轻微变化可用于创建静态或类方法:

>>> def static_add(a,b):
    return a+b

>>> A.static_add = staticmethod(static_add)
>>> a.static_add(3,4)
7
>>> def show_class(cls):
    return str(cls)

>>> A.show_class = classmethod(show_class)
>>> b.show_class()
"<class '__main__.A'>"

【讨论】:

    【解决方案3】:

    [虽然在 Steven Rumbalski 的评论中确实已经回答了这个问题,指向两个独立的问题,但我在这里添加了一个简短的组合答案。]

    是的,你说得对,这没有正确定义方法。

    >>> class C:
    ...   pass
    ...
    >>> p = C()
    >>> p.name = 'nickie'
    >>> p.get_name = lambda self: 'Dr. {}'.format(self.name)
    >>> p.get_name()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: <lambda>() takes exactly 1 argument (0 given)
    

    以下是调用存储在对象p 的名为get_name 的属性中的函数 的方法:

    >>> p.get_name(p)
    'Dr. nickie'
    

    要正确动态定义实例方法,请查看relevant question 的答案。

    如果要动态定义一个类方法,则必须将其定义为:

    >>> C.get_name = lambda self: 'Dr. {}'.format(self.name)
    

    虽然该方法将被添加到现有对象中,但这不适用于p(因为它已经有自己的属性get_name)。但是,对于一个新对象:

    >>> q = C()
    >>> q.name = 'somebody'
    >>> q.get_name()
    'Dr. somebody'
    

    而且(显然),对于没有name 属性的对象,该方法将失败:

    >>> r = C()
    >>> r.get_name()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 1, in <lambda>
    AttributeError: C instance has no attribute 'name'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-21
      • 2014-12-24
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多