动态创建的 class 方法能否在运行时知道它们的 'created' 名称?
Can dynamically created class methods know their 'created' name at runtime?
我有一个 class,我想用它从文本文件(已解析)中提取数据,我想使用动态创建的 class 方法来提取数据,否则会有很多重复的代码。每个创建的 class 方法都应与文本文件的特定行相关联,例如'.get_name()' --> 读取文本文件第 0 行的一部分。
我的想法是为 'to-be-created' 方法名称和相应的行使用字典。
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()
当我尝试访问方法名称到 link 文本文件中指定行的方法时,我确实得到了一个错误,因为方法名称始终是 '__get_line' 而不是例如'get_author'(我所希望的)。
我想解决这个问题的另一种方法是让 '__get_line' 接受一个额外的参数(行)并通过在 'the setattr()' 期间传递 val 来设置它,如下所示:
def __get_line(cls, line):
return print(cls.file[line][0].split('=')[1])
和
for key, val in fn_names.items():
setattr(Filer, key, __get_line(val))
然而,Python 抱怨缺少 1 个参数(行)。
有什么解决办法吗?
我会根据一些假设提出一个更简单的解决方案。您的文件似乎由 key-value 对组成。您选择将行号映射到一个函数,该函数处理通过 =
符号的行的右侧。 Python 通常不使用吸气剂。属性更好,更易于使用。您可以通过使用 property
对象来获得 getter-like 功能,但您实际上不需要它。
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'
如果您希望拥有与您为每个属性建议的方法完全相同的可调用方法,我会 one-up 您的建议,甚至没有方法开始。您实际上可以在 __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__
是一个额外的步骤,它使该函数的行为就像它一直是 class 的方法一样。它将函数对象绑定到实例,即使函数不是 class.
的一部分
例如:
>>> 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())
我有一个 class,我想用它从文本文件(已解析)中提取数据,我想使用动态创建的 class 方法来提取数据,否则会有很多重复的代码。每个创建的 class 方法都应与文本文件的特定行相关联,例如'.get_name()' --> 读取文本文件第 0 行的一部分。 我的想法是为 'to-be-created' 方法名称和相应的行使用字典。
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()
当我尝试访问方法名称到 link 文本文件中指定行的方法时,我确实得到了一个错误,因为方法名称始终是 '__get_line' 而不是例如'get_author'(我所希望的)。 我想解决这个问题的另一种方法是让 '__get_line' 接受一个额外的参数(行)并通过在 'the setattr()' 期间传递 val 来设置它,如下所示:
def __get_line(cls, line):
return print(cls.file[line][0].split('=')[1])
和
for key, val in fn_names.items():
setattr(Filer, key, __get_line(val))
然而,Python 抱怨缺少 1 个参数(行)。
有什么解决办法吗?
我会根据一些假设提出一个更简单的解决方案。您的文件似乎由 key-value 对组成。您选择将行号映射到一个函数,该函数处理通过 =
符号的行的右侧。 Python 通常不使用吸气剂。属性更好,更易于使用。您可以通过使用 property
对象来获得 getter-like 功能,但您实际上不需要它。
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'
如果您希望拥有与您为每个属性建议的方法完全相同的可调用方法,我会 one-up 您的建议,甚至没有方法开始。您实际上可以在 __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__
是一个额外的步骤,它使该函数的行为就像它一直是 class 的方法一样。它将函数对象绑定到实例,即使函数不是 class.
例如:
>>> 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())