检查嵌套字典中的成员资格


问题内容

这是对此的后续问题:

Python DictReader-
跳过缺少列的行?

原来我很傻,并且使用了错误的ID字段。

我在这里使用Python 3.x,顺便说一句。

我有一个员工的字典,由字符串“ directory_id”索引。每个值都是带有员工属性(电话号码,姓氏等)的嵌套字典。这些值之一是辅助ID,例如“
internal_id”,另一个是其管理者,称为“ manager_internal_id”。“
internal_id”字段是非强制性的,并非每个员工都有一个。

{'6443410501': {'manager_internal_id': '989634', 'givenName': 'Mary', 'phoneNumber': '+65 3434 3434', 'sn': 'Jones', 'internal_id': '434214'}
'8117062158': {'manager_internal_id': '180682', 'givenName': 'John', 'phoneNumber': '+65 3434 3434', 'sn': 'Ashmore', 'internal_id': ''}
'9227629067': {'manager_internal_id': '347394', 'givenName': 'Wright', 'phoneNumber': '+65 3434 3434', 'sn': 'Earl', 'internal_id': '257839'}
'1724696976': {'manager_internal_id': '907239', 'givenName': 'Jane', 'phoneNumber': '+65 3434 3434', 'sn': 'Bronte', 'internal_id': '629067'}

}

(为了使内容更易于阅读,以及出于隐私/合规性的原因,我对字段进行了一些简化)。

这里的问题是我们通过每个员工的directory_id索引(键),但是当我们查找他们的经理时,我们需要通过他们的“ internal_id”查找经理。

之前,当我们的字典使用internal_id作为键时,employee.keys()是internal_id的列表,而我正在对此进行成员资格检查。现在,我的if语句的最后一部分将不起作用,因为internal_ids是dict值的一部分,而不是键本身。

def lookup_supervisor(manager_internal_id, employees):
    if manager_internal_id is not None and manager_internal_id != "" and manager_internal_id in employees.keys():
        return (employees[manager_internal_id]['mail'], employees[manager_internal_id]['givenName'], employees[manager_internal_id]['sn'])
    else:
        return ('Supervisor Not Found', 'Supervisor Not Found', 'Supervisor Not Found')

因此,第一个问题是,如何修复if语句以检查dict的internal_ids列表中是否存在manager_internal_id?

我试过用employee.values()替换employee.keys(),那没用。另外,我希望获得一些更有效的方法,不确定是否有办法获取值的子集,尤其是employee
[directory_id] [‘internal_id’]的所有条目。

希望有一些Python的方法可以做到这一点,而无需使用大量的嵌套for / if循环。

我的第二个问题是,然后我该如何干净地返回所需的员工属性(邮件,给定名称,姓氏等)。我的for循环是遍历每个员工,然后调用lookup_supervisor。我在这里有点愚蠢/绊脚石。

def tidy_data(employees):
    for directory_id, data in employees.items():
        # We really shouldnt' be passing employees back and forth like this - hmm, classes?
        data['SupervisorEmail'], data['SupervisorFirstName'], data['SupervisorSurname'] = lookup_supervisor(data['manager_internal_id'], employees)

我应该重新设计我的数据结构吗?还是有另一种方法?

编辑: 我已经稍微调整了代码,请参见下文:

