动态创建的类方法可以在运行时知道它们的“创建”名称吗?

问题描述

我有一个类,我想使用它从文本文件提取数据(已解析),并希望使用动态创建的类方法来这样做,因为否则会出现很多重复的代码。每个创建的类方法都应与文本文件的特定行相关联,例如'.get_name()'->读取文本文件第0行的一部分。 我的想法是为“要创建的”方法名称和相应的行使用字典。

import sys
import inspect

test_file = [['Name=Jon Hancock'],['Date=16.08.2020'],['Author=Donald Duck']]

# intented method names
fn_names = {'get_name': 0,'get_date': 1,'get_author': 2}

class Filer():
    def __init__(self,file):
        self.file = file

def __get_line(cls):
    name = sys._getframe().f_code.co_name
    line = fn_names[name]        # <-- causes error because __get_line is not in fn_names
    print(sys._getframe().f_code.co_name)    # <-- '__get_line' 
    print(inspect.currentframe().f_code.co_name)    # <-- '__get_line'
    return print(cls.file[line][0].split('=')[1])

for key,val in fn_names.items():
    setattr(Filer,key,__get_line)

f = Filer(test_file)
f.get_author()
f.get_date()

当我尝试访问方法名称以将方法链接到文本文件中的指定行时,由于方法名称始终为__get_line而不是例如,我确实收到错误消息。 “ get_author”(我所希望的)。 我想解决此问题的另一种方法是使'__get_line'接受其他参数(行),并在'setattr()'期间传递val来设置它,如下所示:

def __get_line(cls,line):
    return print(cls.file[line][0].split('=')[1])

 for key,val in fn_names.items():
     setattr(Filer,__get_line(val))

但是,然后Python抱怨缺少1个参数(行)。

有什么办法解决吗?

解决方法

基于一些假设,我将提出一个更简单的解决方案。您的文件似乎包含键值对。您正在选择将行号映射到处理=符号之后的行右侧的函数。 Python通常不使用getter。属性更加好用和易于使用。通过使用property对象,您可以具有类似吸气剂的功能,但是您在这里确实不需要。

class Filer():
    def __init__(self,file):
        self.file = file
        for line in file:
            name,value = line[0].split('=',1)
            setattr(self,name.lower(),value)

这就是您所需要的。现在您可以使用结果了:

>>> f = Filer(test_file)
>>> f.author
'Donald Duck'

如果您希望拥有与您为每种属性建议的方法完全相同的可调用方法,那么我会单单建议您的方法,甚至根本没有方法。实际上,您可以在__getattr__中即时生成方法:

class Filer():
    def __init__(self,file):
        self.file = file

    def __getattr__(self,name):
        if name in fn_names:
            index = fn_names[name]
            def func(self):
                print(self.file[index][0].split('=',1)[1])
            func.__name__ = func.__qualname__ = name
            return func.__get__(self,type(self))
        return super().__getattr__(name)

调用__get__是一个额外的步骤,使该函数的行为就像一直是该类的方法一样。它将功能对象绑定到实例,即使该功能不属于该类也是如此。

例如:

>>> f = Filer(test_file)
>>> f.get_author
<bound method get_author of <__main__.Filer object at 0x0000023E7A247748>>
>>> f.get_author()
'Donald Duck'
,

考虑关闭键和值-请注意,您可以看到以下代码在https://ideone.com/qmoZCJ上运行:

import sys
import inspect

test_file = [['Name=Jon Hancock'],['Date=16.08.2020'],['Author=Donald Duck']]

# intented method names
fn_names = {'get_name': 0,'get_date': 1,'get_author': 2}

class Filer():
    def __init__(self,file):
        self.file = file

def getter(key,val):
    def _get_line(self):
        return self.file[val][0].split('=')[1]
    return _get_line
    
for key,val in fn_names.items():
    setattr(Filer,key,getter(key,val))

f = Filer(test_file)
print("Author: ",f.get_author())
print("Date: ",f.get_date())

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...