class Employees:

    def import_gd_dump(self, input_file="test.csv"):
        gd_extract = csv.DictReader(open(input_file), dialect='excel')
        self.employees = {row['directory_id']:row for row in gd_extract}

    def write_gd_formatted(self, output_file="gd_formatted.csv"):
        gd_output_fieldnames = ('internal_id', 'mail', 'givenName', 'sn', 'dbcostcenter', 'directory_id', 'manager_internal_id', 'PHFull', 'PHFull_message', 'SupervisorEmail', 'SupervisorFirstName', 'SupervisorSurname')
        try:
            gd_formatted = csv.DictWriter(open(output_file, 'w', newline=''), fieldnames=gd_output_fieldnames, extrasaction='ignore', dialect='excel')
        except IOError:
            print('Unable to open file, IO error (Is it locked?)')
            sys.exit(1)

        headers = {n:n for n in gd_output_fieldnames}
        gd_formatted.writerow(headers)
        for internal_id, data in self.employees.items():
            gd_formatted.writerow(data)

    def tidy_data(self):
        for directory_id, data in self.employees.items():
            data['PHFull'], data['PHFull_message'] = self.clean_phone_number(data['telephoneNumber'])
            data['SupervisorEmail'], data['SupervisorFirstName'], data['SupervisorSurname'] = self.lookup_supervisor(data['manager_internal_id'])

    def clean_phone_number(self, original_telephone_number):
        standard_format = re.compile(r'^\+(?P<intl_prefix>\d{2})\((?P<area_code>\d)\)(?P<local_first_half>\d{4})-(?P<local_second_half>\d{4})')
        extra_zero = re.compile(r'^\+(?P<intl_prefix>\d{2})\(0(?P<area_code>\d)\)(?P<local_first_half>\d{4})-(?P<local_second_half>\d{4})')
        missing_hyphen = re.compile(r'^\+(?P<intl_prefix>\d{2})\(0(?P<area_code>\d)\)(?P<local_first_half>\d{4})(?P<local_second_half>\d{4})')
        if standard_format.search(original_telephone_number):
            result = standard_format.search(original_telephone_number)
            return '0' + result.group('area_code') + result.group('local_first_half') + result.group('local_second_half'), ''
        elif extra_zero.search(original_telephone_number):
            result = extra_zero.search(original_telephone_number)
            return '0' + result.group('area_code') + result.group('local_first_half') + result.group('local_second_half'), 'Extra zero in area code - ask user to remediate. '
        elif missing_hyphen.search(original_telephone_number):
            result = missing_hyphen.search(original_telephone_number)
            return '0' + result.group('area_code') + result.group('local_first_half') + result.group('local_second_half'), 'Missing hyphen in local component - ask user to remediate. '
        else:
            return '', "Number didn't match format. Original text is: " + original_telephone_number

    def lookup_supervisor(self, manager_internal_id):
        if manager_internal_id is not None and manager_internal_id != "":# and manager_internal_id in self.employees.values():
            return (employees[manager_internal_id]['mail'], employees[manager_internal_id]['givenName'], employees[manager_internal_id]['sn'])
        else:
            return ('Supervisor Not Found', 'Supervisor Not Found', 'Supervisor Not Found')

if __name__ == '__main__':
    our_employees = Employees()
    our_employees.import_gd_dump('test.csv')
    our_employees.tidy_data()
    our_employees.write_gd_formatted()

我猜(1)。我正在寻找一种构造/存储Employee /
Employees的更好方法,并且(2)我在lookup_supervisor()方面尤其遇到问题。\

我应该创建一个雇员类,并将其嵌套在雇员中吗?

而且我是否应该做tidy_data()的工作,并在dict的项的for循环上调用clean_phone_number()和lookup_supervisor()?嗯
困惑的


问题答案:

我的python技能很差,所以我太无知了,无法在任何合理的时间写出我的想法。但是我确实知道如何进行OO分解。

为什么Employees班上要做所有的工作?整体的Employees类可以执行几种类型的操作:

  • 从文件读取和写入数据-aka序列化
  • 管理和访问单个员工的数据
  • 管理员工之间的关系。

我建议您创建一个类来处理列出的每个任务组。

定义一个Employee类来跟踪或记录员工数据并处理现场处理/整理任务。

使用Employees该类作为员工对象的容器。它可以处理诸如追踪员工主管的任务。

定义一个虚拟基类EmployeeLoader来定义一个接口(load,store,??)。然后为CSV文件序列化实现一个子类。(虚拟基类是可选的-
我不确定Python如何处理虚拟类,因此这甚至没有任何意义。)

所以:

  • 创建具有EmployeeCSVLoader文件名的实例。
  • 然后,加载程序可以构建Employees对象并解析文件。
  • 读取每个记录时,将创建一个新的Employee对象并将其存储在Employees对象中。
  • 现在,要求Employees对象填充主管链接。
  • 遍历Employees对象的雇员集合,并要求每个人整理自己。
  • 最后,让序列化对象处理更新数据文件。

为什么这种设计值得努力?

它使事情更容易理解。较小的,以任务为中心的对象更易于为其创建干净,一致的API。

如果发现您需要XML序列化格式,则添加新格式变得很简单。子类化您的虚拟加载器类,以处理XML解析/生成。现在,您可以在CSV和XML格式之间无缝切换。

总而言之,使用对象来简化和构建数据。将常见数据和行为分成单独的类。保持每个班级专注于一种类型的能力。如果您的类是集合,访问器,工厂,厨房水槽,则该API将永远无法使用:它太大了,并装载了不同的方法组。但是,如果您的课程仍在讨论中,那么它们将易于测试,维护,使用,重用和扩展。