├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── README_en.md ├── cookbook ├── __init__.py ├── c01 │ ├── __init__.py │ ├── p03_nitem.py │ ├── p04_nlargest.py │ ├── p05_priority_queue.py │ ├── p06_multidict.py │ ├── p07_ordered_dict.py │ ├── p08_calculate_dict.py │ ├── p09_dict_common.py │ ├── p10_remove_duplicate.py │ ├── p11_naming_slice.py │ ├── p12_mostfreq_items.py │ ├── p13_sort_dictlist.py │ ├── p14_sort_nocompare.py │ ├── p15_group.py │ ├── p16_filter.py │ ├── p17_subdict.py │ ├── p18_nameseq.py │ ├── p19_trans_reduce.py │ └── p20_combine_map.py ├── c02 │ ├── __init__.py │ ├── p01_splitstr.py │ ├── p02_str_start.py │ ├── p03_unix_match.py │ ├── p04_match_search.py │ ├── p05_search_replace.py │ ├── p06_case_insensitive.py │ ├── p07_shortest_match.py │ ├── p08_multiline_match.py │ ├── p09_normal_unicode.py │ ├── p10_re_unicode.py │ ├── p11_strip.py │ ├── p12_translate.py │ ├── p13_align_str.py │ ├── p14_join_str.py │ ├── p15_var_string.py │ ├── p16_textwrap.py │ ├── p17_html_xml.py │ ├── p18_tokenize.py │ ├── p19_descent_parser.py │ └── p20_byte_str.py ├── c03 │ ├── __init__.py │ ├── p01_round.py │ ├── p02_accurate_decimal.py │ ├── p03_format_number.py │ ├── p04_bin_octal.py │ ├── p05_int_bytes.py │ ├── p06_complex.py │ ├── p07_inf_nan.py │ ├── p08_fraction.py │ ├── p09_array_numpy.py │ ├── p10_matrix_linear.py │ ├── p11_random_num.py │ ├── p12_datatime.py │ ├── p13_last_friday.py │ ├── p14_month_range.py │ ├── p15_str_datetime.py │ └── p16_timezone.py ├── c04 │ ├── __init__.py │ ├── p01_manual_iterator.py │ ├── p02_delegate_iter.py │ ├── p03_generator_pattern.py │ ├── p04_iterator_protocol.py │ ├── p05_reverse_iterate.py │ ├── p06_generator_extrastate.py │ ├── p07_iterator_slice.py │ ├── p08_skip_iterable.py │ ├── p09_iter_permutation.py │ ├── p10_iterate_index.py │ ├── p11_iterate_simultaneous.py │ ├── p12_iterate_separate.py │ ├── p13_process_pipline.py │ ├── p14_flatten_sequence.py │ ├── p15_merge_sorted.py │ └── p16_iterate_while.py ├── c05 │ ├── __init__.py │ ├── p01_rw_text.py │ ├── p02_print_tofile.py │ ├── p03_print_sepend.py │ ├── p04_rw_binary.py │ ├── p05_write_notexist.py │ ├── p06_string_io.py │ ├── p07_gzip_bz2.py │ ├── p08_iterate_fixedsize.py │ ├── p09_read_tobuffer.py │ ├── p10_memery_mapping.py │ ├── p11_pathnames.py │ ├── p12_file_existence.py │ ├── p13_dir_listfile.py │ ├── p14_bypass_encode.py │ ├── p15_print_badfile.py │ ├── p16_change_opencode.py │ ├── p17_bytes_tofile.py │ ├── p18_file_descriptor.py │ ├── p19_temp_file.py │ ├── p20_serial_ports.py │ └── p21_serialize_object.py ├── c06 │ ├── __init__.py │ ├── data.json │ ├── p01_rw_csv.py │ ├── p02_rw_json.py │ ├── p03_simple_xml.py │ ├── p04_huge_xml.py │ ├── p05_dict_toxml.py │ ├── p06_rw_xml.py │ ├── p07_namespace_xml.py │ ├── p08_database.py │ ├── p09_codec_hex.py │ ├── p10_codec_base64.py │ ├── p11_rw_barray.py │ ├── p12_var_binary.py │ ├── pred.xml │ └── stocks.csv ├── c07 │ ├── __init__.py │ ├── p02_keyarg_only.py │ ├── p03_func_annotate.py │ ├── p05_default_argument.py │ ├── p06_anony_func.py │ ├── p08_partial.py │ ├── p09_class_to_func.py │ ├── p10_callback.py │ ├── p11_inline_callback.py │ └── p12_closure_access.py ├── c08 │ ├── __init__.py │ ├── p01_str_represent.py │ ├── p02_custom_format.py │ ├── p03_context_protocol.py │ ├── p04_slots.py │ ├── p05_encapsulate_name.py │ ├── p06_managed_attribute.py │ ├── p07_super_method.py │ ├── p08_extend_property.py │ ├── p09_descriptor.py │ ├── p10_lazy_property.py │ ├── p11_simplify_init.py │ ├── p12_abstract_interface.py │ ├── p13_type_system.py │ ├── p14_custom_container.py │ ├── p15_delegate_attribute.py │ ├── p16_more_constructor.py │ ├── p17_without_init.py │ ├── p18_mixin_classes.py │ ├── p19_stateful_object.py │ ├── p20_invoke_bystr.py │ ├── p21_vistor_pattern.py │ ├── p22_vistor_norecursiion.py │ ├── p23_weakref.py │ ├── p24_class_compare.py │ └── p25_cached_objects.py ├── c09 │ ├── __init__.py │ ├── p01_wrap_function.py │ ├── p02_preserve_metadata.py │ ├── p03_unwrap_decorator.py │ ├── p04_decorator_argument.py │ ├── p05_adjust_attribute.py │ ├── p06_optarg_decorator.py │ ├── p07_typecheck.py │ ├── p08_inclass_decorator.py │ ├── p09_class_decorator.py │ ├── p10_static_decorator.py │ ├── p11_add_argument.py │ ├── p12_patch_class.py │ ├── p13_instance_create.py │ ├── p14_attribute_order.py │ ├── p15_meta_optional_arg.py │ ├── p16_enforce_args.py │ ├── p17_code_convention.py │ ├── p18_define_classes.py │ ├── p19_define_init.py │ ├── p20_multiple_dispatch.py │ ├── p21_avoid_repetitive.py │ ├── p22_context_manager.py │ ├── p23_local_side.py │ ├── p24_analyze_source.py │ └── p25_disassemble_bytecode.py ├── c10 │ ├── __init__.py │ ├── p02_control_import.py │ └── p12_import_patch.py ├── c11 │ ├── p01_.py │ ├── p02_.py │ ├── p03_.py │ ├── p04_.py │ ├── p05_.py │ ├── p06_.py │ ├── p07_.py │ ├── p08_.py │ ├── p09_.py │ ├── p10_.py │ ├── p11_.py │ ├── p12_.py │ └── p13_.py ├── c12 │ ├── __init__.py │ ├── p01_start_stop_thread.py │ ├── p02_.py │ ├── p03_.py │ ├── p04_.py │ ├── p05_.py │ ├── p06_.py │ ├── p07_.py │ ├── p08_.py │ ├── p09_.py │ ├── p10_.py │ ├── p11_.py │ ├── p12_.py │ ├── p13_.py │ └── p14_.py ├── c13 │ ├── p01_.py │ ├── p02_.py │ ├── p03_.py │ ├── p04_.py │ ├── p05_.py │ ├── p06_.py │ ├── p07_.py │ ├── p08_.py │ ├── p09_.py │ ├── p10_.py │ ├── p11_.py │ ├── p12_.py │ ├── p13_.py │ ├── p14_.py │ └── p15_.py ├── c14 │ ├── p01_.py │ ├── p02_.py │ ├── p03_.py │ ├── p04_.py │ ├── p05_.py │ ├── p06_.py │ ├── p07_.py │ ├── p08_.py │ ├── p09_.py │ ├── p10_.py │ ├── p11_.py │ ├── p12_.py │ ├── p13_.py │ └── p14_.py ├── c15 │ ├── p01_.py │ ├── p02_.py │ ├── p03_.py │ ├── p04_.py │ ├── p05_.py │ ├── p06_.py │ ├── p07_.py │ ├── p08_.py │ ├── p09_.py │ ├── p10_.py │ ├── p11_.py │ ├── p12_.py │ ├── p13_.py │ ├── p14_.py │ ├── p15_.py │ ├── p16_.py │ ├── p17_.py │ ├── p18_.py │ ├── p19_.py │ ├── p20_.py │ └── p21_.py └── somefile.txt ├── exts ├── chinese_search.py ├── main.dic ├── smallseg.py ├── suffix.dic ├── wuxiong.jpg └── zh.py ├── make.bat ├── notebook ├── fetch_cookbook.py └── ipynb │ ├── 第一章:数据结构和算法.ipynb │ ├── 第一章:数据结构和算法 │ ├── p01_unpack_sequence_into_separate_variables.ipynb │ ├── p02_unpack_elements_from_iterables.ipynb │ ├── p03_keep_last_n_items.ipynb │ ├── p04_find_largest_or_smallest_n_items.ipynb │ ├── p05_implement_a_priority_queue.ipynb │ ├── p06_map_keys_to_multiple_values_in_dict.ipynb │ ├── p07_keep_dict_in_order.ipynb │ ├── p08_calculating_with_dict.ipynb │ ├── p09_find_commonalities_in_dicts.ipynb │ ├── p10_remove_duplicates_from_seq_order.ipynb │ ├── p11_naming_slice.ipynb │ ├── p12_determine_most_freqently_items_in_seq.ipynb │ ├── p13_sort_list_of_dicts_by_key.ipynb │ ├── p14_sort_objects_without_compare_support.ipynb │ ├── p15_group_records_based_on_field.ipynb │ ├── p16_filter_sequence_elements.ipynb │ ├── p17_extract_subset_of_dict.ipynb │ ├── p18_map_names_to_sequence_elements.ipynb │ ├── p19_transform_and_reduce_data_same_time.ipynb │ └── p20_combine_multiple_map_to_single_map.ipynb │ ├── 第七章:函数.ipynb │ ├── 第七章:函数 │ ├── p01_functions_that_accept_any_number_arguments.ipynb │ ├── p02_functions_that_only_accept_keyword_arguments.ipynb │ ├── p03_attach_informatinal_matadata_to_function_arguments.ipynb │ ├── p04_return_multiple_values_from_function.ipynb │ ├── p05_define_functions_with_default_arguments.ipynb │ ├── p06_define_anonymous_or_inline_functions.ipynb │ ├── p07_capturing_variables_in_anonymous_functions.ipynb │ ├── p08_make_callable_with_fewer_arguments.ipynb │ ├── p09_replace_single_method_classes_with_functions.ipynb │ ├── p10_carry_extra_state_with_callback_functions.ipynb │ ├── p11_inline_callback_functions.ipynb │ └── p12_access_variables_defined_inside_closure.ipynb │ ├── 第三章:数字日期和时间.ipynb │ ├── 第三章:数字日期和时间 │ ├── p01_round_number.ipynb │ ├── p02_accurate_decimal_calculations.ipynb │ ├── p03_format_numbers_for_output.ipynb │ ├── p04_binary_octal_hexadecimal_int.ipynb │ ├── p05_pack_unpack_large_int_from_bytes.ipynb │ ├── p06_complex_math.ipynb │ ├── p07_infinity_and_nan.ipynb │ ├── p08_calculating_with_fractions.ipynb │ ├── p09_calculating_with_large_num_arrays.ipynb │ ├── p10_matrix_and_linear_algebra_calculation.ipynb │ ├── p11_pick_things_at_random.ipynb │ ├── p12_convert_days_to_seconds_and_others.ipynb │ ├── p13_determine_last_friday_date.ipynb │ ├── p14_date_range_for_current_month.ipynb │ ├── p15_convert_strings_into_datetimes.ipynb │ └── p16_manipulate_dates_involving_timezone.ipynb │ ├── 第九章:元编程.ipynb │ ├── 第九章:元编程 │ ├── p01_put_wrapper_around_function.ipynb │ ├── p02_preserve_function_metadata_when_write_decorators.ipynb │ ├── p03_unwrapping_decorator.ipynb │ ├── p04_define_decorator_that_takes_arguments.ipynb │ ├── p05_define_decorator_with_user_adjustable_attributes.ipynb │ ├── p06_define_decorator_that_takes_optional_argument.ipynb │ ├── p07_enforcing_type_check_on_function_using_decorator.ipynb │ ├── p08_define_decorators_as_part_of_class.ipynb │ ├── p09_define_decorators_as_classes.ipynb │ ├── p10_apply_decorators_to_class_and_static_methods.ipynb │ ├── p11_write_decorators_that_add_arguments_to_functions.ipynb │ ├── p12_using_decorators_to_patch_class_definitions.ipynb │ ├── p13_using_mataclass_to_control_instance_creation.ipynb │ ├── p14_capture_class_attribute_definition_order.ipynb │ ├── p15_define_metaclass_that_takes_optional_arguments.ipynb │ ├── p16_enforce_argument_signature_on_args_kwargs.ipynb │ ├── p17_enforce_coding_conventions_in_classes.ipynb │ ├── p18_define_classes_programmatically.ipynb │ ├── p19_initializing_class_members_at_definition_time.ipynb │ ├── p20_implement_multiple_dispatch_with_function_annotations.ipynb │ ├── p21_avoid_repetitive_property_methods.ipynb │ ├── p22_define_context_managers_the_easy_way.ipynb │ ├── p23_executing_code_with_local_side_effects.ipynb │ ├── p24_parse_and_analyzing_python_source.ipynb │ └── p25_disassembling_python_byte_code.ipynb │ ├── 第二章:字符串和文本.ipynb │ ├── 第二章:字符串和文本 │ ├── p01_split_string_on_multiple_delimiters.ipynb │ ├── p02_match_text_at_start_end.ipynb │ ├── p03_match_strings_with_shell_wildcard.ipynb │ ├── p04_match_and_search_text.ipynb │ ├── p05_search_and_replace_text.ipynb │ ├── p06_search_replace_case_insensitive.ipynb │ ├── p07_specify_regexp_for_shortest_match.ipynb │ ├── p08_regexp_for_multiline_partterns.ipynb │ ├── p09_normalize_unicode_text_to_regexp.ipynb │ ├── p10_work_with_unicode_in_regexp.ipynb │ ├── p11_strip_unwanted_characters.ipynb │ ├── p12_sanitizing_clean_up_text.ipynb │ ├── p13_aligning_text_strings.ipynb │ ├── p14_combine_and_concatenate_strings.ipynb │ ├── p15_interpolating_variables_in_strings.ipynb │ ├── p16_reformat_text_to_fixed_number_columns.ipynb │ ├── p17_handle_html_xml_in_text.ipynb │ ├── p18_tokenizing_text.ipynb │ ├── p19_writing_recursive_descent_parser.ipynb │ └── p20_perform_text_operations_on_byte_string.ipynb │ ├── 第五章:文件与IO.ipynb │ ├── 第五章:文件与IO │ ├── p01_read_write_text_data.ipynb │ ├── p02_printing_to_file.ipynb │ ├── p03_print_with_different_separator_or_line_ending.ipynb │ ├── p04_read_write_binary_data.ipynb │ ├── p05_write_to_file_not_exist.ipynb │ ├── p06_io_operations_on_string.ipynb │ ├── p07_read_write_compressed_datafiles.ipynb │ ├── p08_iterate_over_fixed_sized_records.ipynb │ ├── p09_read_binary_data_into_mutable_buffer.ipynb │ ├── p10_memory_mapping_binary_files.ipynb │ ├── p11_manipulating_pathnames.ipynb │ ├── p12_test_for_the_existence_of_file.ipynb │ ├── p13_get_directory_listing.ipynb │ ├── p14_bypassing_filename_encoding.ipynb │ ├── p15_printing_bad_filenames.ipynb │ ├── p16_add_change_encoding_of_already_open_file.ipynb │ ├── p17_write_bytes_to_text_file.ipynb │ ├── p18_wrap_existing_file_descriptor_as_file_object.ipynb │ ├── p19_make_temporary_files_and_directories.ipynb │ ├── p20_communicating_with_serial_ports.ipynb │ └── p21_serializing_python_objects.ipynb │ ├── 第八章:类与对象.ipynb │ ├── 第八章:类与对象 │ ├── p01_change_string_representation_of_instances.ipynb │ ├── p02_customizing_string_formatting.ipynb │ ├── p03_make_objects_support_context_management_protocol.ipynb │ ├── p04_save_memory_when_create_large_number_instances.ipynb │ ├── p05_encapsulating_names_in_class.ipynb │ ├── p06_create_managed_attributes.ipynb │ ├── p07_calling_method_on_parent_class.ipynb │ ├── p08_extending_property_in_subclass.ipynb │ ├── p09_create_new_kind_of_class_or_instance_attribute.ipynb │ ├── p10_using_lazily_computed_properties.ipynb │ ├── p11_simplify_initialization_of_data_structure.ipynb │ ├── p12_define_interface_or_abstract_base_class.ipynb │ ├── p13_implementing_data_model_or_type_system.ipynb │ ├── p14_implementing_custom_containers.ipynb │ ├── p15_delegating_attribute_access.ipynb │ ├── p16_define_more_than_one_constructor_in_class.ipynb │ ├── p17_create_instance_without_invoking_init_method.ipynb │ ├── p18_extending_classes_with_mixins.ipynb │ ├── p19_implements_stateful_objects_or_state_machines.ipynb │ ├── p20_call_method_on_object_by_string_name.ipynb │ ├── p21_implementing_visitor_pattern.ipynb │ ├── p22_implementing_visitor_pattern_without_recursion.ipynb │ ├── p23_managing_memory_in_cyclic_data_structures.ipynb │ ├── p24_making_classes_support_comparison_operations.ipynb │ └── p25_creating_cached_instances.ipynb │ ├── 第六章:数据编码和处理.ipynb │ ├── 第六章:数据编码和处理 │ ├── p01_read_write_csv_data.ipynb │ ├── p02_read-write_json_data.ipynb │ ├── p03_parse_simple_xml_data.ipynb │ ├── p04_parse_huge_xml_files_incrementally.ipynb │ ├── p05_turning_dictionary_into_xml.ipynb │ ├── p06_parse_modify_rewrite_xml.ipynb │ ├── p07_parse_xml_documents_with_namespaces.ipynb │ ├── p08_interact_with_relational_database.ipynb │ ├── p09_decode_encode_hexadecimal_digits.ipynb │ ├── p10_decode_encode_base64.ipynb │ ├── p11_read_write_binary_arrays_of_structures.ipynb │ ├── p12_read_nested_and_variable_sized_binary_structures.ipynb │ └── p13_summarizing_and_perform_statistics.ipynb │ ├── 第十一章:网络与Web编程.ipynb │ ├── 第十一章:网络与Web编程 │ ├── p01_interact_with_http_services_as_client.ipynb │ ├── p02_creating_tcp_server.ipynb │ ├── p03_creating_udp_server.ipynb │ ├── p04_generate_range_of_ip_addresses_from_cidr_address.ipynb │ ├── p05_creating_simple_rest_based_interface.ipynb │ ├── p06_implement_simple_remote_procedure_call_with_xml_rpc.ipynb │ ├── p07_communicate_simply_between_interpreters.ipynb │ ├── p08_implementing_remote_procedure_calls.ipynb │ ├── p09_authenticating_clients_simply.ipynb │ ├── p10_add_ssl_to_network_services.ipynb │ ├── p11_pass_socket_file_descriptor_between_processes.ipynb │ ├── p12_understanding_event_driven_io.ipynb │ └── p13_sending_receiving_large_arrays.ipynb │ ├── 第十三章:脚本编程与系统管理.ipynb │ ├── 第十三章:脚本编程与系统管理 │ ├── p01_accept_input_via_redirect_pips_or_input_files.ipynb │ ├── p02_terminate_program_with_an_error_message.ipynb │ ├── p03_parsing_command_line_options.ipynb │ ├── p04_prompt_for_password_at_runtime.ipynb │ ├── p05_getting_terminal_size.ipynb │ ├── p06_executing_external_command_and_get_its_output.ipynb │ ├── p07_copy_move_files_and_directories.ipynb │ ├── p08_creating_and_unpacking_archives.ipynb │ ├── p09_find_files_by_name.ipynb │ ├── p10_read_configuration_files.ipynb │ ├── p11_add_logging_to_simple_scripts.ipynb │ ├── p12_add_logging_to_libraries.ipynb │ ├── p13_making_stopwatch_timer.ipynb │ ├── p14_putting_limits_on_memory_and_cpu_usage.ipynb │ └── p15_luanch_a_web_browser.ipynb │ ├── 第十二章:并发编程.ipynb │ ├── 第十二章:并发编程 │ ├── p01_start_stop_thread.ipynb │ ├── p02_determining_if_thread_has_started.ipynb │ ├── p03_communicating_between_threads.ipynb │ ├── p04_locking_critical_sections.ipynb │ ├── p05_locking_with_deadlock_avoidance.ipynb │ ├── p06_storing_thread_specific_state.ipynb │ ├── p07_creating_thread_pool.ipynb │ ├── p08_perform_simple_parallel_programming.ipynb │ ├── p09_dealing_with_gil_stop_worring_about_it.ipynb │ ├── p10_defining_an_actor_task.ipynb │ ├── p11_implement_publish_subscribe_messaging.ipynb │ ├── p12_using_generators_as_alternative_to_threads.ipynb │ ├── p13_polling_multiple_thread_queues.ipynb │ └── p14_launching_daemon_process_on_unix.ipynb │ ├── 第十五章:C语言扩展.ipynb │ ├── 第十五章:C语言扩展 │ ├── p01_access_ccode_using_ctypes.ipynb │ ├── p02_write_simple_c_extension_module.ipynb │ ├── p03_write_extension_function_operate_on_arrays.ipynb │ ├── p04_manage_opaque_pointers_in_c_extension_modules.ipynb │ ├── p05_define_and_export_c_api_from_extension_modules.ipynb │ ├── p06_calling_python_from_c.ipynb │ ├── p07_release_the_gil_in_c_extensions.ipynb │ ├── p08_mix_threads_from_c_and_python.ipynb │ ├── p09_wrap_c_code_with_swig.ipynb │ ├── p10_wrap_existing_c_code_with_cython.ipynb │ ├── p11_use_cython_to_write_high_performance_array_operation.ipynb │ ├── p12_turning_function_pointer_into_callable.ipynb │ ├── p13_pass_null_terminated_string_to_c_libraries.ipynb │ ├── p14_pass_unicode_strings_to_c_libraries.ipynb │ ├── p15_converting_c_string_to_python.ipynb │ ├── p16_work_with_c_strings_of_dubious_encoding.ipynb │ ├── p17_pass_filenames_to_c_extensions.ipynb │ ├── p18_pass_open_files_to_c_extensions.ipynb │ ├── p19_read_file_like_objects_from_c.ipynb │ ├── p20_consuming_an_iterable_from_c.ipynb │ └── p21_diagnosing_segmentation_faults.ipynb │ ├── 第十四章:测试、调试和异常.ipynb │ ├── 第十四章:测试、调试和异常 │ ├── p01_testing_output_sent_to_stdout.ipynb │ ├── p02_patching_objects_in_unit_tests.ipynb │ ├── p03_testing_for_exceptional_conditions_in_unit_tests.ipynb │ ├── p04_logging_test_output_to_file.ipynb │ ├── p05_skip_or_anticipate_test_failures.ipynb │ ├── p06_handle_multiple_exceptions.ipynb │ ├── p07_catching_all_exceptions.ipynb │ ├── p08_creating_custom_exceptions.ipynb │ ├── p09_raise_exception_in_response_to_another_exception.ipynb │ ├── p10_reraising_the_last_exception.ipynb │ ├── p11_issuing_warning_messages.ipynb │ ├── p12_debugging_basic_program_crashes.ipynb │ ├── p13_profiling_and_timing_your_program.ipynb │ └── p14_make_your_program_run_faster.ipynb │ ├── 第十章:模块与包.ipynb │ ├── 第十章:模块与包 │ ├── p01_make_hierarchical_package_of_modules.ipynb │ ├── p02_control_the_import_of_everything.ipynb │ ├── p03_import_submodules_by_relative_names.ipynb │ ├── p04_split_module_into_multiple_files.ipynb │ ├── p05_separate_directories_import_by_namespace.ipynb │ ├── p06_reloading_modules.ipynb │ ├── p07_make_directory_or_zip_runnable_as_main_script.ipynb │ ├── p08_read_datafile_within_package.ipynb │ ├── p09_add_directories_to_sys_path.ipynb │ ├── p10_import_modules_using_name_given_in_string.ipynb │ ├── p11_load_modules_from_remote_machine_by_hooks.ipynb │ ├── p12_patching_modules_on_import.ipynb │ ├── p13_installing_packages_just_for_yourself.ipynb │ ├── p14_creating_new_python_environment.ipynb │ └── p15_distributing_packages.ipynb │ ├── 第四章:迭代器与生成器.ipynb │ └── 第四章:迭代器与生成器 │ ├── p01_manually_consuming_iterator.ipynb │ ├── p02_delegating_iteration.ipynb │ ├── p03_create_new_iteration_with_generators.ipynb │ ├── p04_implement_iterator_protocol.ipynb │ ├── p05_iterating_in_reverse.ipynb │ ├── p06_define_generator_func_with_extra_state.ipynb │ ├── p07_taking_slice_of_iterator.ipynb │ ├── p08_skip_first_part_of_iterable.ipynb │ ├── p09_iterate_over_combination_or_permutation.ipynb │ ├── p10_iterate_over_index_value_pairs_of_sequence.ipynb │ ├── p11_iterate_over_multiple_sequences_simultaneously.ipynb │ ├── p12_iterate_on_items_in_separate_containers.ipynb │ ├── p13_create_data_processing_pipelines.ipynb │ ├── p14_flattening_nested_sequence.ipynb │ ├── p15_iterate_in_sorted_order_over_merged_sorted_iterables.ipynb │ └── p16_replace_infinite_while_loops_with_iterator.ipynb ├── qcode.jpg ├── requirements_.txt └── source ├── aboutme.rst ├── c01 ├── p01_unpack_sequence_into_separate_variables.rst ├── p02_unpack_elements_from_iterables.rst ├── p03_keep_last_n_items.rst ├── p04_find_largest_or_smallest_n_items.rst ├── p05_implement_a_priority_queue.rst ├── p06_map_keys_to_multiple_values_in_dict.rst ├── p07_keep_dict_in_order.rst ├── p08_calculating_with_dict.rst ├── p09_find_commonalities_in_dicts.rst ├── p10_remove_duplicates_from_seq_order.rst ├── p11_naming_slice.rst ├── p12_determine_most_freqently_items_in_seq.rst ├── p13_sort_list_of_dicts_by_key.rst ├── p14_sort_objects_without_compare_support.rst ├── p15_group_records_based_on_field.rst ├── p16_filter_sequence_elements.rst ├── p17_extract_subset_of_dict.rst ├── p18_map_names_to_sequence_elements.rst ├── p19_transform_and_reduce_data_same_time.rst └── p20_combine_multiple_map_to_single_map.rst ├── c02 ├── p01_split_string_on_multiple_delimiters.rst ├── p02_match_text_at_start_end.rst ├── p03_match_strings_with_shell_wildcard.rst ├── p04_match_and_search_text.rst ├── p05_search_and_replace_text.rst ├── p06_search_replace_case_insensitive.rst ├── p07_specify_regexp_for_shortest_match.rst ├── p08_regexp_for_multiline_partterns.rst ├── p09_normalize_unicode_text_to_regexp.rst ├── p10_work_with_unicode_in_regexp.rst ├── p11_strip_unwanted_characters.rst ├── p12_sanitizing_clean_up_text.rst ├── p13_aligning_text_strings.rst ├── p14_combine_and_concatenate_strings.rst ├── p15_interpolating_variables_in_strings.rst ├── p16_reformat_text_to_fixed_number_columns.rst ├── p17_handle_html_xml_in_text.rst ├── p18_tokenizing_text.rst ├── p19_writing_recursive_descent_parser.rst └── p20_perform_text_operations_on_byte_string.rst ├── c03 ├── p01_round_number.rst ├── p02_accurate_decimal_calculations.rst ├── p03_format_numbers_for_output.rst ├── p04_binary_octal_hexadecimal_int.rst ├── p05_pack_unpack_large_int_from_bytes.rst ├── p06_complex_math.rst ├── p07_infinity_and_nan.rst ├── p08_calculating_with_fractions.rst ├── p09_calculating_with_large_num_arrays.rst ├── p10_matrix_and_linear_algebra_calculation.rst ├── p11_pick_things_at_random.rst ├── p12_convert_days_to_seconds_and_others.rst ├── p13_determine_last_friday_date.rst ├── p14_date_range_for_current_month.rst ├── p15_convert_strings_into_datetimes.rst └── p16_manipulate_dates_involving_timezone.rst ├── c04 ├── p01_manually_consuming_iterator.rst ├── p02_delegating_iteration.rst ├── p03_create_new_iteration_with_generators.rst ├── p04_implement_iterator_protocol.rst ├── p05_iterating_in_reverse.rst ├── p06_define_generator_func_with_extra_state.rst ├── p07_taking_slice_of_iterator.rst ├── p08_skip_first_part_of_iterable.rst ├── p09_iterate_over_combination_or_permutation.rst ├── p10_iterate_over_index_value_pairs_of_sequence.rst ├── p11_iterate_over_multiple_sequences_simultaneously.rst ├── p12_iterate_on_items_in_separate_containers.rst ├── p13_create_data_processing_pipelines.rst ├── p14_flattening_nested_sequence.rst ├── p15_iterate_in_sorted_order_over_merged_sorted_iterables.rst └── p16_replace_infinite_while_loops_with_iterator.rst ├── c05 ├── p01_read_write_text_data.rst ├── p02_printing_to_file.rst ├── p03_print_with_different_separator_or_line_ending.rst ├── p04_read_write_binary_data.rst ├── p05_write_to_file_not_exist.rst ├── p06_io_operations_on_string.rst ├── p07_read_write_compressed_datafiles.rst ├── p08_iterate_over_fixed_sized_records.rst ├── p09_read_binary_data_into_mutable_buffer.rst ├── p10_memory_mapping_binary_files.rst ├── p11_manipulating_pathnames.rst ├── p12_test_for_the_existence_of_file.rst ├── p13_get_directory_listing.rst ├── p14_bypassing_filename_encoding.rst ├── p15_printing_bad_filenames.rst ├── p16_add_change_encoding_of_already_open_file.rst ├── p17_write_bytes_to_text_file.rst ├── p18_wrap_existing_file_descriptor_as_file_object.rst ├── p19_make_temporary_files_and_directories.rst ├── p20_communicating_with_serial_ports.rst └── p21_serializing_python_objects.rst ├── c06 ├── p01_read_write_csv_data.rst ├── p02_read-write_json_data.rst ├── p03_parse_simple_xml_data.rst ├── p04_parse_huge_xml_files_incrementally.rst ├── p05_turning_dictionary_into_xml.rst ├── p06_parse_modify_rewrite_xml.rst ├── p07_parse_xml_documents_with_namespaces.rst ├── p08_interact_with_relational_database.rst ├── p09_decode_encode_hexadecimal_digits.rst ├── p10_decode_encode_base64.rst ├── p11_read_write_binary_arrays_of_structures.rst ├── p12_read_nested_and_variable_sized_binary_structures.rst └── p13_summarizing_and_perform_statistics.rst ├── c07 ├── p01_functions_that_accept_any_number_arguments.rst ├── p02_functions_that_only_accept_keyword_arguments.rst ├── p03_attach_informatinal_matadata_to_function_arguments.rst ├── p04_return_multiple_values_from_function.rst ├── p05_define_functions_with_default_arguments.rst ├── p06_define_anonymous_or_inline_functions.rst ├── p07_capturing_variables_in_anonymous_functions.rst ├── p08_make_callable_with_fewer_arguments.rst ├── p09_replace_single_method_classes_with_functions.rst ├── p10_carry_extra_state_with_callback_functions.rst ├── p11_inline_callback_functions.rst └── p12_access_variables_defined_inside_closure.rst ├── c08 ├── p01_change_string_representation_of_instances.rst ├── p02_customizing_string_formatting.rst ├── p03_make_objects_support_context_management_protocol.rst ├── p04_save_memory_when_create_large_number_instances.rst ├── p05_encapsulating_names_in_class.rst ├── p06_create_managed_attributes.rst ├── p07_calling_method_on_parent_class.rst ├── p08_extending_property_in_subclass.rst ├── p09_create_new_kind_of_class_or_instance_attribute.rst ├── p10_using_lazily_computed_properties.rst ├── p11_simplify_initialization_of_data_structure.rst ├── p12_define_interface_or_abstract_base_class.rst ├── p13_implementing_data_model_or_type_system.rst ├── p14_implementing_custom_containers.rst ├── p15_delegating_attribute_access.rst ├── p16_define_more_than_one_constructor_in_class.rst ├── p17_create_instance_without_invoking_init_method.rst ├── p18_extending_classes_with_mixins.rst ├── p19_implements_stateful_objects_or_state_machines.rst ├── p20_call_method_on_object_by_string_name.rst ├── p21_implementing_visitor_pattern.rst ├── p22_implementing_visitor_pattern_without_recursion.rst ├── p23_managing_memory_in_cyclic_data_structures.rst ├── p24_making_classes_support_comparison_operations.rst └── p25_creating_cached_instances.rst ├── c09 ├── p01_put_wrapper_around_function.rst ├── p02_preserve_function_metadata_when_write_decorators.rst ├── p03_unwrapping_decorator.rst ├── p04_define_decorator_that_takes_arguments.rst ├── p05_define_decorator_with_user_adjustable_attributes.rst ├── p06_define_decorator_that_takes_optional_argument.rst ├── p07_enforcing_type_check_on_function_using_decorator.rst ├── p08_define_decorators_as_part_of_class.rst ├── p09_define_decorators_as_classes.rst ├── p10_apply_decorators_to_class_and_static_methods.rst ├── p11_write_decorators_that_add_arguments_to_functions.rst ├── p12_using_decorators_to_patch_class_definitions.rst ├── p13_using_mataclass_to_control_instance_creation.rst ├── p14_capture_class_attribute_definition_order.rst ├── p15_define_metaclass_that_takes_optional_arguments.rst ├── p16_enforce_argument_signature_on_args_kwargs.rst ├── p17_enforce_coding_conventions_in_classes.rst ├── p18_define_classes_programmatically.rst ├── p19_initializing_class_members_at_definition_time.rst ├── p20_implement_multiple_dispatch_with_function_annotations.rst ├── p21_avoid_repetitive_property_methods.rst ├── p22_define_context_managers_the_easy_way.rst ├── p23_executing_code_with_local_side_effects.rst ├── p24_parse_and_analyzing_python_source.rst └── p25_disassembling_python_byte_code.rst ├── c10 ├── p01_make_hierarchical_package_of_modules.rst ├── p02_control_the_import_of_everything.rst ├── p03_import_submodules_by_relative_names.rst ├── p04_split_module_into_multiple_files.rst ├── p05_separate_directories_import_by_namespace.rst ├── p06_reloading_modules.rst ├── p07_make_directory_or_zip_runnable_as_main_script.rst ├── p08_read_datafile_within_package.rst ├── p09_add_directories_to_sys_path.rst ├── p10_import_modules_using_name_given_in_string.rst ├── p11_load_modules_from_remote_machine_by_hooks.rst ├── p12_patching_modules_on_import.rst ├── p13_installing_packages_just_for_yourself.rst ├── p14_creating_new_python_environment.rst └── p15_distributing_packages.rst ├── c11 ├── p01_interact_with_http_services_as_client.rst ├── p02_creating_tcp_server.rst ├── p03_creating_udp_server.rst ├── p04_generate_range_of_ip_addresses_from_cidr_address.rst ├── p05_creating_simple_rest_based_interface.rst ├── p06_implement_simple_remote_procedure_call_with_xml_rpc.rst ├── p07_communicate_simply_between_interpreters.rst ├── p08_implementing_remote_procedure_calls.rst ├── p09_authenticating_clients_simply.rst ├── p10_add_ssl_to_network_services.rst ├── p11_pass_socket_file_descriptor_between_processes.rst ├── p12_understanding_event_driven_io.rst └── p13_sending_receiving_large_arrays.rst ├── c12 ├── p01_start_stop_thread.rst ├── p02_determining_if_thread_has_started.rst ├── p03_communicating_between_threads.rst ├── p04_locking_critical_sections.rst ├── p05_locking_with_deadlock_avoidance.rst ├── p06_storing_thread_specific_state.rst ├── p07_creating_thread_pool.rst ├── p08_perform_simple_parallel_programming.rst ├── p09_dealing_with_gil_stop_worring_about_it.rst ├── p10_defining_an_actor_task.rst ├── p11_implement_publish_subscribe_messaging.rst ├── p12_using_generators_as_alternative_to_threads.rst ├── p13_polling_multiple_thread_queues.rst └── p14_launching_daemon_process_on_unix.rst ├── c13 ├── p01_accept_input_via_redirect_pips_or_input_files.rst ├── p02_terminate_program_with_an_error_message.rst ├── p03_parsing_command_line_options.rst ├── p04_prompt_for_password_at_runtime.rst ├── p05_getting_terminal_size.rst ├── p06_executing_external_command_and_get_its_output.rst ├── p07_copy_move_files_and_directories.rst ├── p08_creating_and_unpacking_archives.rst ├── p09_find_files_by_name.rst ├── p10_read_configuration_files.rst ├── p11_add_logging_to_simple_scripts.rst ├── p12_add_logging_to_libraries.rst ├── p13_making_stopwatch_timer.rst ├── p14_putting_limits_on_memory_and_cpu_usage.rst └── p15_luanch_a_web_browser.rst ├── c14 ├── p01_testing_output_sent_to_stdout.rst ├── p02_patching_objects_in_unit_tests.rst ├── p03_testing_for_exceptional_conditions_in_unit_tests.rst ├── p04_logging_test_output_to_file.rst ├── p05_skip_or_anticipate_test_failures.rst ├── p06_handle_multiple_exceptions.rst ├── p07_catching_all_exceptions.rst ├── p08_creating_custom_exceptions.rst ├── p09_raise_exception_in_response_to_another_exception.rst ├── p10_reraising_the_last_exception.rst ├── p11_issuing_warning_messages.rst ├── p12_debugging_basic_program_crashes.rst ├── p13_profiling_and_timing_your_program.rst └── p14_make_your_program_run_faster.rst ├── c15 ├── p01_access_ccode_using_ctypes.rst ├── p02_write_simple_c_extension_module.rst ├── p03_write_extension_function_operate_on_arrays.rst ├── p04_manage_opaque_pointers_in_c_extension_modules.rst ├── p05_define_and_export_c_api_from_extension_modules.rst ├── p06_calling_python_from_c.rst ├── p07_release_the_gil_in_c_extensions.rst ├── p08_mix_threads_from_c_and_python.rst ├── p09_wrap_c_code_with_swig.rst ├── p10_wrap_existing_c_code_with_cython.rst ├── p11_use_cython_to_write_high_performance_array_operation.rst ├── p12_turning_function_pointer_into_callable.rst ├── p13_pass_null_terminated_string_to_c_libraries.rst ├── p14_pass_unicode_strings_to_c_libraries.rst ├── p15_converting_c_string_to_python.rst ├── p16_work_with_c_strings_of_dubious_encoding.rst ├── p17_pass_filenames_to_c_extensions.rst ├── p18_pass_open_files_to_c_extensions.rst ├── p19_read_file_like_objects_from_c.rst ├── p20_consuming_an_iterable_from_c.rst └── p21_diagnosing_segmentation_faults.rst ├── chapters ├── p01_data_structures_algorithms.rst ├── p02_strings_and_text.rst ├── p03_numbers_dates_times.rst ├── p04_iterators_and_generators.rst ├── p05_files_and_io.rst ├── p06_data_encoding_and_process.rst ├── p07_functions.rst ├── p08_classes_and_objects.rst ├── p09_meta_programming.rst ├── p10_modules_and_packages.rst ├── p11_network_and_web_program.rst ├── p12_concurrency.rst ├── p13_utility_script_and_system_manage.rst ├── p14_test_debug_and_exceptions.rst ├── p15_c_extensions.rst └── p16_appendix.rst ├── conf.py ├── copyright.rst ├── index.rst ├── preface.rst └── roadmap.rst /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .idea/ 3 | *.pyc -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | cache: pip 3 | python: 4 | - 3.6 5 | install: 6 | - pip install flake8 7 | before_script: 8 | # stop the build if there are Python syntax errors or undefined names 9 | - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics 10 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 11 | - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 12 | script: 13 | - true 14 | notifications: 15 | on_success: change 16 | on_failure: change # `always` will be the setting once code changes slow down 17 | -------------------------------------------------------------------------------- /cookbook/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c01/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c01/p03_nitem.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: collections.deque演示 5 | Desc : deque有一个maxlen参数,当append的时候,如果超过,那么最前面的就被挤出队列。 6 | """ 7 | from collections import deque 8 | 9 | 10 | def search(lines, pattern, history=5): 11 | previous_lines = deque(maxlen=history) 12 | for li in lines: 13 | if pattern in li: 14 | yield li, previous_lines 15 | previous_lines.append(li) 16 | 17 | # Example use on a file 18 | if __name__ == '__main__': 19 | with open(r'../../cookbook/somefile.txt') as f: 20 | for line, prevlines in search(f, 'Python', 5): 21 | for pline in prevlines: 22 | print(pline, end='') 23 | print(line, end='') 24 | print('-' * 20) 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /cookbook/c01/p04_nlargest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 返回集合中最大或最小的N个元素 5 | Desc : 6 | """ 7 | import heapq 8 | 9 | 10 | def main(): 11 | portfolio = [ 12 | {'name': 'IBM', 'shares': 100, 'price': 91.1}, 13 | {'name': 'AAPL', 'shares': 50, 'price': 543.22}, 14 | {'name': 'FB', 'shares': 200, 'price': 21.09}, 15 | {'name': 'HPQ', 'shares': 35, 'price': 31.75}, 16 | {'name': 'YHOO', 'shares': 45, 'price': 16.35}, 17 | {'name': 'ACME', 'shares': 75, 'price': 115.65} 18 | ] 19 | cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price']) 20 | expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price']) 21 | print(cheap) 22 | print(expensive) 23 | 24 | nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] 25 | heapq.heapify(nums) 26 | print(nums) 27 | print(heapq.heappop(nums)) 28 | print(heapq.heappop(nums)) 29 | print(heapq.heappop(nums)) 30 | 31 | 32 | if __name__ == '__main__': 33 | main() 34 | 35 | -------------------------------------------------------------------------------- /cookbook/c01/p05_priority_queue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 优先级队列 5 | Desc : 6 | """ 7 | import heapq 8 | 9 | 10 | class PriorityQueue: 11 | def __init__(self): 12 | self._queue = [] 13 | self._index = 0 14 | 15 | def push(self, item, priority): 16 | heapq.heappush(self._queue, (-priority, self._index, item)) 17 | self._index += 1 18 | 19 | def pop(self): 20 | return heapq.heappop(self._queue)[-1] 21 | 22 | -------------------------------------------------------------------------------- /cookbook/c01/p06_multidict.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 多值映射 5 | Desc : 6 | """ 7 | 8 | from collections import defaultdict 9 | 10 | 11 | def multi_dict(): 12 | d = defaultdict(list) 13 | d['a'].append(1) 14 | d['a'].append(2) 15 | d['b'].append(4) 16 | 17 | d = defaultdict(set) 18 | d['a'].add(1) 19 | d['a'].add(2) 20 | d['b'].add(4) 21 | 22 | d = {} # A regular dictionary 23 | d.setdefault('a', []).append(1) 24 | d.setdefault('a', []).append(2) 25 | d.setdefault('b', []).append(4) 26 | 27 | 28 | -------------------------------------------------------------------------------- /cookbook/c01/p07_ordered_dict.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 排序字典 5 | Desc : 6 | """ 7 | 8 | from collections import OrderedDict 9 | 10 | 11 | d = OrderedDict() 12 | d['foo'] = 1 13 | d['bar'] = 2 14 | d['spam'] = 3 15 | d['grok'] = 4 16 | # Outputs "foo 1", "bar 2", "spam 3", "grok 4" 17 | for key in d: 18 | print(key, d[key]) 19 | 20 | -------------------------------------------------------------------------------- /cookbook/c01/p08_calculate_dict.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字典的数据运算 5 | Desc : 6 | """ 7 | 8 | 9 | def calc_dict(): 10 | prices = { 11 | 'ACME': 45.23, 12 | 'AAPL': 612.78, 13 | 'IBM': 205.55, 14 | 'HPQ': 37.20, 15 | 'FB': 10.75 16 | } 17 | 18 | min_price = min(zip(prices.values(), prices.keys())) 19 | # min_price is (10.75, 'FB') 20 | max_price = max(zip(prices.values(), prices.keys())) 21 | # max_price is (612.78, 'AAPL') 22 | 23 | prices_sorted = sorted(zip(prices.values(), prices.keys())) 24 | # prices_sorted is [(10.75, 'FB'), (37.2, 'HPQ'), 25 | # (45.23, 'ACME'), (205.55, 'IBM'), 26 | # (612.78, 'AAPL')] 27 | 28 | prices_and_names = zip(prices.values(), prices.keys()) 29 | print(min(prices_and_names)) # OK 30 | print(max(prices_and_names)) # ValueError: max() arg is an empty sequence 31 | 32 | min(prices) # Returns 'AAPL' 33 | max(prices) # Returns 'IBM' 34 | 35 | min(prices, key=lambda k: prices[k]) # Returns 'FB' 36 | max(prices, key=lambda k: prices[k]) # Returns 'AAPL' 37 | 38 | min_value = prices[min(prices, key=lambda k: prices[k])] 39 | 40 | prices = { 'AAA' : 45.23, 'ZZZ': 45.23 } 41 | min(zip(prices.values(), prices.keys())) 42 | # (45.23, 'AAA') 43 | max(zip(prices.values(), prices.keys())) 44 | # (45.23, 'ZZZ') 45 | -------------------------------------------------------------------------------- /cookbook/c01/p09_dict_common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字典的集合操作 5 | Desc : 6 | """ 7 | 8 | 9 | def dict_commonality(): 10 | a = { 11 | 'x': 1, 12 | 'y': 2, 13 | 'z': 3 14 | } 15 | 16 | b = { 17 | 'w': 10, 18 | 'x': 11, 19 | 'y': 2 20 | } 21 | 22 | # Find keys in common 23 | print(a.keys() & b.keys()) # { 'x', 'y' } 24 | # Find keys in a that are not in b 25 | print(a.keys() - b.keys()) # { 'z' } 26 | # Find (key,value) pairs in common 27 | print(a.items() & b.items()) # { ('y', 2) } 28 | 29 | print(type(a.items())) 30 | 31 | for a, b in a.items(): 32 | print(a, b) 33 | 34 | 35 | if __name__ == '__main__': 36 | dict_commonality() -------------------------------------------------------------------------------- /cookbook/c01/p10_remove_duplicate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 消除序列重复值并保持顺序 5 | Desc : 6 | """ 7 | 8 | 9 | def dedupe(items): 10 | """元素都是hashable""" 11 | seen = set() 12 | for item in items: 13 | if item not in seen: 14 | yield item 15 | seen.add(item) 16 | 17 | 18 | def dedupe2(items, key=None): 19 | """元素不是hashable的时候""" 20 | seen = set() 21 | for item in items: 22 | val = item if key is None else key(item) 23 | if val not in seen: 24 | yield item 25 | seen.add(val) 26 | 27 | 28 | def remove_dup(): 29 | a = [1, 5, 2, 1, 9, 1, 5, 10] 30 | print(list(dedupe(a))) 31 | 32 | a = [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}] 33 | print(list(dedupe2(a, key=lambda d: (d['x'], d['y'])))) 34 | print(list(dedupe2(a, key=lambda d: d['x']))) 35 | 36 | 37 | if __name__ == '__main__': 38 | remove_dup() 39 | -------------------------------------------------------------------------------- /cookbook/c01/p11_naming_slice.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 命名切片 5 | Desc : 6 | """ 7 | 8 | 9 | def name_slice(): 10 | record = '....................100 .......513.25 ..........' 11 | cost = int(record[20:23]) * float(record[31:37]) 12 | 13 | SHARES = slice(20, 23) 14 | PRICE = slice(31, 37) 15 | cost = int(record[SHARES]) * float(record[PRICE]) 16 | print(cost) 17 | print(SHARES.start) 18 | print(SHARES.stop) 19 | print(SHARES.step) 20 | 21 | a = slice(5, 50, 2) 22 | s = 'HelloWorld' 23 | print(a.indices(len(s))) 24 | for i in range(*a.indices(len(s))): 25 | print(s[i]) 26 | 27 | 28 | if __name__ == '__main__': 29 | name_slice() -------------------------------------------------------------------------------- /cookbook/c01/p12_mostfreq_items.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 查找出现次数最多的元素 5 | Desc : 6 | """ 7 | 8 | 9 | def most_freqency(): 10 | words = [ 11 | 'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes', 12 | 'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the', 13 | 'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into', 14 | 'my', 'eyes', "you're", 'under' 15 | ] 16 | from collections import Counter 17 | word_counts = Counter(words) 18 | # 出现频率最高的3个单词 19 | top_three = word_counts.most_common(3) 20 | print(top_three) 21 | # Outputs [('eyes', 8), ('the', 5), ('look', 4)] 22 | 23 | if __name__ == '__main__': 24 | most_freqency() 25 | 26 | -------------------------------------------------------------------------------- /cookbook/c01/p13_sort_dictlist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 排序dict列表 5 | Desc : 6 | """ 7 | 8 | 9 | def sort_dictlist(): 10 | rows = [ 11 | {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, 12 | {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, 13 | {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, 14 | {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} 15 | ] 16 | 17 | from operator import itemgetter 18 | rows_by_fname = sorted(rows, key=itemgetter('fname')) 19 | rows_by_uid = sorted(rows, key=itemgetter('uid')) 20 | print(rows_by_fname) 21 | print(rows_by_uid) 22 | 23 | rows_by_lfname = sorted(rows, key=itemgetter('lname','fname')) 24 | print(rows_by_lfname) 25 | 26 | if __name__ == '__main__': 27 | sort_dictlist() 28 | 29 | -------------------------------------------------------------------------------- /cookbook/c01/p14_sort_nocompare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 排序不支持原生比较操作的对象 5 | Desc : 6 | """ 7 | 8 | 9 | class User: 10 | def __init__(self, user_id): 11 | self.user_id = user_id 12 | 13 | def __repr__(self): 14 | return 'User({})'.format(self.user_id) 15 | 16 | 17 | def sort_notcompare(): 18 | users = [User(23), User(3), User(99)] 19 | print(users) 20 | print(sorted(users, key=lambda u: u.user_id)) 21 | 22 | from operator import attrgetter 23 | print(sorted(users, key=attrgetter('user_id'))) 24 | 25 | # print(sorted(users, key=attrgetter('last_name', 'first_name'))) 26 | 27 | print(min(users, key=attrgetter('user_id'))) 28 | print(max(users, key=attrgetter('user_id'))) 29 | if __name__ == '__main__': 30 | sort_notcompare() -------------------------------------------------------------------------------- /cookbook/c01/p15_group.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 分组迭代 5 | Desc : 6 | """ 7 | from operator import itemgetter 8 | from itertools import groupby 9 | 10 | 11 | def group_iter(): 12 | rows = [ 13 | {'address': '5412 N CLARK', 'date': '07/01/2012'}, 14 | {'address': '5148 N CLARK', 'date': '07/04/2012'}, 15 | {'address': '5800 E 58TH', 'date': '07/02/2012'}, 16 | {'address': '2122 N CLARK', 'date': '07/03/2012'}, 17 | {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}, 18 | {'address': '1060 W ADDISON', 'date': '07/02/2012'}, 19 | {'address': '4801 N BROADWAY', 'date': '07/01/2012'}, 20 | {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}, 21 | ] 22 | 23 | # Sort by the desired field first 24 | rows.sort(key=itemgetter('date')) 25 | # Iterate in groups 26 | for date, items in groupby(rows, key=itemgetter('date')): 27 | print(date) 28 | for i in items: 29 | print(' ', i) 30 | 31 | # defaultdict使用 32 | from collections import defaultdict 33 | rows_by_date = defaultdict(list) 34 | for row in rows: 35 | rows_by_date[row['date']].append(row) 36 | 37 | if __name__ == '__main__': 38 | group_iter() -------------------------------------------------------------------------------- /cookbook/c01/p16_filter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 序列元素过滤 5 | Desc : 6 | """ 7 | from itertools import compress 8 | 9 | 10 | def cb_filter(): 11 | mylist = [1, 4, -5, 10, -7, 2, 3, -1] 12 | print([n for n in mylist if n > 0]) 13 | print([n for n in mylist if n < 0]) 14 | 15 | pos = (n for n in mylist if n > 0) 16 | print(pos) 17 | for x in pos: 18 | print(x, end=',') 19 | print() 20 | 21 | values = ['1', '2', '-3', '-', '4', 'N/A', '5'] 22 | def is_int(val): 23 | try: 24 | x = int(val) 25 | return True 26 | except ValueError: 27 | return False 28 | ivals = list(filter(is_int, values)) 29 | print(ivals) 30 | # Outputs ['1', '2', '-3', '4', '5'] 31 | 32 | # 条件过滤 33 | clip_neg = [n if n > 0 else 0 for n in mylist] 34 | print(clip_neg) 35 | 36 | addresses = [ 37 | '5412 N CLARK', 38 | '5148 N CLARK', 39 | '5800 E 58TH', 40 | '2122 N CLARK', 41 | '5645 N RAVENSWOOD', 42 | '1060 W ADDISON', 43 | '4801 N BROADWAY', 44 | '1039 W GRANVILLE', 45 | ] 46 | counts = [ 0, 3, 10, 4, 1, 7, 6, 1] 47 | more5 = [n > 5 for n in counts] 48 | print(list(compress(addresses, more5))) 49 | 50 | 51 | if __name__ == '__main__': 52 | cb_filter() 53 | -------------------------------------------------------------------------------- /cookbook/c01/p17_subdict.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: dict子集 5 | Desc : 6 | """ 7 | 8 | 9 | def sub_dict(): 10 | prices = { 11 | 'ACME': 45.23, 12 | 'AAPL': 612.78, 13 | 'IBM': 205.55, 14 | 'HPQ': 37.20, 15 | 'FB': 10.75 16 | } 17 | # Make a dictionary of all prices over 200 18 | p1 = {key: value for key, value in prices.items() if value > 200} 19 | # Make a dictionary of tech stocks 20 | tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'} 21 | p2 = {key: value for key, value in prices.items() if key in tech_names} 22 | 23 | if __name__ == '__main__': 24 | sub_dict() 25 | -------------------------------------------------------------------------------- /cookbook/c01/p19_trans_reduce.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 转换并聚集函数 5 | Desc : 6 | """ 7 | import os 8 | 9 | 10 | def trans_reduce(): 11 | nums = [1, 2, 3, 4, 5] 12 | s = sum(x * x for x in nums) 13 | print(s) 14 | 15 | files = os.listdir('dirname') 16 | if any(name.endswith('.py') for name in files): 17 | print('There be python!') 18 | else: 19 | print('Sorry, no python.') 20 | # Output a tuple as CSV 21 | s = ('ACME', 50, 123.45) 22 | print(','.join(str(x) for x in s)) 23 | # Data reduction across fields of a data structure 24 | portfolio = [ 25 | {'name':'GOOG', 'shares': 50}, 26 | {'name':'YHOO', 'shares': 75}, 27 | {'name':'AOL', 'shares': 20}, 28 | {'name':'SCOX', 'shares': 65} 29 | ] 30 | min_shares = min(s['shares'] for s in portfolio) 31 | 32 | # Original: Returns 20 33 | min_shares = min(s['shares'] for s in portfolio) 34 | # Alternative: Returns {'name': 'AOL', 'shares': 20} 35 | min_shares = min(portfolio, key=lambda s: s['shares']) 36 | 37 | if __name__ == '__main__': 38 | trans_reduce() 39 | 40 | -------------------------------------------------------------------------------- /cookbook/c01/p20_combine_map.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 合并多个字典或映射 5 | Desc : 6 | """ 7 | 8 | from collections import ChainMap 9 | 10 | 11 | def combine_map(): 12 | a = {'x': 1, 'z': 3 } 13 | b = {'y': 2, 'z': 4 } 14 | c = ChainMap(a,b) 15 | print(c['x']) # Outputs 1 (from a) 16 | print(c['y']) # Outputs 2 (from b) 17 | print(c['z']) # Outputs 3 (from a) 18 | 19 | print(len(c)) 20 | print(list(c.keys())) 21 | print(list(c.values())) 22 | 23 | c['z'] = 10 24 | c['w'] = 40 25 | del c['x'] 26 | print(a) 27 | # del c['y'] 28 | 29 | values = ChainMap() 30 | values['x'] = 1 31 | # Add a new mapping 32 | values = values.new_child() 33 | values['x'] = 2 34 | # Add a new mapping 35 | values = values.new_child() 36 | values['x'] = 3 37 | print(values) 38 | print(values['x']) 39 | # Discard last mapping 40 | values = values.parents 41 | print(values['x']) 42 | # Discard last mapping 43 | values = values.parents 44 | print(values['x']) 45 | print(values) 46 | 47 | 48 | if __name__ == '__main__': 49 | combine_map() -------------------------------------------------------------------------------- /cookbook/c02/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c02/p01_splitstr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 正则式分割字符串 5 | Desc : 6 | """ 7 | import re 8 | 9 | 10 | def split_str(): 11 | line = 'asdf fjdk; afed, fjek,asdf, foo' 12 | print(re.split(r'[;,\s]\s*', line)) 13 | print(re.split(r'(;|,|\s)\s*', line)) 14 | fields = re.split(r'(;|,|\s)\s*', line) 15 | values = fields[::2] 16 | delimiters = fields[1::2] + [''] 17 | print(''.join(v+d for v,d in zip(values, delimiters))) 18 | 19 | if __name__ == '__main__': 20 | split_str() 21 | 22 | -------------------------------------------------------------------------------- /cookbook/c02/p02_str_start.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 检查字符串开始或结尾 5 | Desc : 6 | """ 7 | import re 8 | import os 9 | from urllib.request import urlopen 10 | 11 | 12 | def start_end(): 13 | filename = 'spam.txt' 14 | print(filename.endswith('.txt')) 15 | print(filename.startswith('file:')) 16 | url = 'http://www.python.org' 17 | print(url.startswith('http:')) 18 | 19 | filenames = os.listdir('.') 20 | print(filenames) 21 | print([name for name in filenames if name.endswith(('.py', '.c'))]) 22 | print(any(name.endswith('.py') for name in filenames)) 23 | 24 | choices = ['http:', 'ftp:'] 25 | url = 'http://www.python.org' 26 | url.startswith(tuple(choices)) 27 | 28 | # 切片实现,看上去不美 29 | filename = 'spam.txt' 30 | print(filename[-4:] == '.txt') 31 | url = 'http://www.python.org' 32 | print(url[:5] == 'http:' or url[:6] == 'https:' or url[:4] == 'ftp:') 33 | 34 | # 正则式实现 35 | url = 'http://www.python.org' 36 | print(re.match('http:|https:|ftp:', url)) 37 | 38 | 39 | def read_data(name): 40 | if name.startswith(('http:', 'https:', 'ftp:')): 41 | return urlopen(name).read() 42 | else: 43 | with open(name) as f: 44 | return f.read() 45 | 46 | if __name__ == '__main__': 47 | start_end() 48 | 49 | -------------------------------------------------------------------------------- /cookbook/c02/p03_unix_match.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: Unix Shell通配符匹配 5 | Desc : 6 | """ 7 | from fnmatch import fnmatch, fnmatchcase 8 | 9 | 10 | def unix_match(): 11 | print(fnmatch('foo.txt', '*.txt')) 12 | print(fnmatch('foo.txt', '?oo.txt')) 13 | print(fnmatch('Dat45.csv', 'Dat[0-9]*')) 14 | names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py'] 15 | print([name for name in names if fnmatch(name, 'Dat*.csv')]) 16 | 17 | # 完全按照模式大小写来 18 | print(fnmatchcase('foo.txt', '*.TXT')) 19 | 20 | # 处理普通文本 21 | addresses = [ 22 | '5412 N CLARK ST', 23 | '1060 W ADDISON ST', 24 | '1039 W GRANVILLE AVE', 25 | '2122 N CLARK ST', 26 | '4802 N BROADWAY', 27 | ] 28 | print([addr for addr in addresses if fnmatchcase(addr, '* ST')]) 29 | print([addr for addr in addresses if fnmatchcase(addr, '54[0-9][0-9] *CLARK*')]) 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | unix_match() -------------------------------------------------------------------------------- /cookbook/c02/p05_search_replace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字符串搜索和替换 5 | Desc : 6 | """ 7 | import re 8 | from calendar import month_abbr 9 | 10 | 11 | def change_date(m): 12 | mon_name = month_abbr[int(m.group(1))] 13 | return '{} {} {}'.format(m.group(2), mon_name, m.group(3)) 14 | 15 | 16 | def search_replace(): 17 | text = 'yeah, but no, but yeah, but no, but yeah' 18 | print(text.replace('yeah', 'yep')) 19 | 20 | # 复杂的模式,使用sub() 21 | text = 'Today is 11/27/2012. PyCon starts 3/13/2013.' 22 | print(re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text)) 23 | print(re.sub(r'(?P\d+)/(?P\d+)/(?P\d+)', r'\g-\g-\g', text)) 24 | 25 | # 先编译 26 | datepat = re.compile(r'(\d+)/(\d+)/(\d+)') 27 | print(datepat.sub(r'\3-\1-\2', text)) 28 | 29 | # 更复杂的替换,使用回调函数 30 | print(datepat.sub(change_date, text)) 31 | 32 | # 同时返回替换次数 33 | newtext, n = datepat.subn(r'\3-\1-\2', text) 34 | print(newtext, n) 35 | 36 | 37 | if __name__ == '__main__': 38 | search_replace() 39 | 40 | -------------------------------------------------------------------------------- /cookbook/c02/p06_case_insensitive.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 忽略大小写 5 | Desc : 6 | """ 7 | import re 8 | 9 | 10 | def matchcase(word): 11 | def replace(m): 12 | text = m.group() 13 | if text.isupper(): 14 | return word.upper() 15 | elif text.islower(): 16 | return word.lower() 17 | elif text[0].isupper(): 18 | return word.capitalize() 19 | else: 20 | return word 21 | return replace 22 | 23 | def case_insens(): 24 | text = 'UPPER PYTHON, lower python, Mixed Python' 25 | print(re.findall('python', text, flags=re.IGNORECASE)) 26 | print(re.sub('python', 'snake', text, flags=re.IGNORECASE)) 27 | 28 | # 大小写自动匹配 29 | print(re.sub('python', matchcase('snake'), text, flags=re.IGNORECASE)) 30 | 31 | if __name__ == '__main__': 32 | case_insens() 33 | -------------------------------------------------------------------------------- /cookbook/c02/p07_shortest_match.py: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env python 3 | # -*- encoding: utf-8 -*- 4 | """ 5 | Topic: 最短匹配,非贪婪模式匹配 6 | Desc : 7 | """ 8 | import re 9 | 10 | 11 | def short_match(): 12 | # 贪婪模式 13 | str_pat = re.compile(r'\"(.*)\"') 14 | text1 = 'Computer says "no."' 15 | print(str_pat.findall(text1)) 16 | text2 = 'Computer says "no." Phone says "yes."' 17 | print(str_pat.findall(text2)) 18 | 19 | # 非贪婪模式 20 | str_pat = re.compile(r'\"(.*?)\"') 21 | print(str_pat.findall(text2)) 22 | 23 | if __name__ == '__main__': 24 | short_match() 25 | 26 | -------------------------------------------------------------------------------- /cookbook/c02/p08_multiline_match.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 多行匹配 5 | Desc : 6 | """ 7 | import re 8 | 9 | 10 | def multiline_match(): 11 | comment = re.compile(r'/\*(.*?)\*/') 12 | text1 = '/* this is a comment */' 13 | text2 = '''/* this is a 14 | multiline comment */ 15 | ''' 16 | print(comment.findall(text1)) 17 | print(comment.findall(text2)) 18 | 19 | # 修正模式 20 | comment = re.compile(r'/\*((?:.|\n)*?)\*/') 21 | print(comment.findall(text2)) 22 | 23 | # 使用标志参数re.DOTALL,复杂匹配时不推荐 24 | comment = re.compile(r'/\*(.*?)\*/', re.DOTALL) 25 | print(comment.findall(text2)) 26 | 27 | 28 | if __name__ == '__main__': 29 | multiline_match() 30 | -------------------------------------------------------------------------------- /cookbook/c02/p09_normal_unicode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: unicode字符串标准化表示 5 | Desc : 6 | """ 7 | import unicodedata 8 | 9 | 10 | def nor_unicode(): 11 | s1 = 'Spicy Jalape\u00f1o' 12 | s2 = 'Spicy Jalapen\u0303o' 13 | print(s1, s2) 14 | print(s1 == s2) 15 | print(len(s1), len(s2)) 16 | 17 | # 先将文本标准化表示 18 | t1 = unicodedata.normalize('NFC', s1) 19 | t2 = unicodedata.normalize('NFC', s2) 20 | print(t1 == t2) 21 | print(ascii(t1)) 22 | 23 | t3 = unicodedata.normalize('NFD', s1) 24 | t4 = unicodedata.normalize('NFD', s2) 25 | print(t3 == t4) 26 | print(ascii(t3)) 27 | 28 | # 扩展的NFKC和NFKD 29 | s = '\ufb01' # A single character 30 | print(s, len(s)) 31 | print(unicodedata.normalize('NFD', s), len(unicodedata.normalize('NFD', s))) 32 | print(unicodedata.normalize('NFKC', s), len(unicodedata.normalize('NFKC', s))) 33 | print(unicodedata.normalize('NFKD', s), len(unicodedata.normalize('NFKD', s))) 34 | 35 | # 消除变音符 36 | t1 = unicodedata.normalize('NFD', s1) 37 | print(''.join(c for c in t1 if not unicodedata.combining(c))) 38 | 39 | 40 | if __name__ == '__main__': 41 | nor_unicode() 42 | 43 | -------------------------------------------------------------------------------- /cookbook/c02/p10_re_unicode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 在正则式中使用Unicode 5 | Desc : 6 | """ 7 | import re 8 | 9 | 10 | def re_unicode(): 11 | num = re.compile('\d+') 12 | 13 | # ASCII digits 14 | print(num.match('123')) 15 | 16 | # 阿拉伯数字 17 | print(num.match('\u0661\u0662\u0663')) 18 | 19 | # 匹配所有阿拉伯编码字符 20 | arabic = re.compile('[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff]+') 21 | 22 | # 大小写忽略情形 23 | pat = re.compile('stra\u00dfe', re.IGNORECASE) 24 | s = 'straße' 25 | print(pat.match(s)) 26 | print(pat.match(s.upper())) # Doesn't match 27 | print(s.upper()) # 大小写转换 28 | 29 | 30 | if __name__ == '__main__': 31 | re_unicode() 32 | 33 | -------------------------------------------------------------------------------- /cookbook/c02/p11_strip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 去除字符串中多余字符 5 | Desc : 6 | """ 7 | import re 8 | 9 | 10 | def strip_str(): 11 | s = ' hello world \n' 12 | print(s.strip()) 13 | print(s.lstrip()) 14 | print(s.rstrip()) 15 | 16 | # Character stripping 17 | t = '-----hello=====' 18 | print(t.lstrip('-')) 19 | print(t.strip('-=')) 20 | 21 | # 对中间不会影响 22 | s = ' hello world \n' 23 | print(s.strip()) 24 | 25 | print(s.replace(' ', '')) 26 | print(re.sub('\s+', ' ', s)) 27 | 28 | # 生成器表达式 29 | with open('filename') as f: 30 | lines = (line.strip() for line in f) 31 | for line in lines: 32 | pass 33 | 34 | 35 | if __name__ == '__main__': 36 | strip_str() 37 | 38 | -------------------------------------------------------------------------------- /cookbook/c02/p12_translate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: str的translate方法清理文本 5 | Desc : 6 | """ 7 | import unicodedata 8 | import sys 9 | 10 | 11 | def clean_spaces(s): 12 | """普通替换使用replace最快""" 13 | s = s.replace('\r', '') 14 | s = s.replace('\t', ' ') 15 | s = s.replace('\f', ' ') 16 | return s 17 | 18 | 19 | def translate_str(): 20 | s = 'pýtĥöñ\fis\tawesome\r\n' 21 | print(s) 22 | 23 | remap = { 24 | ord('\t'): ' ', 25 | ord('\f'): ' ', 26 | ord('\r'): None # Deleted 27 | } 28 | 29 | a = s.translate(remap) 30 | print(a) 31 | 32 | # 删除和音符 33 | cmb_chrs = dict.fromkeys(c for c in range(sys.maxunicode) 34 | if unicodedata.combining(chr(c))) 35 | b = unicodedata.normalize('NFD', a) 36 | print(b) 37 | print(b.translate(cmb_chrs)) 38 | 39 | # unicode数字字符映射到ascii字符 40 | digitmap = {c: ord('0') + unicodedata.digit(chr(c)) 41 | for c in range(sys.maxunicode) 42 | if unicodedata.category(chr(c)) == 'Nd'} 43 | print(len(digitmap)) 44 | x = '\u0661\u0662\u0663' 45 | print(x.translate(digitmap)) 46 | 47 | # 先标准化,然后使用encode和decode函数 48 | b = unicodedata.normalize('NFD', a) 49 | print(type(b)) 50 | print(b.encode('ascii', 'ignore').decode('ascii')) 51 | 52 | 53 | if __name__ == '__main__': 54 | translate_str() 55 | 56 | -------------------------------------------------------------------------------- /cookbook/c02/p13_align_str.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 对齐字符串 5 | Desc : 6 | """ 7 | 8 | 9 | def align_str(): 10 | text = 'Hello World' 11 | print(text.ljust(20)) 12 | print(text.rjust(20)) 13 | print(text.center(20)) 14 | 15 | # 填充字符 16 | print(text.rjust(20,'=')) 17 | print(text.center(20,'*')) 18 | 19 | # format函数 20 | print(format(text, '>20')) 21 | print(format(text, '<20')) 22 | print(format(text, '^20')) 23 | # 同时增加填充字符 24 | print(format(text, '=>20s')) 25 | print(format(text, '*^20s')) 26 | 27 | # 格式化多个值 28 | print('{:=>10s} {:*^10s}'.format('Hello', 'World')) 29 | 30 | # 格式化数字 31 | x = 1.2345 32 | print(format(x, '=^10.2f')) 33 | 34 | 35 | if __name__ == '__main__': 36 | align_str() 37 | 38 | -------------------------------------------------------------------------------- /cookbook/c02/p14_join_str.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字符串合并 5 | Desc : 6 | """ 7 | 8 | 9 | def combine(source, maxsize): 10 | parts = [] 11 | size = 0 12 | for part in source: 13 | parts.append(part) 14 | size += len(part) 15 | if size > maxsize: 16 | yield ''.join(parts) 17 | parts = [] 18 | size = 0 19 | yield ''.join(parts) 20 | 21 | 22 | def sample(): 23 | yield 'Is' 24 | yield 'Chicago' 25 | yield 'Not' 26 | yield 'Chicago?' 27 | 28 | 29 | def join_str(): 30 | parts = ['Is', 'Chicago', 'Not', 'Chicago?'] 31 | print(' '.join(parts)) 32 | print(','.join(parts)) 33 | print(''.join(parts)) 34 | 35 | # 使用+ 36 | a = 'Is Chicago' 37 | b = 'Not Chicago?' 38 | c = 'ccc' 39 | print(a + ' ' + b) 40 | 41 | data = ['ACME', 50, 91.1] 42 | print(','.join(str(d) for d in data)) 43 | 44 | 45 | print(a + ':' + b + ':' + c) # Ugly 46 | print(':'.join([a, b, c])) # Still ugly 47 | print(a, b, c, sep=':') # Better 48 | 49 | # 混合方案 50 | # with open('filename', 'w') as f: 51 | # for part in combine(sample(), 32768): 52 | # f.write(part) 53 | for part in combine(sample(), 32768): 54 | print(part) 55 | 56 | if __name__ == '__main__': 57 | join_str() 58 | 59 | -------------------------------------------------------------------------------- /cookbook/c02/p15_var_string.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字符串中的变量 5 | Desc : 6 | """ 7 | import sys 8 | 9 | class Info: 10 | def __init__(self, name, n): 11 | self.name = name 12 | self.n = n 13 | 14 | 15 | class SafeSub(dict): 16 | """防止key找不到""" 17 | def __missing__(self, key): 18 | return '{' + key + '}' 19 | 20 | 21 | def sub(text): 22 | return text.format_map(SafeSub(sys._getframe(1).f_locals)) 23 | 24 | def var_str(): 25 | s = '{name} has {n} messages.' 26 | print(s.format(name='Guido', n=37)) 27 | 28 | # vars()和format_map 29 | a = Info('Guido', 37) 30 | print(s.format_map(vars(a))) 31 | 32 | name = 'Lisi' 33 | print(s.format_map(SafeSub(vars()))) 34 | 35 | name = 'Guido' 36 | n = 37 37 | print(sub('Hello {name}')) 38 | print(sub('You have {n} messages.')) 39 | print(sub('Your favorite color is {color}')) 40 | 41 | 42 | if __name__ == '__main__': 43 | var_str() 44 | 45 | -------------------------------------------------------------------------------- /cookbook/c02/p16_textwrap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 格式化字符串为指定宽度 5 | Desc : 6 | """ 7 | import textwrap 8 | import os 9 | 10 | 11 | def reformat_width(): 12 | s = "Look into my eyes, look into my eyes, the eyes, the eyes, \ 13 | the eyes, not around the eyes, don't look around the eyes, \ 14 | look into my eyes, you're under." 15 | 16 | print(textwrap.fill(s, 70)) 17 | print('*' * 40) 18 | print(textwrap.fill(s, 40)) 19 | print('*' * 40) 20 | print(textwrap.fill(s, 40, initial_indent=' ')) 21 | print('*' * 40) 22 | print(textwrap.fill(s, 40, subsequent_indent=' ')) 23 | 24 | # 获取终端屏幕尺寸 25 | print(os.get_terminal_size().columns) 26 | 27 | 28 | if __name__ == '__main__': 29 | reformat_width() -------------------------------------------------------------------------------- /cookbook/c02/p17_html_xml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 处理html和xml文本 5 | Desc : 6 | """ 7 | import html 8 | 9 | 10 | def html_xml(): 11 | s = 'Elements are written as "text".' 12 | print(s) 13 | print(html.escape(s)) 14 | 15 | # Disable escaping of quotes 16 | print(html.escape(s, quote=False)) 17 | 18 | s = 'Spicy Jalapeño' 19 | print(s.encode('ascii', errors='xmlcharrefreplace')) 20 | 21 | if __name__ == '__main__': 22 | html_xml() 23 | 24 | -------------------------------------------------------------------------------- /cookbook/c02/p20_byte_str.py: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env python 3 | # -*- encoding: utf-8 -*- 4 | """ 5 | Topic: 字节字符串操作 6 | Desc : 7 | """ 8 | import re 9 | 10 | 11 | def byte_str(): 12 | data = b'Hello World' 13 | print(data[0:5]) 14 | print(data.startswith(b'Hello')) 15 | print(data.split()) 16 | print(data.replace(b'Hello', b'Hello Cruel')) 17 | 18 | # 字节数组 19 | data = bytearray(b'Hello World') 20 | print(data[0:5]) 21 | print(data.startswith(b'Hello')) 22 | print(data.split()) 23 | print(data.replace(b'Hello', b'Hello Cruel')) 24 | 25 | # 正则式 26 | data = b'FOO:BAR,SPAM' 27 | print(re.split(b'[:,]',data)) 28 | 29 | # 字节字符串打印不美观 30 | s = b'Hello World' 31 | print(s) 32 | print(s.decode('utf-8')) 33 | 34 | print('{:10s} {:10d} {:10.2f}'.format ('ACME', 100, 490.1).encode('ascii')) 35 | 36 | 37 | if __name__ == '__main__': 38 | byte_str() -------------------------------------------------------------------------------- /cookbook/c03/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c03/p01_round.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 四舍五入运算 5 | Desc : 6 | """ 7 | 8 | 9 | def round_num(): 10 | print(round(1.23, 1)) 11 | print(round(1.27, 1)) 12 | print(round(-1.27, 1)) 13 | print(round(1.25361,3)) 14 | 15 | # 舍入数为负数 16 | a = 1627731 17 | print(round(a, -1)) 18 | print(round(a, -2)) 19 | print(round(a, -3)) 20 | 21 | # 格式化输出 22 | x = 1.23456 23 | print(format(x, '0.2f')) 24 | print(format(x, '0.3f')) 25 | print('value is {:0.3f}'.format(x)) 26 | 27 | # 不要自以为是的用round去修正一些精度问题 28 | a = 2.1 29 | b = 4.2 30 | c = a + b 31 | print(c) 32 | c = round(c, 2) # "Fix" result (???) 33 | print(c) 34 | 35 | if __name__ == '__main__': 36 | round_num() 37 | 38 | -------------------------------------------------------------------------------- /cookbook/c03/p02_accurate_decimal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 精确的浮点数运算 5 | Desc : 6 | """ 7 | from decimal import Decimal 8 | from decimal import localcontext 9 | import math 10 | 11 | 12 | def acc_deciamal(): 13 | a = 4.2 14 | b = 2.1 15 | print(a + b) 16 | print((a + b) == 6.3) 17 | 18 | # 使用decimal模块 19 | a = Decimal('4.2') 20 | b = Decimal('2.1') 21 | print(a + b) 22 | print((a + b) == Decimal('6.3')) 23 | 24 | a = Decimal('1.3') 25 | b = Decimal('1.7') 26 | print(a / b) 27 | with localcontext() as ctx: 28 | ctx.prec = 3 29 | print(a / b) 30 | 31 | nums = [1.23e+18, 1, -1.23e+18] 32 | print(sum(nums)) 33 | print(math.fsum(nums)) 34 | 35 | 36 | if __name__ == '__main__': 37 | acc_deciamal() 38 | -------------------------------------------------------------------------------- /cookbook/c03/p03_format_number.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 格式化输出数字 5 | Desc : 6 | """ 7 | 8 | 9 | def format_number(): 10 | x = 1234.56789 11 | # Two decimal places of accuracy 12 | print(format(x, '0.2f')) 13 | 14 | # Right justified in 10 chars, one-digit accuracy 15 | print(format(x, '>10.1f')) 16 | 17 | # Left justified 18 | print(format(x, '<10.1f')) 19 | 20 | # Centered 21 | print(format(x, '^10.1f')) 22 | 23 | # Inclusion of thousands separator 24 | print(format(x, ',')) 25 | print(format(x, '0,.1f')) 26 | 27 | print(format(x, 'e')) 28 | print(format(x, '0.2E')) 29 | 30 | # strings 31 | print('The value is {:0,.2f}'.format(x)) 32 | 33 | print(format(x, '0.1f')) 34 | print(format(-x, '0.1f')) 35 | 36 | swap_separators = {ord('.'): ',', ord(','): '.'} 37 | print(format(x, ',').translate(swap_separators)) 38 | 39 | 40 | if __name__ == '__main__': 41 | format_number() 42 | 43 | 44 | -------------------------------------------------------------------------------- /cookbook/c03/p04_bin_octal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 不同进制的数字表示输出 5 | Desc : 6 | """ 7 | 8 | 9 | def bin_octal(): 10 | x = 1234 11 | print(type(bin(x))) 12 | print(bin(x), oct(x), hex(x)) 13 | 14 | # format() function 15 | print(format(x, 'b')) 16 | print(format(x, 'o')) 17 | print(format(x, 'x')) 18 | 19 | print(int('4d2', 16)) 20 | print(int('10011010010', 2)) 21 | 22 | 23 | if __name__ == '__main__': 24 | bin_octal() 25 | -------------------------------------------------------------------------------- /cookbook/c03/p05_int_bytes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 大整数与字节的相互转换 5 | Desc : 6 | """ 7 | 8 | 9 | def int_bytes(): 10 | data = b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004' 11 | print(len(data)) 12 | print(int.from_bytes(data, 'little')) 13 | print(int.from_bytes(data, 'big')) 14 | 15 | x = 94522842520747284487117727783387188 16 | print(x.to_bytes(16, 'big')) 17 | print(x.to_bytes(20, 'big')) 18 | 19 | 20 | # bit_length真有用 21 | x = 523 ** 23 22 | print(x) 23 | print(x.bit_length()) 24 | nbytes, rem = divmod(x.bit_length(), 8) 25 | if rem: 26 | nbytes += 1 27 | print(x.to_bytes(nbytes, 'little')) 28 | 29 | if __name__ == '__main__': 30 | int_bytes() 31 | 32 | -------------------------------------------------------------------------------- /cookbook/c03/p06_complex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | import cmath 8 | 9 | 10 | def complex_math(): 11 | a = complex(2, 4) 12 | b = 3 - 5j 13 | print(a.conjugate()) 14 | 15 | # 正弦 余弦 平方根等 16 | print(cmath.sin(a)) 17 | print(cmath.cos(a)) 18 | print(cmath.sqrt(a)) 19 | 20 | 21 | 22 | if __name__ == '__main__': 23 | complex_math() 24 | -------------------------------------------------------------------------------- /cookbook/c03/p07_inf_nan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 无穷大与NaN 5 | Desc : 6 | """ 7 | 8 | 9 | def inf_nan(): 10 | a = float('inf') 11 | b = float('-inf') 12 | c = float('nan') 13 | 14 | print(a + 45) 15 | print(a + 45 == a) 16 | print(a * 10 == a) 17 | print(10 / a) 18 | 19 | # undefined 20 | print(a / a) 21 | print(a + b) 22 | 23 | print(c + 23) 24 | print(c / 2 == c) # False ? 25 | 26 | 27 | if __name__ == '__main__': 28 | inf_nan() 29 | 30 | -------------------------------------------------------------------------------- /cookbook/c03/p08_fraction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 分数运算 5 | Desc : 6 | """ 7 | from fractions import Fraction 8 | 9 | 10 | def frac(): 11 | a = Fraction(5, 4) 12 | b = Fraction(7, 16) 13 | print(print(a + b)) 14 | print(a.numerator, a.denominator) 15 | 16 | c = a + b 17 | print(float(c)) 18 | print(type(c.limit_denominator(8))) 19 | print(c.limit_denominator(8)) 20 | 21 | 22 | if __name__ == '__main__': 23 | frac() 24 | -------------------------------------------------------------------------------- /cookbook/c03/p09_array_numpy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 利用numpy执行数组运算 5 | Desc : 6 | """ 7 | import numpy as np 8 | 9 | 10 | def array_numpy(): 11 | x = [1, 2, 3, 4] 12 | y = [5, 6, 7, 8] 13 | print(x * 2) 14 | print(x + y) 15 | 16 | # Numpy arrays 17 | ax = np.array([1, 2, 3, 4]) 18 | ay = np.array([5, 6, 7, 8]) 19 | print(ax * 2) 20 | print(ax + ay) 21 | print(ax * ay) 22 | 23 | print(f(ax)) 24 | print(np.sqrt(ax)) 25 | print(np.cos(ax)) 26 | 27 | # 大数组 28 | grid = np.zeros(shape=(10000, 10000), dtype=float) 29 | grid += 10 30 | print(grid) 31 | print(np.sin(grid)) 32 | 33 | # 二维数组的索引操作 34 | a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) 35 | print(a) 36 | print(a[1]) # Select row 1 37 | print(a[:, 1]) # Select column 1 38 | # Select a subregion and change it 39 | print(a[1:3, 1:3]) 40 | a[1:3, 1:3] += 10 41 | print(a) 42 | 43 | # Broadcast a row vector across an operation on all rows 44 | print(a + [100, 101, 102, 103]) 45 | # Conditional assignment on an array 46 | print(np.where(a < 10, a, 10)) 47 | 48 | 49 | 50 | def f(x): 51 | return 3 * x ** 2 - 2 * x + 7 52 | 53 | 54 | if __name__ == '__main__': 55 | array_numpy() -------------------------------------------------------------------------------- /cookbook/c03/p10_matrix_linear.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 矩阵和线性代数 5 | Desc : 6 | """ 7 | import numpy as np 8 | import numpy.linalg 9 | 10 | 11 | def matrix_linear(): 12 | m = np.matrix([[1,-2,3],[0,4,5],[7,8,-9]]) 13 | print(m) 14 | 15 | # Return transpose 转置矩阵 16 | print(m.T) 17 | 18 | # Return inverse # 逆矩阵 19 | print(m.I) 20 | 21 | 22 | # Create a vector and multiply 23 | v = np.matrix([[2],[3],[4]]) 24 | print(v) 25 | print(m * v) 26 | 27 | # Determinant 行列式 28 | print(numpy.linalg.det(m)) 29 | 30 | # Eigenvalues 特征值 31 | print(numpy.linalg.eigvals(m)) 32 | 33 | # Solve for x in m*x = v 34 | x = numpy.linalg.solve(m, v) 35 | print(x) 36 | print(m * x) 37 | print(v) 38 | 39 | 40 | 41 | if __name__ == '__main__': 42 | matrix_linear() 43 | -------------------------------------------------------------------------------- /cookbook/c03/p11_random_num.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 随机数 5 | Desc : 6 | """ 7 | import random 8 | 9 | 10 | def random_num(): 11 | values = [1, 2, 3, 4, 5, 6] 12 | print(random.choice(values)) 13 | print(random.choice(values)) 14 | print(random.choice(values)) 15 | print(random.choice(values)) 16 | print(random.choice(values)) 17 | 18 | # 抽取样本 19 | print(random.sample(values, 2)) 20 | print(random.sample(values, 2)) 21 | print(random.sample(values, 3)) 22 | 23 | # 打算顺序 24 | random.shuffle(values) 25 | print(values) 26 | 27 | # 随机整数 28 | print(random.randint(0,10)) 29 | print(random.randint(0,10)) 30 | print(random.randint(0,10)) 31 | print(random.randint(0,10)) 32 | 33 | # 随机二进制数的整数返回 34 | print(random.getrandbits(200)) 35 | 36 | # 修改随机数生成的种子 37 | random.seed() # Seed based on system time or os.urandom() 38 | random.seed(12345) # Seed based on integer given 39 | random.seed(b'bytedata') # Seed based on byte data 40 | 41 | if __name__ == '__main__': 42 | random_num() 43 | 44 | -------------------------------------------------------------------------------- /cookbook/c03/p12_datatime.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 日期时间转换 5 | Desc : 6 | """ 7 | from datetime import timedelta 8 | from datetime import datetime 9 | from dateutil.relativedelta import relativedelta 10 | 11 | 12 | def date_time(): 13 | a = timedelta(days=2, hours=6) 14 | b = timedelta(hours=4.5) 15 | c = a + b 16 | print(c.days) 17 | print(c.seconds) 18 | print(c.seconds / 3600) 19 | print(c.total_seconds() / 3600) 20 | 21 | # 具体的日期 22 | a = datetime(2012, 9, 23) 23 | print(a + timedelta(days=10)) 24 | b = datetime(2012, 12, 21) 25 | d = b - a 26 | print(d.days) 27 | now = datetime.today() 28 | print(now) 29 | print(now + timedelta(minutes=10)) 30 | 31 | # 标准库中datetime模块 32 | a = datetime(2012, 9, 23) 33 | # a + timedelta(months=1) # 这个会报错 34 | 35 | # 使用dateutil模块解决这个问题 36 | print(a + relativedelta(months=+1)) 37 | print(a + relativedelta(months=+4)) 38 | 39 | # Time between two dates 40 | b = datetime(2012, 12, 21) 41 | d = b - a 42 | print(d) 43 | d = relativedelta(b, a) 44 | print(d) 45 | print(d.months, d.days) 46 | 47 | 48 | 49 | if __name__ == '__main__': 50 | date_time() 51 | 52 | -------------------------------------------------------------------------------- /cookbook/c03/p13_last_friday.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 最后的周五 5 | Desc : 6 | """ 7 | from datetime import datetime, timedelta 8 | from dateutil.relativedelta import relativedelta 9 | from dateutil.rrule import * 10 | 11 | weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 12 | 'Friday', 'Saturday', 'Sunday'] 13 | 14 | 15 | def get_previous_byday(dayname, start_date=None): 16 | if start_date is None: 17 | start_date = datetime.today() 18 | day_num = start_date.weekday() 19 | day_num_target = weekdays.index(dayname) 20 | days_ago = (7 + day_num - day_num_target) % 7 21 | if days_ago == 0: 22 | days_ago = 7 23 | target_date = start_date - timedelta(days=days_ago) 24 | return target_date 25 | 26 | 27 | def last_friday(): 28 | print(datetime.today()) 29 | print(get_previous_byday('Monday')) 30 | print(get_previous_byday('Tuesday')) 31 | print(get_previous_byday('Friday')) 32 | print(get_previous_byday('Saturday')) 33 | # 显式的传递开始日期 34 | print(get_previous_byday('Sunday', datetime(2012, 12, 21))) 35 | 36 | # 使用dateutil模块 37 | d = datetime.now() 38 | # 下一个周五 39 | print(d + relativedelta(weekday=FR)) 40 | # 上一个周五 41 | print(d + relativedelta(weekday=FR(-1))) 42 | # 下一个周六, 为什么如果今天是周六,下一个/上一个都返回今天的日期?? 43 | print(d + relativedelta(weekday=SA)) 44 | # 上一个周六 45 | print(d + relativedelta(weekday=SA(-1))) 46 | 47 | 48 | if __name__ == '__main__': 49 | last_friday() 50 | 51 | 52 | -------------------------------------------------------------------------------- /cookbook/c03/p14_month_range.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 计算当前月份的日期范围 5 | Desc : 6 | """ 7 | from datetime import datetime, date, timedelta 8 | import calendar 9 | 10 | 11 | def get_month_range(start_date=None): 12 | if start_date is None: 13 | start_date = date.today().replace(day=1) 14 | _, days_in_month = calendar.monthrange(start_date.year, start_date.month) 15 | end_date = start_date + timedelta(days=days_in_month) 16 | return (start_date, end_date) 17 | 18 | 19 | def date_range(start, stop, step): 20 | while start < stop: 21 | yield start 22 | start += step 23 | 24 | 25 | def month_range(): 26 | a_day = timedelta(days=1) 27 | first_day, last_day = get_month_range() 28 | while first_day < last_day: 29 | print(first_day) 30 | first_day += a_day 31 | 32 | # 使用生成器 33 | for d in date_range(datetime(2012, 9, 1), datetime(2012, 10, 1), 34 | timedelta(hours=6)): 35 | print(d) 36 | 37 | 38 | if __name__ == '__main__': 39 | month_range() 40 | 41 | -------------------------------------------------------------------------------- /cookbook/c03/p15_str_datetime.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字符串转换为datetime 5 | Desc : 6 | """ 7 | from datetime import datetime 8 | 9 | 10 | def str_datetime(): 11 | text = '2012-09-20' 12 | y = datetime.strptime(text, '%Y-%m-%d') 13 | z = datetime.now() 14 | diff = z - y 15 | print(diff) 16 | 17 | print(z) 18 | nice_z = datetime.strftime(z, '%A %B %d, %Y') 19 | print(nice_z) 20 | 21 | 22 | def parse_ymd(s): 23 | '''自定义解析,要快很多''' 24 | year_s, mon_s, day_s = s.split('-') 25 | return datetime(int(year_s), int(mon_s), int(day_s)) 26 | 27 | 28 | if __name__ == '__main__': 29 | str_datetime() 30 | 31 | -------------------------------------------------------------------------------- /cookbook/c03/p16_timezone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 日期时区和本地化 5 | Desc : 6 | """ 7 | from datetime import datetime, timedelta 8 | from pytz import timezone 9 | import pytz 10 | 11 | 12 | def tz_local(): 13 | d = datetime(2012, 12, 21, 9, 30, 0) 14 | print(d) 15 | 16 | # Localize the date for Chicago 17 | central = timezone('US/Central') 18 | loc_d = central.localize(d) 19 | print(loc_d) 20 | 21 | # Convert to Bangalore time 22 | bang_d = loc_d.astimezone(timezone('Asia/Kolkata')) 23 | print(bang_d) 24 | 25 | 26 | # 夏令时 27 | d = datetime(2013, 3, 10, 1, 45) 28 | loc_d = central.localize(d) 29 | print(loc_d) 30 | later = loc_d + timedelta(minutes=30) 31 | print(later) 32 | # 使用normalize修正这个问题 33 | later = central.normalize(loc_d + timedelta(minutes=30)) 34 | print(later) 35 | 36 | # 一个普遍策略是先转换为UTC时间,使用UTC时间来进行计算 37 | print(loc_d) 38 | utc_d = loc_d.astimezone(pytz.utc) 39 | print(utc_d) 40 | 41 | later_utc = utc_d + timedelta(minutes=30) 42 | # 转回到本地时间 43 | print(later_utc.astimezone(central)) 44 | 45 | # 根据ISO 3166国家代码查找时区名称 46 | print(pytz.country_timezones['IN']) 47 | 48 | if __name__ == '__main__': 49 | tz_local() 50 | 51 | -------------------------------------------------------------------------------- /cookbook/c04/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c04/p01_manual_iterator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 手动遍历迭代器 5 | Desc : 6 | """ 7 | 8 | 9 | def manual_iter(): 10 | with open('/etc/passwd') as f: 11 | try: 12 | while True: 13 | line = next(f) 14 | print(line, end='') 15 | except StopIteration: 16 | pass 17 | 18 | def manual_iter2(): 19 | with open('/etc/passwd') as f: 20 | while True: 21 | line = next(f) 22 | if line is None: 23 | break 24 | print(line, end='') 25 | 26 | 27 | if __name__ == '__main__': 28 | manual_iter() -------------------------------------------------------------------------------- /cookbook/c04/p02_delegate_iter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 代理迭代 5 | Desc : 6 | """ 7 | 8 | 9 | class Node: 10 | def __init__(self, value): 11 | self._value = value 12 | self._children = [] 13 | 14 | def __repr__(self): 15 | return 'Node({!r})'.format(self._value) 16 | 17 | def add_child(self, node): 18 | self._children.append(node) 19 | 20 | def __iter__(self): 21 | return iter(self._children) 22 | 23 | # Example 24 | if __name__ == '__main__': 25 | root = Node(0) 26 | child1 = Node(1) 27 | child2 = Node(2) 28 | root.add_child(child1) 29 | root.add_child(child2) 30 | # Outputs Node(1), Node(2) 31 | for ch in root: 32 | print(ch) 33 | -------------------------------------------------------------------------------- /cookbook/c04/p03_generator_pattern.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 使用生成器创建新的迭代模式 5 | Desc : 6 | """ 7 | 8 | 9 | def frange(start, stop, increment): 10 | x = start 11 | while x < stop: 12 | yield x 13 | x += increment 14 | 15 | 16 | def countdown(n): 17 | print('Starting to count from', n) 18 | while n > 0: 19 | yield n 20 | n -= 1 21 | print('Done') 22 | 23 | 24 | def gen_pattern(): 25 | for n in frange(0, 4, 0.5): 26 | print(n) 27 | print(list(frange(0, 1, 0.125))) 28 | 29 | #生成器函数 30 | # Create the generator, notice no output appears 31 | c = countdown(3) 32 | print(next(c)) 33 | print(next(c)) 34 | print(next(c)) 35 | print(next(c)) 36 | 37 | if __name__ == '__main__': 38 | gen_pattern() -------------------------------------------------------------------------------- /cookbook/c04/p05_reverse_iterate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 方向迭代 5 | Desc : 6 | """ 7 | 8 | 9 | def reverse_iterate(): 10 | a = [1, 2, 3, 4] 11 | for x in reversed(a): 12 | print(x) 13 | 14 | # 两个条件:大小可知或者实现__reversed__方法, 15 | # 如果都不满足,先转换为list 16 | # Print a file backwards 17 | # f = open('somefile') 18 | # for line in reversed(list(f)): 19 | # print(line, end='') 20 | 21 | for rr in reversed(Countdown(30)): 22 | print(rr) 23 | for rr in Countdown(30): 24 | print(rr) 25 | 26 | 27 | class Countdown: 28 | def __init__(self, start): 29 | self.start = start 30 | 31 | # Forward iterator 32 | def __iter__(self): 33 | n = self.start 34 | while n > 0: 35 | yield n 36 | n -= 1 37 | 38 | # Reverse iterator 39 | def __reversed__(self): 40 | n = 1 41 | while n <= self.start: 42 | yield n 43 | n += 1 44 | 45 | 46 | if __name__ == '__main__': 47 | reverse_iterate() 48 | 49 | -------------------------------------------------------------------------------- /cookbook/c04/p06_generator_extrastate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 带外部状态的生成器 5 | Desc : 6 | """ 7 | from collections import deque 8 | 9 | 10 | class linehistory: 11 | def __init__(self, lines, histlen=3): 12 | self.lines = lines 13 | self.history = deque(maxlen=histlen) 14 | 15 | def __iter__(self): 16 | for lineno, line in enumerate(self.lines, 1): 17 | self.history.append((lineno, line)) 18 | yield line 19 | 20 | def clear(self): 21 | self.history.clear() 22 | 23 | 24 | def gen_extrastate(): 25 | with open('somefile.txt') as f: 26 | lines = linehistory(f) 27 | for line in lines: 28 | if 'python' in line: 29 | for lineno, hline in lines.history: 30 | print('{}:{}'.format(lineno, hline), end='') 31 | 32 | 33 | if __name__ == '__main__': 34 | gen_extrastate() 35 | 36 | 37 | -------------------------------------------------------------------------------- /cookbook/c04/p07_iterator_slice.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 迭代器和生成器切片 5 | Desc : 6 | """ 7 | import itertools 8 | 9 | 10 | def count(n): 11 | while True: 12 | yield n 13 | n += 1 14 | 15 | 16 | def iter_slice(): 17 | c = count(0) 18 | for x in itertools.islice(c, 10, 20): 19 | print(x) 20 | 21 | 22 | if __name__ == '__main__': 23 | iter_slice() 24 | 25 | 26 | -------------------------------------------------------------------------------- /cookbook/c04/p08_skip_iterable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 跳过可迭代对象开始部分 5 | Desc : 6 | """ 7 | from itertools import dropwhile 8 | from itertools import islice 9 | 10 | 11 | def skip_iter(): 12 | # with open('/etc/passwd') as f: 13 | # for line in dropwhile(lambda line: not line.startswith('#'), f): 14 | # print(line, end='') 15 | 16 | # 明确知道了要跳过的元素序号 17 | items = ['a', 'b', 'c', 1, 4, 10, 15] 18 | for x in islice(items, 3, None): 19 | print(x) 20 | 21 | if __name__ == '__main__': 22 | skip_iter() 23 | 24 | 25 | -------------------------------------------------------------------------------- /cookbook/c04/p09_iter_permutation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 排列组合迭代 5 | Desc : 6 | """ 7 | from itertools import permutations 8 | from itertools import combinations 9 | from itertools import combinations_with_replacement 10 | 11 | 12 | def iter_permutation(): 13 | """排列组合""" 14 | 15 | items = ['a', 'b', 'c'] 16 | 17 | # 全排列 18 | for p in permutations(items): 19 | print(p) 20 | 21 | # 指定长度 22 | for p in permutations(items, 2): 23 | print(p) 24 | 25 | # 组合 26 | for c in combinations(items, 3): 27 | print(c) 28 | 29 | # 可重复组合 30 | for c in combinations_with_replacement(items, 3): 31 | print(c) 32 | 33 | if __name__ == '__main__': 34 | iter_permutation() 35 | -------------------------------------------------------------------------------- /cookbook/c04/p10_iterate_index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 迭代并跟踪索引 5 | Desc : 6 | """ 7 | from collections import defaultdict 8 | 9 | 10 | def iterate_index(): 11 | my_list = ['a', 'b', 'c'] 12 | for idx, val in enumerate(my_list): 13 | print(idx, val) 14 | # 索引从1开始 15 | for idx, val in enumerate(my_list, 1): 16 | print(idx, val) 17 | 18 | # 序列中含有元组的解压 19 | data = [ (1, 2), (3, 4), (5, 6), (7, 8) ] 20 | for n, (x, y) in enumerate(data): 21 | print(n) 22 | print(x, y) 23 | 24 | 25 | def parse_data(filename): 26 | with open(filename, 'rt') as f: 27 | for lineno, line in enumerate(f, 1): 28 | fields = line.split() 29 | try: 30 | count = int(fields[1]) 31 | # ... 32 | except ValueError as e: 33 | print('Line {}: Parse error: {}'.format(lineno, e)) 34 | 35 | 36 | def word_lines(): 37 | word_summary = defaultdict(list) 38 | with open('myfile.txt', 'r') as f: 39 | lines = f.readlines() 40 | for idx, line in enumerate(lines): 41 | # Create a list of words in current line 42 | words = [w.strip().lower() for w in line.split()] 43 | for word in words: 44 | word_summary[word].append(idx) 45 | 46 | if __name__ == '__main__': 47 | iterate_index() 48 | 49 | -------------------------------------------------------------------------------- /cookbook/c04/p11_iterate_simultaneous.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 同时迭代多个序列 5 | Desc : 6 | """ 7 | from itertools import zip_longest 8 | 9 | 10 | def iterate_simul(): 11 | xpts = [1, 5, 4, 2, 10, 7] 12 | ypts = [101, 78, 37, 15, 62, 99] 13 | for x, y in zip(xpts, ypts): 14 | print(x, y) 15 | 16 | a = [1, 2, 3] 17 | b = ['w', 'x', 'y', 'z'] 18 | for i in zip(a,b): 19 | print(i) # 默认是按最短长度 20 | for i in zip_longest(a,b): 21 | print(i) 22 | for i in zip_longest(a, b, fillvalue=0): 23 | print(i) 24 | 25 | headers = ['name', 'shares', 'price'] 26 | values = ['ACME', 100, 490.1] 27 | s = dict(zip(headers,values)) 28 | 29 | for name, val in zip(headers, values): 30 | print(name, '=', val) 31 | 32 | 33 | if __name__ == '__main__': 34 | iterate_simul() 35 | 36 | -------------------------------------------------------------------------------- /cookbook/c04/p12_iterate_separate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 在不同容器中迭代 5 | Desc : 6 | """ 7 | from itertools import chain 8 | 9 | 10 | def iter_separate(): 11 | a = [1, 2, 3, 4] 12 | b = ['x', 'y', 'z'] 13 | for x in chain(a, b): 14 | print(x) 15 | 16 | if __name__ == '__main__': 17 | iter_separate() 18 | 19 | -------------------------------------------------------------------------------- /cookbook/c04/p14_flatten_sequence.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | from collections import Iterable 8 | 9 | 10 | def flatten(items, ignore_types=(str, bytes)): 11 | for x in items: 12 | if isinstance(x, Iterable) and not isinstance(x, ignore_types): 13 | yield from flatten(x) 14 | else: 15 | yield x 16 | 17 | 18 | def flatten_seq(): 19 | items = [1, 2, [3, 4, [5, 6], 7], 8] 20 | # Produces 1 2 3 4 5 6 7 8 21 | for x in flatten(items): 22 | print(x) 23 | items = ['Dave', 'Paula', ['Thomas', 'Lewis']] 24 | for x in flatten(items): 25 | print(x) 26 | 27 | if __name__ == '__main__': 28 | flatten_seq() -------------------------------------------------------------------------------- /cookbook/c04/p15_merge_sorted.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | import heapq 8 | 9 | 10 | def merge_sorted(): 11 | a = [1, 4, 7, 10] 12 | b = [2, 5, 6, 11] 13 | for c in heapq.merge(a, b): 14 | print(c) 15 | 16 | # 合并排序文件 17 | with open('sorted_file_1', 'rt') as file1, \ 18 | open('sorted_file_2', 'rt') as file2, \ 19 | open('merged_file', 'wt') as outf: 20 | 21 | for line in heapq.merge(file1, file2): 22 | outf.write(line) 23 | 24 | 25 | if __name__ == '__main__': 26 | merge_sorted() 27 | 28 | -------------------------------------------------------------------------------- /cookbook/c04/p16_iterate_while.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 使用迭代器重写while无限循环 5 | Desc : 6 | """ 7 | import sys 8 | 9 | 10 | def process_data(): 11 | print(data) 12 | 13 | 14 | def reader(s, size): 15 | while True: 16 | data = s.recv(size) 17 | if data == b'': 18 | break 19 | # process_data(data) 20 | 21 | 22 | def reader2(s, size): 23 | for data in iter(lambda: s.recv(size), b''): 24 | process_data(data) 25 | 26 | 27 | def iterate_while(): 28 | CHUNKSIZE = 8192 29 | with open('/etc/passwd') as f: 30 | for chunk in iter(lambda: f.read(10), ''): 31 | n = sys.stdout.write(chunk) 32 | 33 | 34 | if __name__ == '__main__': 35 | iterate_while() 36 | -------------------------------------------------------------------------------- /cookbook/c05/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c05/p01_rw_text.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 读写文本文件 5 | Desc : 6 | """ 7 | 8 | def rw_text(): 9 | # Iterate over the lines of the file 10 | with open('somefile.txt', 'rt') as f: 11 | for line in f: 12 | # process line 13 | print(line) 14 | 15 | # Write chunks of text data 16 | with open('somefile.txt', 'wt') as f: 17 | f.write('text1') 18 | f.write('text2') 19 | 20 | if __name__ == '__main__': 21 | rw_text() 22 | 23 | -------------------------------------------------------------------------------- /cookbook/c05/p02_print_tofile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 输出重定向到文件 5 | Desc : 6 | """ 7 | 8 | 9 | def print_tofile(): 10 | with open('d:/work/test.txt', 'wt') as f: 11 | print('Hello World!', file=f) 12 | 13 | if __name__ == '__main__': 14 | print_tofile() -------------------------------------------------------------------------------- /cookbook/c05/p03_print_sepend.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: print分隔符和结尾符 5 | Desc : 6 | """ 7 | 8 | def print_sepend(): 9 | print('ACME', 50, 91.5) 10 | print('ACME', 50, 91.5, sep=',') 11 | print('ACME', 50, 91.5, sep=',', end='!!\n') 12 | for i in range(5): 13 | print(i) 14 | for i in range(5): 15 | print(i, end=' ') 16 | print() 17 | 18 | row = ['ACME', 50, 91.5] 19 | print(*row, sep=',') 20 | 21 | if __name__ == '__main__': 22 | print_sepend() 23 | 24 | -------------------------------------------------------------------------------- /cookbook/c05/p04_rw_binary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 读写二进制文件 5 | Desc : 6 | """ 7 | 8 | 9 | def rw_binary(): 10 | # Read the entire file as a single byte string 11 | with open('somefile.bin', 'rb') as f: 12 | data = f.read() 13 | 14 | # Write binary data to a file 15 | with open('somefile.bin', 'wb') as f: 16 | f.write(b'Hello World') 17 | 18 | # Text string 19 | t = 'Hello World' 20 | print(t[0]) 21 | 22 | # Byte string 23 | b = b'Hello World' 24 | print(b[0]) 25 | for c in b: 26 | print(c) 27 | 28 | if __name__ == '__main__': 29 | rw_binary() 30 | 31 | -------------------------------------------------------------------------------- /cookbook/c05/p05_write_notexist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 文件不存在时才写入 5 | Desc : 6 | """ 7 | 8 | 9 | def write_noexist(): 10 | with open('D:/work/test1.txt', 'wt') as f: 11 | f.write('BBBBBBBBBBBB') 12 | with open('D:/work/tt.txt', 'xt') as f: 13 | f.write('XXXXXXX') 14 | 15 | if __name__ == '__main__': 16 | write_noexist() -------------------------------------------------------------------------------- /cookbook/c05/p06_string_io.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字符串的I/O操作 5 | Desc : 6 | """ 7 | import io 8 | 9 | 10 | def string_io(): 11 | s = io.StringIO() 12 | s.write('Hello World\n') 13 | print('This is a test', file=s) 14 | # Get all of the data written so far 15 | print(s.getvalue()) 16 | 17 | # Wrap a file interface around an existing string 18 | s = io.StringIO('Hello\nWorld\n') 19 | print(s.read(4)) 20 | print(s.read()) 21 | 22 | if __name__ == '__main__': 23 | string_io() 24 | 25 | -------------------------------------------------------------------------------- /cookbook/c05/p07_gzip_bz2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 读写压缩文件 5 | Desc : 6 | """ 7 | import gzip 8 | import bz2 9 | 10 | 11 | def gzip_bz2(): 12 | with gzip.open('somefile.gz', 'rt') as f: 13 | text = f.read() 14 | with bz2.open('somefile.bz2', 'rt') as f: 15 | text = f.read() 16 | 17 | with gzip.open('somefile.gz', 'wt') as f: 18 | f.write(text) 19 | with bz2.open('somefile.bz2', 'wt') as f: 20 | f.write(text) 21 | with gzip.open('somefile.gz', 'wt', compresslevel=5) as f: 22 | f.write(text) 23 | 24 | # 作用在已打开的二进制文件上 25 | f = open('somefile.gz', 'rb') 26 | with gzip.open(f, 'rt') as g: 27 | text = g.read() 28 | 29 | if __name__ == '__main__': 30 | gzip_bz2() 31 | -------------------------------------------------------------------------------- /cookbook/c05/p08_iterate_fixedsize.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 固定长度迭代文件 5 | Desc : 6 | """ 7 | from functools import partial 8 | 9 | 10 | def iterate_fixed(): 11 | RECORD_SIZE = 32 12 | 13 | with open('somefile.data', 'rb') as f: 14 | records = iter(partial(f.read, RECORD_SIZE), b'') 15 | for r in records: 16 | print(r) 17 | 18 | if __name__ == '__main__': 19 | iterate_fixed() 20 | 21 | -------------------------------------------------------------------------------- /cookbook/c05/p09_read_tobuffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 读取二进制数据到可变缓冲区中 5 | Desc : 6 | """ 7 | import os.path 8 | 9 | 10 | def read_into_buffer(filename): 11 | buf = bytearray(os.path.getsize(filename)) 12 | with open(filename, 'rb') as f: 13 | f.readinto(buf) 14 | return buf 15 | 16 | 17 | def read_tobuffer(): 18 | buf = bytearray(os.path.getsize('filename')) 19 | print(buf) 20 | m1 = memoryview(buf) 21 | m2 = m1[-5:] 22 | print(m2) 23 | m2[:] = b'WORLD' 24 | print(buf) 25 | 26 | bytearray(b'Hello World') 27 | 28 | 29 | if __name__ == '__main__': 30 | read_tobuffer() 31 | -------------------------------------------------------------------------------- /cookbook/c05/p10_memery_mapping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 文件的内存映射 5 | Desc : 6 | """ 7 | import os 8 | import mmap 9 | 10 | 11 | def memory_map(filename, access=mmap.ACCESS_WRITE): 12 | size = os.path.getsize(filename) 13 | fd = os.open(filename, os.O_RDWR) 14 | return mmap.mmap(fd, size, access=access) 15 | 16 | 17 | def mem_mapping(): 18 | pass 19 | 20 | 21 | if __name__ == '__main__': 22 | mem_mapping() 23 | 24 | -------------------------------------------------------------------------------- /cookbook/c05/p11_pathnames.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 操作路径名 5 | Desc : 6 | """ 7 | import os 8 | 9 | 10 | def path_names(): 11 | path = '/Users/beazley/Data/data.csv' 12 | print(os.path.basename(path)) 13 | print(os.path.dirname(path)) 14 | print(os.path.join('tmp', 'data', os.path.basename(path))) 15 | 16 | path = '~/Data/data.csv' 17 | print(os.path.expanduser(path)) 18 | print(os.path.splitext(path)) 19 | 20 | if __name__ == '__main__': 21 | path_names() 22 | 23 | -------------------------------------------------------------------------------- /cookbook/c05/p12_file_existence.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 测试文件或目录是否存在 5 | Desc : 6 | """ 7 | import os 8 | import time 9 | 10 | 11 | def file_existence(): 12 | print(os.path.exists('/etc/passwd')) 13 | print(os.path.exists('/tmp/spam')) 14 | 15 | print(os.path.isfile('/etc/passwd')) 16 | print(os.path.isdir('/etc/passwd')) 17 | print(os.path.islink('/usr/local/bin/python3')) 18 | print(os.path.realpath('/usr/local/bin/python3')) 19 | 20 | print(os.path.getsize('/etc/passwd')) 21 | print(os.path.getmtime('/etc/passwd')) 22 | print(time.ctime(os.path.getmtime('/etc/passwd'))) 23 | 24 | 25 | if __name__ == '__main__': 26 | file_existence() 27 | 28 | -------------------------------------------------------------------------------- /cookbook/c05/p13_dir_listfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 目录文件列表 5 | Desc : 6 | """ 7 | import os 8 | import os.path 9 | import glob 10 | from fnmatch import fnmatch 11 | 12 | 13 | def dir_listfile(): 14 | names = os.listdir('somedir') 15 | 16 | # Get all regular files 17 | names = [name for name in os.listdir('somedir') 18 | if os.path.isfile(os.path.join('somedir', name))] 19 | 20 | # Get all dirs 21 | dirnames = [name for name in os.listdir('somedir') 22 | if os.path.isdir(os.path.join('somedir', name))] 23 | 24 | pyfiles = [name for name in os.listdir('somedir') 25 | if name.endswith('.py')] 26 | 27 | pyfiles = glob.glob('somedir/*.py') 28 | 29 | pyfiles = [name for name in os.listdir('somedir') 30 | if fnmatch(name, '*.py')] 31 | 32 | pyfiles = glob.glob('*.py') 33 | 34 | # Get file sizes and modification dates 35 | name_sz_date = [(name, os.path.getsize(name), os.path.getmtime(name)) 36 | for name in pyfiles] 37 | for name, size, mtime in name_sz_date: 38 | print(name, size, mtime) 39 | 40 | # Alternative: Get file metadata 41 | file_metadata = [(name, os.stat(name)) for name in pyfiles] 42 | for name, meta in file_metadata: 43 | print(name, meta.st_size, meta.st_mtime) 44 | 45 | 46 | if __name__ == '__main__': 47 | dir_listfile() 48 | 49 | -------------------------------------------------------------------------------- /cookbook/c05/p14_bypass_encode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 忽略文件名编码 5 | Desc : 6 | """ 7 | import sys 8 | 9 | 10 | def bypass_encoding(): 11 | print(sys.getfilesystemencoding()) 12 | 13 | if __name__ == '__main__': 14 | bypass_encoding() 15 | 16 | -------------------------------------------------------------------------------- /cookbook/c05/p15_print_badfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 打印不合法文件名 5 | Desc : 6 | """ 7 | import os 8 | import sys 9 | 10 | 11 | def bad_filename(filename): 12 | return repr(filename)[1:-1] 13 | 14 | 15 | def bad_filename2(filename): 16 | """完美方案""" 17 | temp = filename.encode(sys.getfilesystemencoding(), errors='surrogateescape') 18 | return temp.decode('latin-1') 19 | 20 | 21 | def print_badfile(filename): 22 | try: 23 | print(filename) 24 | except UnicodeEncodeError: 25 | print('UnicodeEncodeError') 26 | print(bad_filename(filename)) 27 | 28 | files = os.listdir('.') 29 | print(files) 30 | 31 | 32 | if __name__ == '__main__': 33 | print_badfile('bäd.txt') 34 | 35 | -------------------------------------------------------------------------------- /cookbook/c05/p16_change_opencode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 增加/修改已打开文件的编码 5 | Desc : 6 | """ 7 | import urllib.request 8 | import io 9 | import sys 10 | 11 | 12 | def change_open_encode(): 13 | u = urllib.request.urlopen('http://www.python.org') 14 | f = io.TextIOWrapper(u, encoding='utf-8') 15 | text = f.read() 16 | 17 | print(sys.stdout.encoding) 18 | sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1') 19 | print(sys.stdout.encoding) 20 | 21 | f = open('sample.txt','w') 22 | print(f) 23 | print(f.buffer) 24 | print(f.buffer.raw) 25 | 26 | 27 | if __name__ == '__main__': 28 | change_open_encode() 29 | -------------------------------------------------------------------------------- /cookbook/c05/p17_bytes_tofile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 在文本模式文件中写入字节 5 | Desc : 6 | """ 7 | import sys 8 | 9 | 10 | def bytes_tofile(): 11 | sys.stdout.buffer.write(b'Hello\n') 12 | 13 | if __name__ == '__main__': 14 | bytes_tofile() 15 | 16 | -------------------------------------------------------------------------------- /cookbook/c05/p18_file_descriptor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 文件描述符到文件的转换 5 | Desc : 6 | """ 7 | import os 8 | import sys 9 | from socket import socket, AF_INET, SOCK_STREAM 10 | 11 | 12 | def file_descriptor(): 13 | fd = os.open('somefile.txt', os.O_WRONLY | os.O_CREAT) 14 | 15 | # Turn into a proper file 16 | f = open(fd, 'wt') 17 | f.write('hello world\n') 18 | f.close() 19 | 20 | # Create a binary-mode file for stdout 21 | bstdout = open(sys.stdout.fileno(), 'wb', closefd=False) 22 | bstdout.write(b'Hello World\n') 23 | bstdout.flush() 24 | 25 | 26 | def echo_client(client_sock, addr): 27 | print('Got connection from', addr) 28 | 29 | # Make text-mode file wrappers for socket reading/writing 30 | client_in = open(client_sock.fileno(), 'rt', encoding='latin-1', 31 | closefd=False) 32 | 33 | client_out = open(client_sock.fileno(), 'wt', encoding='latin-1', 34 | closefd=False) 35 | 36 | # Echo lines back to the client using file I/O 37 | for line in client_in: 38 | client_out.write(line) 39 | client_out.flush() 40 | 41 | client_sock.close() 42 | 43 | 44 | def echo_server(address): 45 | sock = socket(AF_INET, SOCK_STREAM) 46 | sock.bind(address) 47 | sock.listen(1) 48 | while True: 49 | client, addr = sock.accept() 50 | echo_client(client, addr) 51 | 52 | if __name__ == '__main__': 53 | file_descriptor() 54 | 55 | 56 | -------------------------------------------------------------------------------- /cookbook/c05/p19_temp_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 临时文件和目录 5 | Desc : 6 | """ 7 | from tempfile import TemporaryFile 8 | from tempfile import TemporaryDirectory 9 | from tempfile import NamedTemporaryFile 10 | import tempfile 11 | 12 | 13 | def temp_file(): 14 | with TemporaryFile('w+t') as f: 15 | # Read/write to the file 16 | f.write('Hello World\n') 17 | f.write('Testing\n') 18 | 19 | # Seek back to beginning and read the data 20 | f.seek(0) 21 | data = f.read() 22 | print(data) 23 | 24 | with NamedTemporaryFile('w+t') as f: 25 | print('filename is:', f.name) 26 | 27 | with TemporaryDirectory() as dirname: 28 | print('dirname is:', dirname) 29 | 30 | print(tempfile.mkstemp()) 31 | print(tempfile.mkdtemp()) 32 | print(tempfile.gettempdir()) 33 | 34 | if __name__ == '__main__': 35 | temp_file() 36 | 37 | -------------------------------------------------------------------------------- /cookbook/c05/p20_serial_ports.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 串行端口数据交换 5 | Desc : 6 | """ 7 | import serial 8 | 9 | 10 | def serial_posts(): 11 | ser = serial.Serial('/dev/tty.usbmodem641', # Device name varies 12 | baudrate=9600, 13 | bytesize=8, 14 | parity='N', 15 | stopbits=1) 16 | 17 | 18 | if __name__ == '__main__': 19 | serial_posts() 20 | 21 | -------------------------------------------------------------------------------- /cookbook/c05/p21_serialize_object.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 序列化一个对象 5 | Desc : 6 | """ 7 | import pickle 8 | 9 | 10 | def serailize_object(): 11 | data = [1, 2, 3] 12 | f = open('somefile', 'wb') 13 | pickle.dump(data, f) 14 | 15 | # 将对象转储为字符串 16 | s = pickle.dumps(data) 17 | 18 | # Restore from a file 19 | f = open('somefile', 'rb') 20 | data = pickle.load(f) 21 | 22 | # Restore from a string 23 | data = pickle.loads(s) 24 | 25 | f = open('somedata', 'wb') 26 | pickle.dump([1, 2, 3, 4], f) 27 | pickle.dump('hello', f) 28 | pickle.dump({'Apple', 'Pear', 'Banana'}, f) 29 | f.close() 30 | 31 | f = open('somedata', 'rb') 32 | print(pickle.load(f)) 33 | print(pickle.load(f)) 34 | print(pickle.load(f)) 35 | 36 | if __name__ == '__main__': 37 | serailize_object() 38 | -------------------------------------------------------------------------------- /cookbook/c06/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c06/data.json: -------------------------------------------------------------------------------- 1 | {"name": "ACME", "shares": 100, "price": 542.23} -------------------------------------------------------------------------------- /cookbook/c06/p01_rw_csv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 读写CSV数据 5 | Desc : 6 | """ 7 | import csv 8 | from collections import namedtuple 9 | 10 | 11 | def rw_csv(): 12 | with open('stocks.csv') as f: 13 | f_csv = csv.reader(f) 14 | headers = next(f_csv) 15 | for row in f_csv: 16 | print(row) 17 | 18 | with open('stocks.csv') as f: 19 | f_csv = csv.reader(f) 20 | headings = next(f_csv) 21 | Row = namedtuple('Row', headings) 22 | for r in f_csv: 23 | row = Row(*r) 24 | # Process row 25 | print(row.Change) 26 | 27 | headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume'] 28 | rows = [('AA', 39.48, '6/11/2007', '9:36am', -0.18, 181800), 29 | ('AIG', 71.38, '6/11/2007', '9:36am', -0.15, 195500), 30 | ('AXP', 62.58, '6/11/2007', '9:36am', -0.46, 935000), 31 | ] 32 | 33 | with open('stocks.csv', 'w') as f: 34 | f_csv = csv.writer(f) 35 | f_csv.writerow(headers) 36 | f_csv.writerows(rows) 37 | 38 | 39 | if __name__ == '__main__': 40 | rw_csv() 41 | 42 | -------------------------------------------------------------------------------- /cookbook/c06/p03_simple_xml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 解析简单的XML 5 | Desc : 6 | """ 7 | from urllib.request import urlopen 8 | from xml.etree.ElementTree import parse 9 | 10 | 11 | def simple_xml(): 12 | # Download the RSS feed and parse it 13 | u = urlopen('http://planet.python.org/rss20.xml') 14 | doc = parse(u) 15 | 16 | # Extract and output tags of interest 17 | for item in doc.iterfind('channel/item'): 18 | title = item.findtext('title') 19 | date = item.findtext('pubDate') 20 | link = item.findtext('link') 21 | 22 | print(title) 23 | print(date) 24 | print(link) 25 | print() 26 | 27 | if __name__ == '__main__': 28 | simple_xml() 29 | 30 | -------------------------------------------------------------------------------- /cookbook/c06/p04_huge_xml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 增量式的处理大型XML文档 5 | Desc : 6 | """ 7 | from xml.etree.ElementTree import iterparse 8 | from xml.etree.ElementTree import parse 9 | from collections import Counter 10 | 11 | 12 | def parse_and_remove(filename, path): 13 | path_parts = path.split('/') 14 | doc = iterparse(filename, ('start', 'end')) 15 | # Skip the root element 16 | next(doc) 17 | 18 | tag_stack = [] 19 | elem_stack = [] 20 | for event, elem in doc: 21 | if event == 'start': 22 | tag_stack.append(elem.tag) 23 | elem_stack.append(elem) 24 | elif event == 'end': 25 | if tag_stack == path_parts: 26 | yield elem 27 | elem_stack[-2].remove(elem) 28 | try: 29 | tag_stack.pop() 30 | elem_stack.pop() 31 | except IndexError: 32 | pass 33 | 34 | 35 | def huge_xml(): 36 | potholes_by_zip = Counter() 37 | 38 | doc = parse('potholes.xml') 39 | for pothole in doc.iterfind('row/row'): 40 | potholes_by_zip[pothole.findtext('zip')] += 1 41 | for zipcode, num in potholes_by_zip.most_common(): 42 | print(zipcode, num) 43 | 44 | 45 | potholes_by_zip = Counter() 46 | 47 | data = parse_and_remove('potholes.xml', 'row/row') 48 | for pothole in data: 49 | potholes_by_zip[pothole.findtext('zip')] += 1 50 | for zipcode, num in potholes_by_zip.most_common(): 51 | print(zipcode, num) 52 | 53 | if __name__ == '__main__': 54 | huge_xml() 55 | 56 | -------------------------------------------------------------------------------- /cookbook/c06/p05_dict_toxml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 字典转换成XML格式 5 | Desc : 6 | """ 7 | from xml.etree.ElementTree import Element 8 | from xml.etree.ElementTree import tostring 9 | 10 | 11 | def dict_to_xml(tag, d): 12 | """ 13 | Turn a simple dict of key/value pairs into XML 14 | """ 15 | elem = Element(tag) 16 | for key, val in d.items(): 17 | child = Element(key) 18 | child.text = str(val) 19 | elem.append(child) 20 | return elem 21 | 22 | if __name__ == '__main__': 23 | r = dict_to_xml('root', {'1':'22', '3':'444'}) 24 | print(r) 25 | print(tostring(r)) 26 | r.set('_id','1234') 27 | print(tostring(r)) 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /cookbook/c06/p06_rw_xml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 读取修改某个XML文档 5 | Desc : 6 | """ 7 | from xml.etree.ElementTree import parse, Element 8 | 9 | 10 | def rw_xml(): 11 | doc = parse('pred.xml') 12 | root = doc.getroot() 13 | # Remove a few elements 14 | root.remove(root.find('sri')) 15 | root.remove(root.find('cr')) 16 | # Insert a new element after ... 17 | root.getchildren().index(root.find('nm')) 18 | 19 | e = Element('spam') 20 | e.text = 'This is a test' 21 | root.insert(2, e) 22 | # Write back to a file 23 | doc.write('newpred.xml', xml_declaration=True) 24 | 25 | 26 | 27 | if __name__ == '__main__': 28 | rw_xml() 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /cookbook/c06/p07_namespace_xml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 处理含命名空间的XML文档 5 | Desc : 6 | """ 7 | 8 | 9 | class XMLNamespaces: 10 | def __init__(self, **kwargs): 11 | self.namespaces = {} 12 | for name, uri in kwargs.items(): 13 | self.register(name, uri) 14 | 15 | def register(self, name, uri): 16 | self.namespaces[name] = '{' + uri + '}' 17 | 18 | def __call__(self, path): 19 | return path.format_map(self.namespaces) 20 | 21 | 22 | if __name__ == '__main__': 23 | ns = XMLNamespaces(html='http://www.w3.org/1999/xhtml') 24 | # doc.find(ns('content/{html}html')) 25 | # doc.findtext(ns('content/{html}html/{html}head/{html}title')) -------------------------------------------------------------------------------- /cookbook/c06/p08_database.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 关系型数据库处理 5 | Desc : 6 | """ 7 | import sqlite3 8 | import datetime.time 9 | 10 | 11 | def db_operation(): 12 | db = sqlite3.connect('database.db') 13 | c = db.cursor() 14 | c.execute('create table portfolio (symbol text, shares integer, price real)') 15 | db.commit() 16 | 17 | stocks = [ 18 | ('GOOG', 100, 490.1), 19 | ('AAPL', 50, 545.75), 20 | ('FB', 150, 7.45), 21 | ('HPQ', 75, 33.2), 22 | ] 23 | c.executemany('insert into portfolio values (?,?,?)', stocks) 24 | db.commit() 25 | 26 | for row in db.execute('select * from portfolio'): 27 | print(row) 28 | 29 | min_price = 12 30 | for row in db.execute('select * from portfolio where price >= ?', (min_price,)): 31 | print(row) 32 | 33 | if __name__ == '__main__': 34 | db_operation() 35 | 36 | -------------------------------------------------------------------------------- /cookbook/c06/p09_codec_hex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 编码/解码十六进制原始字符串 5 | Desc : 6 | """ 7 | import binascii 8 | import base64 9 | 10 | 11 | def codec_hex(): 12 | s = b'hello' 13 | # Encode as hex 14 | h = binascii.b2a_hex(s) 15 | print(h) 16 | # Decode back to bytes 17 | h = binascii.a2b_hex(h) 18 | print(h) 19 | 20 | # 使用base64模块也可以 21 | h = base64.b16encode(s) 22 | print(h) 23 | print(h.decode('ascii')) 24 | h = base64.b16decode(h) 25 | print(h) 26 | print(h.decode('ascii')) 27 | 28 | 29 | if __name__ == '__main__': 30 | codec_hex() 31 | -------------------------------------------------------------------------------- /cookbook/c06/p10_codec_base64.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 编码/解码Base64 5 | Desc : 6 | """ 7 | import base64 8 | 9 | 10 | def codec_base64(): 11 | s = b'hello' 12 | 13 | # Encode as Base64 14 | a = base64.b64encode(s) 15 | print(a) 16 | 17 | # Decode from Base64 18 | b = base64.b64decode(a) 19 | print(b) 20 | 21 | if __name__ == '__main__': 22 | codec_base64() 23 | 24 | 25 | -------------------------------------------------------------------------------- /cookbook/c06/pred.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14791 4 | Clark & Balmoral 5 | 6 | 22 7 | North Bound 8 |
North Bound
9 |
10 | 22 11 |
12 |         5 MIN
13 |         Howard
14 |         1378
15 |         22
16 |     
17 |
18 |         15 MIN
19 |         Howard
20 |         1867
21 |         22
22 |     
23 |
-------------------------------------------------------------------------------- /cookbook/c06/stocks.csv: -------------------------------------------------------------------------------- 1 | Symbol,Price,Date,Time,Change,Volume 2 | AA,39.48,6/11/2007,9:36am,-0.18,181800 3 | AIG,71.38,6/11/2007,9:36am,-0.15,195500 4 | AXP,62.58,6/11/2007,9:36am,-0.46,935000 5 | -------------------------------------------------------------------------------- /cookbook/c07/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c07/p02_keyarg_only.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 只允许关键字形式的参数 5 | Desc : 6 | """ 7 | 8 | 9 | def recv(maxsize, *, block): 10 | 'Receives a message' 11 | pass 12 | 13 | # recv(1024, True) # TypeError 14 | recv(1024, block=True) # Ok 15 | 16 | 17 | def minimum(*values, clip=None): 18 | m = min(values) 19 | if clip is not None: 20 | m = clip if clip > m else m 21 | return m 22 | 23 | 24 | minimum(1, 5, 2, -5, 10) # Returns -5 25 | minimum(1, 5, 2, -5, 10, clip=0) # Returns 0 -------------------------------------------------------------------------------- /cookbook/c07/p03_func_annotate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 函数注解元信息 5 | Desc : 6 | """ 7 | 8 | def add(x:int, y:int) -> int: 9 | return x + y 10 | 11 | help(add) 12 | 13 | print(add.__annotations__) 14 | 15 | -------------------------------------------------------------------------------- /cookbook/c07/p05_default_argument.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 函数默认参数 5 | Desc : 6 | """ 7 | 8 | def spam(a, b=42): 9 | print(a, b) 10 | 11 | spam(1) # Ok. a=1, b=42 12 | spam(1, 2) # Ok. a=1, b=2 13 | 14 | _no_value = object() 15 | 16 | def spam(a, b=_no_value): 17 | if b is _no_value: 18 | print('No b value supplied') 19 | 20 | -------------------------------------------------------------------------------- /cookbook/c07/p06_anony_func.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 匿名函数lambda表达式 5 | Desc : 6 | """ 7 | 8 | add = lambda x, y: x + y 9 | print(add(2,3)) 10 | -------------------------------------------------------------------------------- /cookbook/c07/p08_partial.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 使用partial函数来减少参数个数 5 | Desc : 6 | """ 7 | import logging 8 | from multiprocessing import Pool 9 | from functools import partial 10 | from socketserver import StreamRequestHandler, TCPServer 11 | 12 | 13 | def spam(a, b, c, d): 14 | print(a, b, c, d) 15 | 16 | 17 | def output_result(result, log=None): 18 | if log is not None: 19 | log.debug('Got: %r', result) 20 | 21 | 22 | # A sample function 23 | def add(x, y): 24 | return x + y 25 | 26 | 27 | class EchoHandler(StreamRequestHandler): 28 | # ack is added keyword-only argument. *args, **kwargs are 29 | # any normal parameters supplied (which are passed on) 30 | def __init__(self, *args, ack, **kwargs): 31 | self.ack = ack 32 | super().__init__(*args, **kwargs) 33 | 34 | def handle(self): 35 | for line in self.rfile: 36 | self.wfile.write(self.ack + line) 37 | 38 | if __name__ == '__main__': 39 | s1 = partial(spam, 1) # a = 1 40 | s1(2, 3, 4) 41 | s1(4, 5, 6) 42 | s2 = partial(spam, d=42) # d = 42 43 | s2(1, 2, 3) 44 | s2(4, 5, 5) 45 | s3 = partial(spam, 1, 2, d=42) # a = 1, b = 2, d = 42 46 | s3(3) 47 | s3(4) 48 | 49 | logging.basicConfig(level=logging.DEBUG) 50 | log = logging.getLogger('test') 51 | 52 | p = Pool() 53 | p.apply_async(add, (3, 4), callback=partial(output_result, log=log)) 54 | p.close() 55 | p.join() 56 | 57 | # socket服务器 58 | serv = TCPServer(('', 15000), partial(EchoHandler, ack=b'RECEIVED:')) 59 | serv.serve_forever() 60 | 61 | -------------------------------------------------------------------------------- /cookbook/c07/p09_class_to_func.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 单方法类转换为函数 5 | Desc : 6 | """ 7 | 8 | from urllib.request import urlopen 9 | 10 | 11 | class UrlTemplate: 12 | def __init__(self, template): 13 | self.template = template 14 | 15 | def open(self, **kwargs): 16 | return urlopen(self.template.format_map(kwargs)) 17 | 18 | # Example use. Download stock data from yahoo 19 | yahoo = UrlTemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}') 20 | for line in yahoo.open(names='IBM,AAPL,FB', fields='sl1c1v'): 21 | print(line.decode('utf-8')) 22 | 23 | 24 | # =======================闭包方案================= 25 | def urltemplate(template): 26 | def opener(**kwargs): 27 | return urlopen(template.format_map(kwargs)) 28 | return opener 29 | 30 | # Example use 31 | yahoo = urltemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}') 32 | for line in yahoo(names='IBM,AAPL,FB', fields='sl1c1v'): 33 | print(line.decode('utf-8')) 34 | -------------------------------------------------------------------------------- /cookbook/c07/p10_callback.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 带状态值的回调函数 5 | Desc : 6 | """ 7 | 8 | 9 | def apply_async(func, args, *, callback): 10 | # Compute the result 11 | result = func(*args) 12 | 13 | # Invoke the callback with the result 14 | callback(result) 15 | 16 | 17 | def add(x, y): 18 | return x + y 19 | 20 | 21 | # 类方案 22 | class ResultHandler: 23 | 24 | def __init__(self): 25 | self.sequence = 0 26 | 27 | def handler(self, result): 28 | self.sequence += 1 29 | print('[{}] Got: {}'.format(self.sequence, result)) 30 | 31 | r = ResultHandler() 32 | apply_async(add, (2, 3), callback=r.handler) 33 | apply_async(add, ('hello', 'world'), callback=r.handler) 34 | 35 | 36 | # 闭包方案 37 | def make_handler(): 38 | sequence = 0 39 | def handler(result): 40 | nonlocal sequence 41 | sequence += 1 42 | print('[{}] Got: {}'.format(sequence, result)) 43 | return handler 44 | 45 | handler = make_handler() 46 | apply_async(add, (2, 3), callback=handler) 47 | apply_async(add, ('hello', 'world'), callback=handler) 48 | 49 | 50 | # 协程方案 51 | def make_handler(): 52 | sequence = 0 53 | while True: 54 | result = yield 55 | sequence += 1 56 | print('[{}] Got: {}'.format(sequence, result)) 57 | 58 | handler = make_handler() 59 | next(handler) # Advance to the yield 60 | apply_async(add, (2, 3), callback=handler.send) 61 | apply_async(add, ('hello', 'world'), callback=handler.send) 62 | 63 | -------------------------------------------------------------------------------- /cookbook/c07/p12_closure_access.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 闭包访问函数内部变量 5 | Desc : 6 | """ 7 | 8 | 9 | def sample(): 10 | n = 0 11 | # Closure function 12 | def func(): 13 | print('n=', n) 14 | 15 | # Accessor methods for n 16 | def get_n(): 17 | return n 18 | 19 | def set_n(value): 20 | nonlocal n 21 | n = value 22 | 23 | # Attach as function attributes 24 | func.get_n = get_n 25 | func.set_n = set_n 26 | return func 27 | 28 | f = sample() 29 | f() 30 | f.set_n(10) 31 | f() 32 | 33 | import sys 34 | class ClosureInstance: 35 | def __init__(self, locals=None): 36 | if locals is None: 37 | locals = sys._getframe(1).f_locals 38 | 39 | # Update instance dictionary with callables 40 | self.__dict__.update((key,value) for key, value in locals.items() 41 | if callable(value) ) 42 | # Redirect special methods 43 | def __len__(self): 44 | return self.__dict__['__len__']() 45 | 46 | # Example use 47 | def Stack(): 48 | items = [] 49 | def push(item): 50 | items.append(item) 51 | 52 | def pop(): 53 | return items.pop() 54 | 55 | def __len__(): 56 | return len(items) 57 | 58 | return ClosureInstance() 59 | 60 | s = Stack() 61 | print(s) 62 | s.push(10) 63 | s.push(20) 64 | print(len(s)) 65 | print(s.pop()) 66 | print(s.pop()) 67 | -------------------------------------------------------------------------------- /cookbook/c08/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c08/p01_str_represent.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 实例的字符串显示 5 | Desc : 6 | """ 7 | 8 | 9 | class Pair: 10 | def __init__(self, x, y): 11 | self.x = x 12 | self.y = y 13 | 14 | def __repr__(self): 15 | return 'Pair({0.x!r}, {0.y!r})'.format(self) 16 | 17 | def __str__(self): 18 | return '({0.x!s}, {0.y!s})'.format(self) 19 | 20 | p = Pair(3, 4) 21 | print(p) 22 | 23 | 24 | -------------------------------------------------------------------------------- /cookbook/c08/p02_custom_format.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 对象自定义格式化 5 | Desc : 6 | """ 7 | _formats = { 8 | 'ymd': '{d.year}-{d.month}-{d.day}', 9 | 'mdy': '{d.month}/{d.day}/{d.year}', 10 | 'dmy': '{d.day}/{d.month}/{d.year}' 11 | } 12 | 13 | 14 | class Date: 15 | def __init__(self, year, month, day): 16 | self.year = year 17 | self.month = month 18 | self.day = day 19 | 20 | def __format__(self, code): 21 | if code == '': 22 | code = 'ymd' 23 | fmt = _formats[code] 24 | return fmt.format(d=self) 25 | 26 | 27 | d = Date(2012, 12, 21) 28 | print(d) 29 | print(format(d, 'mdy')) 30 | print('The date is {:ymd}'.format(d)) 31 | print('The date is {:mdy}'.format(d)) -------------------------------------------------------------------------------- /cookbook/c08/p04_slots.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 使用slots来减少内存占用 5 | Desc : 6 | """ 7 | 8 | 9 | class Date: 10 | __slots__ = ['year', 'month', 'day'] 11 | 12 | def __init__(self, year, month, day): 13 | self.year = year 14 | self.month = month 15 | self.day = day 16 | 17 | -------------------------------------------------------------------------------- /cookbook/c08/p05_encapsulate_name.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 隐藏私有属性 5 | Desc : 6 | """ 7 | 8 | 9 | class A: 10 | def __init__(self): 11 | self._internal = 0 # An internal attribute 12 | self.public = 1 # A public attribute 13 | 14 | def public_method(self): 15 | ''' 16 | A public method 17 | ''' 18 | pass 19 | 20 | def _internal_method(self): 21 | pass 22 | 23 | 24 | class B: 25 | def __init__(self): 26 | self.__private = 0 27 | 28 | def __private_method(self): 29 | pass 30 | 31 | def public_method(self): 32 | pass 33 | self.__private_method() 34 | 35 | 36 | class C(B): 37 | def __init__(self): 38 | super().__init__() 39 | self.__private = 1 # Does not override B.__private 40 | 41 | # Does not override B.__private_method() 42 | def __private_method(self): 43 | pass -------------------------------------------------------------------------------- /cookbook/c08/p10_lazy_property.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 延迟属性 5 | Desc : 6 | """ 7 | import math 8 | 9 | 10 | class lazyproperty: 11 | def __init__(self, func): 12 | self.func = func 13 | 14 | def __get__(self, instance, cls): 15 | if instance is None: 16 | return self 17 | else: 18 | value = self.func(instance) 19 | setattr(instance, self.func.__name__, value) 20 | return value 21 | 22 | 23 | class Circle: 24 | def __init__(self, radius): 25 | self.radius = radius 26 | 27 | @lazyproperty 28 | def area(self): 29 | print('Computing area') 30 | return math.pi * self.radius ** 2 31 | 32 | @lazyproperty 33 | def perimeter(self): 34 | print('Computing perimeter') 35 | return 2 * math.pi * self.radius 36 | 37 | c = Circle(4.0) 38 | print(vars(c)) 39 | print(c.area) 40 | print(vars(c)) 41 | del c.area 42 | print(vars(c)) 43 | print(c.area) 44 | 45 | 46 | def lazyproperty2(func): 47 | name = '_lazy_' + func.__name__ 48 | @property 49 | def lazy(self): 50 | if hasattr(self, name): 51 | return getattr(self, name) 52 | else: 53 | value = func(self) 54 | setattr(self, name, value) 55 | return value 56 | return lazy -------------------------------------------------------------------------------- /cookbook/c08/p12_abstract_interface.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 定义接口或抽象类 5 | Desc : 6 | """ 7 | from abc import ABCMeta, abstractmethod 8 | 9 | 10 | class IStream(metaclass=ABCMeta): 11 | @abstractmethod 12 | def read(self, maxbytes=-1): 13 | pass 14 | 15 | @abstractmethod 16 | def write(self, data): 17 | pass 18 | 19 | 20 | class SocketStream(IStream): 21 | def read(self, maxbytes=-1): 22 | pass 23 | 24 | def write(self, data): 25 | pass 26 | 27 | 28 | class A(metaclass=ABCMeta): 29 | @property 30 | @abstractmethod 31 | def name(self): 32 | pass 33 | 34 | @name.setter 35 | @abstractmethod 36 | def name(self, value): 37 | pass 38 | 39 | @classmethod 40 | @abstractmethod 41 | def method1(cls): 42 | pass 43 | 44 | @staticmethod 45 | @abstractmethod 46 | def method2(): 47 | pass 48 | 49 | -------------------------------------------------------------------------------- /cookbook/c08/p16_more_constructor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 定义类的多个构造函数 5 | Desc : 6 | """ 7 | 8 | import time 9 | 10 | 11 | class Date: 12 | """方法一:使用类方法""" 13 | # Primary constructor 14 | def __init__(self, year, month, day): 15 | self.year = year 16 | self.month = month 17 | self.day = day 18 | 19 | # Alternate constructor 20 | @classmethod 21 | def today(cls): 22 | t = time.localtime() 23 | return cls(t.tm_year, t.tm_mon, t.tm_mday) 24 | 25 | a = Date(2012, 12, 21) # Primary 26 | b = Date.today() # Alternate 27 | 28 | -------------------------------------------------------------------------------- /cookbook/c08/p17_without_init.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 不使用__init__方法初创建对象 5 | Desc : 6 | """ 7 | 8 | 9 | class Date: 10 | def __init__(self, year, month, day): 11 | self.year = year 12 | self.month = month 13 | self.day = day 14 | 15 | 16 | data = {'year': 2012, 'month': 8, 'day': 29} 17 | d = Date.__new__(Date) 18 | for key, value in data.items(): 19 | setattr(d, key, value) 20 | print(d.year, d.month, d.day) 21 | 22 | from time import localtime 23 | 24 | 25 | class Date: 26 | def __init__(self, year, month, day): 27 | self.year = year 28 | self.month = month 29 | self.day = day 30 | 31 | @classmethod 32 | def today(cls): 33 | d = cls.__new__(cls) 34 | t = localtime() 35 | d.year = t.tm_year 36 | d.month = t.tm_mon 37 | d.day = t.tm_mday 38 | return d -------------------------------------------------------------------------------- /cookbook/c08/p20_invoke_bystr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 通过字符串调用方法 5 | Desc : 6 | """ 7 | 8 | import math 9 | 10 | 11 | class Point: 12 | def __init__(self, x, y): 13 | self.x = x 14 | self.y = y 15 | 16 | def __repr__(self): 17 | # !r表示调用后面参数的__repr__()方法 18 | return 'Point({!r:},{!r:})'.format(self.x, self.y) 19 | 20 | def distance(self, x, y): 21 | return math.hypot(self.x - x, self.y - y) 22 | 23 | 24 | p = Point(2, 3) 25 | d = getattr(p, 'distance')(0, 0) # Calls p.distance(0, 0) 26 | 27 | import operator 28 | 29 | operator.methodcaller('distance', 0, 0)(p) 30 | 31 | points = [ 32 | Point(1, 2), 33 | Point(3, 0), 34 | Point(10, -3), 35 | Point(-5, -7), 36 | Point(-1, 8), 37 | Point(3, 2) 38 | ] 39 | # Sort by distance from origin (0, 0) 40 | points.sort(key=operator.methodcaller('distance', 0, 0)) 41 | -------------------------------------------------------------------------------- /cookbook/c08/p23_weakref.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 弱引用 5 | Desc : 6 | """ 7 | 8 | import weakref 9 | 10 | 11 | class Node: 12 | def __init__(self, value): 13 | self.value = value 14 | self._parent = None 15 | self.children = [] 16 | 17 | def __repr__(self): 18 | return 'Node({!r:})'.format(self.value) 19 | 20 | # property that manages the parent as a weak-reference 21 | @property 22 | def parent(self): 23 | return None if self._parent is None else self._parent() 24 | 25 | @parent.setter 26 | def parent(self, node): 27 | self._parent = weakref.ref(node) 28 | 29 | def add_child(self, child): 30 | self.children.append(child) 31 | child.parent = self 32 | 33 | 34 | # Class just to illustrate when deletion occurs 35 | class Data: 36 | def __del__(self): 37 | print('Data.__del__') 38 | 39 | 40 | # Node class involving a cycle 41 | class Node1: 42 | def __init__(self): 43 | self.data = Data() 44 | self.parent = None 45 | self.children = [] 46 | 47 | def add_child(self, child): 48 | self.children.append(child) 49 | child.parent = self 50 | 51 | 52 | a = Data() 53 | del a 54 | # print(a) NameError: name 'a' is not defined 55 | a = Node1() 56 | del a 57 | # print(a) 58 | a = Node1() 59 | a.add_child(Node1()) 60 | print('--------last del start------------') 61 | del a # Not deleted (no message) 62 | print('--------last del end------------') 63 | # print(a) 64 | print('11111111111111111') 65 | -------------------------------------------------------------------------------- /cookbook/c09/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c09/p01_wrap_function.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 包装函数 5 | Desc : 6 | """ 7 | 8 | import time 9 | from functools import wraps 10 | 11 | 12 | def timethis(func): 13 | ''' 14 | Decorator that reports the execution time. 15 | ''' 16 | @wraps(func) 17 | def wrapper(*args, **kwargs): 18 | start = time.time() 19 | result = func(*args, **kwargs) 20 | end = time.time() 21 | print(func.__name__, end-start) 22 | return result 23 | return wrapper 24 | 25 | @timethis 26 | def countdown(n): 27 | """ 28 | Counts down 29 | """ 30 | while n > 0: 31 | n -= 1 32 | countdown(100000) 33 | countdown(10000000) -------------------------------------------------------------------------------- /cookbook/c09/p02_preserve_metadata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 创建装饰器时保留函数元信息 5 | Desc : 6 | """ 7 | 8 | import time 9 | from functools import wraps 10 | 11 | 12 | def timethis(func): 13 | """ 14 | Decorator that reports the execution time. 15 | """ 16 | 17 | @wraps(func) 18 | def wrapper(*args, **kwargs): 19 | start = time.time() 20 | result = func(*args, **kwargs) 21 | end = time.time() 22 | print(func.__name__, end - start) 23 | return result 24 | 25 | return wrapper 26 | 27 | 28 | @timethis 29 | def countdown(n: int): 30 | """ 31 | Counts down 32 | """ 33 | while n > 0: 34 | n -= 1 35 | 36 | 37 | print(countdown.__name__) 38 | print(countdown.__doc__) 39 | print(countdown.__annotations__) 40 | from inspect import signature 41 | 42 | print(signature(countdown)) -------------------------------------------------------------------------------- /cookbook/c09/p03_unwrap_decorator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 解除包装器 5 | Desc : 6 | """ 7 | 8 | from functools import wraps 9 | 10 | 11 | def decorator1(func): 12 | @wraps(func) 13 | def wrapper(*args, **kwargs): 14 | print('Decorator 1') 15 | return func(*args, **kwargs) 16 | return wrapper 17 | 18 | 19 | def decorator2(func): 20 | @wraps(func) 21 | def wrapper(*args, **kwargs): 22 | print('Decorator 2') 23 | return func(*args, **kwargs) 24 | return wrapper 25 | 26 | 27 | @decorator1 28 | @decorator2 29 | def add(x, y): 30 | return x + y 31 | 32 | add(1, 2) 33 | print('-----------------') 34 | print(add.__wrapped__(2, 3)) -------------------------------------------------------------------------------- /cookbook/c09/p04_decorator_argument.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 带有参数的装饰器 5 | Desc : 6 | """ 7 | 8 | from functools import wraps 9 | import logging 10 | 11 | 12 | def logged(level, name=None, message=None): 13 | """ 14 | Add logging to a function. level is the logging 15 | level, name is the logger name, and message is the 16 | log message. If name and message aren't specified, 17 | they default to the function's module and name. 18 | """ 19 | 20 | def decorate(func): 21 | logname = name if name else func.__module__ 22 | log = logging.getLogger(logname) 23 | logmsg = message if message else func.__name__ 24 | 25 | @wraps(func) 26 | def wrapper(*args, **kwargs): 27 | log.log(level, logmsg) 28 | return func(*args, **kwargs) 29 | 30 | return wrapper 31 | 32 | return decorate 33 | 34 | 35 | # Example use 36 | @logged(logging.DEBUG) 37 | def add(x, y): 38 | return x + y 39 | 40 | 41 | @logged(logging.CRITICAL, 'example') 42 | def spam(): 43 | print('Spam!') 44 | 45 | -------------------------------------------------------------------------------- /cookbook/c09/p06_optarg_decorator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 带可选参数的装饰器 5 | Desc : 6 | """ 7 | from functools import wraps, partial 8 | import logging 9 | 10 | 11 | def logged(func=None, *, level=logging.DEBUG, name=None, message=None): 12 | if func is None: 13 | return partial(logged, level=level, name=name, message=message) 14 | 15 | logname = name if name else func.__module__ 16 | log = logging.getLogger(logname) 17 | logmsg = message if message else func.__name__ 18 | 19 | @wraps(func) 20 | def wrapper(*args, **kwargs): 21 | log.log(level, logmsg) 22 | return func(*args, **kwargs) 23 | 24 | return wrapper 25 | 26 | 27 | # Example use 28 | @logged 29 | def add(x, y): 30 | return x + y 31 | 32 | 33 | @logged(level=logging.CRITICAL, name='example') 34 | def spam(): 35 | print('Spam!') 36 | 37 | spam() 38 | 39 | 40 | def aa(kk=None, *, a=1,b=2,c=3): 41 | print(kk, a, b, c) 42 | bbb = partial(aa, a=1,b=2,c=3) 43 | bbb('333') -------------------------------------------------------------------------------- /cookbook/c09/p07_typecheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 函数参数强制类型检查 5 | Desc : 6 | """ 7 | 8 | from inspect import signature 9 | from functools import wraps 10 | 11 | 12 | def typeassert(*ty_args, **ty_kwargs): 13 | def decorate(func): 14 | # If in optimized mode, disable type checking 15 | if not __debug__: 16 | return func 17 | 18 | # Map function argument names to supplied types 19 | sig = signature(func) 20 | bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments 21 | 22 | @wraps(func) 23 | def wrapper(*args, **kwargs): 24 | bound_values = sig.bind(*args, **kwargs) 25 | # Enforce type assertions across supplied arguments 26 | for name, value in bound_values.arguments.items(): 27 | if name in bound_types: 28 | if not isinstance(value, bound_types[name]): 29 | raise TypeError( 30 | 'Argument {} must be {}'.format(name, bound_types[name])) 31 | return func(*args, **kwargs) 32 | 33 | return wrapper 34 | 35 | return decorate 36 | 37 | 38 | @typeassert(int, int) 39 | def add(x, y): 40 | return x + y 41 | 42 | 43 | add(2, 3) 44 | # add(2, '22') 45 | 46 | 47 | @typeassert(int, list) 48 | def bar(x, items=None): 49 | if items is None: 50 | items = [] 51 | items.append(x) 52 | return items 53 | 54 | 55 | bar(2) 56 | bar(2, [1, 2, 3]) -------------------------------------------------------------------------------- /cookbook/c09/p08_inclass_decorator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 类中定义装饰器 5 | Desc : 6 | """ 7 | 8 | from functools import wraps 9 | 10 | class A: 11 | # Decorator as an instance method 12 | def decorator1(self, func): 13 | @wraps(func) 14 | def wrapper(*args, **kwargs): 15 | print('Decorator 1') 16 | return func(*args, **kwargs) 17 | return wrapper 18 | 19 | # Decorator as a class method 20 | @classmethod 21 | def decorator2(cls, func): 22 | @wraps(func) 23 | def wrapper(*args, **kwargs): 24 | print('Decorator 2') 25 | return func(*args, **kwargs) 26 | return wrapper 27 | 28 | class Person: 29 | # Create a property instance 30 | first_name = property() 31 | 32 | # Apply decorator methods 33 | @first_name.getter 34 | def first_name(self): 35 | return self._first_name 36 | 37 | @first_name.setter 38 | def first_name(self, value): 39 | if not isinstance(value, str): 40 | raise TypeError('Expected a string') 41 | self._first_name = value -------------------------------------------------------------------------------- /cookbook/c09/p09_class_decorator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 将装饰器定义成类 5 | Desc : 6 | """ 7 | 8 | import types 9 | from functools import wraps 10 | 11 | class Profiled: 12 | def __init__(self, func): 13 | wraps(func)(self) 14 | self.ncalls = 0 15 | 16 | def __call__(self, *args, **kwargs): 17 | self.ncalls += 1 18 | return self.__wrapped__(*args, **kwargs) 19 | 20 | def __get__(self, instance, cls): 21 | if instance is None: 22 | return self 23 | else: 24 | return types.MethodType(self, instance) 25 | 26 | @Profiled 27 | def add(x, y): 28 | return x + y 29 | 30 | class Spam: 31 | @Profiled 32 | def bar(self, x): 33 | print(self, x) 34 | 35 | Spam().bar(3) 36 | 37 | 38 | import types 39 | from functools import wraps 40 | 41 | def profiled(func): 42 | ncalls = 0 43 | @wraps(func) 44 | def wrapper(*args, **kwargs): 45 | nonlocal ncalls 46 | ncalls += 1 47 | return func(*args, **kwargs) 48 | wrapper.ncalls = lambda: ncalls 49 | return wrapper 50 | 51 | # Example 52 | @profiled 53 | def add(x, y): 54 | return x + y 55 | 56 | -------------------------------------------------------------------------------- /cookbook/c09/p10_static_decorator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | import time 9 | from functools import wraps 10 | 11 | # A simple decorator 12 | def timethis(func): 13 | @wraps(func) 14 | def wrapper(*args, **kwargs): 15 | start = time.time() 16 | r = func(*args, **kwargs) 17 | end = time.time() 18 | print(end-start) 19 | return r 20 | return wrapper 21 | 22 | # Class illustrating application of the decorator to different kinds of methods 23 | class Spam: 24 | @timethis 25 | def instance_method(self, n): 26 | print(self, n) 27 | while n > 0: 28 | n -= 1 29 | 30 | @classmethod 31 | @timethis 32 | def class_method(cls, n): 33 | print(cls, n) 34 | while n > 0: 35 | n -= 1 36 | 37 | @staticmethod 38 | @timethis 39 | def static_method(n): 40 | print(n) 41 | while n > 0: 42 | n -= 1 43 | 44 | from abc import ABCMeta, abstractmethod 45 | class A(metaclass=ABCMeta): 46 | @classmethod 47 | @abstractmethod 48 | def method(cls): 49 | pass 50 | -------------------------------------------------------------------------------- /cookbook/c09/p12_patch_class.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 使用类装饰器来增强类功能 5 | Desc : 6 | """ 7 | 8 | 9 | def log_getattribute(cls): 10 | # Get the original implementation 11 | orig_getattribute = cls.__getattribute__ 12 | 13 | # Make a new definition 14 | def new_getattribute(self, name): 15 | print('getting:', name) 16 | return orig_getattribute(self, name) 17 | 18 | # Attach to the class and return 19 | cls.__getattribute__ = new_getattribute 20 | return cls 21 | 22 | 23 | # Example use 24 | @log_getattribute 25 | class A: 26 | def __init__(self, x): 27 | self.x = x 28 | 29 | def spam(self): 30 | pass 31 | 32 | -------------------------------------------------------------------------------- /cookbook/c09/p13_instance_create.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 通过元类控制实例的创建 5 | Desc : 6 | """ 7 | 8 | 9 | class NoInstances(type): 10 | def __call__(self, *args, **kwargs): 11 | raise TypeError("Can't instantiate directly") 12 | 13 | 14 | # Example 15 | class Spam(metaclass=NoInstances): 16 | @staticmethod 17 | def grok(x): 18 | print('Spam.grok') 19 | 20 | 21 | class Singleton(type): 22 | def __init__(self, *args, **kwargs): 23 | self.__instance = None 24 | super().__init__(*args, **kwargs) 25 | 26 | def __call__(self, *args, **kwargs): 27 | if self.__instance is None: 28 | self.__instance = super().__call__(*args, **kwargs) 29 | return self.__instance 30 | else: 31 | return self.__instance 32 | 33 | 34 | # Example 35 | class Spam1(metaclass=Singleton): 36 | def __init__(self): 37 | print('Creating Spam') 38 | 39 | 40 | import weakref 41 | 42 | 43 | class Cached(type): 44 | def __init__(self, *args, **kwargs): 45 | super().__init__(*args, **kwargs) 46 | self.__cache = weakref.WeakValueDictionary() 47 | 48 | def __call__(self, *args): 49 | if args in self.__cache: 50 | return self.__cache[args] 51 | else: 52 | obj = super().__call__(*args) 53 | self.__cache[args] = obj 54 | return obj 55 | 56 | 57 | # Example 58 | class Spam2(metaclass=Cached): 59 | def __init__(self, name): 60 | print('Creating Spam({!r})'.format(name)) 61 | self.name = name 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /cookbook/c09/p15_meta_optional_arg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 元类中的可选参数 5 | Desc : 6 | """ 7 | 8 | from abc import ABCMeta, abstractmethod 9 | 10 | class IStream(metaclass=ABCMeta): 11 | @abstractmethod 12 | def read(self, maxsize=None): 13 | pass 14 | 15 | @abstractmethod 16 | def write(self, data): 17 | pass 18 | 19 | class MyMeta(type): 20 | # Optional 21 | @classmethod 22 | def __prepare__(cls, name, bases, *, debug=False, synchronize=False): 23 | # Custom processing 24 | pass 25 | return super().__prepare__(name, bases) 26 | 27 | # Required 28 | def __new__(cls, name, bases, ns, *, debug=False, synchronize=False): 29 | # Custom processing 30 | pass 31 | return super().__new__(cls, name, bases, ns) 32 | 33 | # Required 34 | def __init__(self, name, bases, ns, *, debug=False, synchronize=False): 35 | # Custom processing 36 | pass 37 | super().__init__(name, bases, ns) -------------------------------------------------------------------------------- /cookbook/c09/p18_define_classes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 以编程方式定义类 5 | Desc : 6 | """ 7 | 8 | # stock.py 9 | # Example of making a class manually from parts 10 | 11 | # Methods 12 | def __init__(self, name, shares, price): 13 | self.name = name 14 | self.shares = shares 15 | self.price = price 16 | 17 | 18 | def cost(self): 19 | return self.shares * self.price 20 | 21 | 22 | cls_dict = { 23 | '__init__': __init__, 24 | 'cost': cost, 25 | } 26 | 27 | # Make a class 28 | import types 29 | 30 | Stock = types.new_class('Stock', (), {}, lambda ns: ns.update(cls_dict)) 31 | Stock.__module__ = __name__ 32 | 33 | import operator 34 | import types 35 | import sys 36 | 37 | 38 | def named_tuple(classname, fieldnames): 39 | # Populate a dictionary of field property accessors 40 | cls_dict = {name: property(operator.itemgetter(n)) 41 | for n, name in enumerate(fieldnames)} 42 | 43 | # Make a __new__ function and add to the class dict 44 | def __new__(cls, *args): 45 | if len(args) != len(fieldnames): 46 | raise TypeError('Expected {} arguments'.format(len(fieldnames))) 47 | return tuple.__new__(cls, args) 48 | 49 | cls_dict['__new__'] = __new__ 50 | 51 | # Make the class 52 | cls = types.new_class(classname, (tuple,), {}, 53 | lambda ns: ns.update(cls_dict)) 54 | 55 | # Set the module to that of the caller 56 | cls.__module__ = sys._getframe(1).f_globals['__name__'] 57 | return cls 58 | -------------------------------------------------------------------------------- /cookbook/c09/p19_define_init.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 在定义的时候初始化类的成员 5 | Desc : 6 | """ 7 | 8 | import operator 9 | 10 | 11 | class StructTupleMeta(type): 12 | def __init__(cls, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | for n, name in enumerate(cls._fields): 15 | setattr(cls, name, property(operator.itemgetter(n))) 16 | 17 | 18 | class StructTuple(tuple, metaclass=StructTupleMeta): 19 | _fields = [] 20 | 21 | def __new__(cls, *args): 22 | if len(args) != len(cls._fields): 23 | raise ValueError('{} arguments required'.format(len(cls._fields))) 24 | return super().__new__(cls, args) 25 | 26 | 27 | class Stock(StructTuple): 28 | _fields = ['name', 'shares', 'price'] 29 | 30 | 31 | class Point(StructTuple): 32 | _fields = ['x', 'y'] -------------------------------------------------------------------------------- /cookbook/c09/p22_context_manager.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 定义上下文管理器的简单方法 5 | Desc : 6 | """ 7 | 8 | import time 9 | from contextlib import contextmanager 10 | 11 | @contextmanager 12 | def timethis(label): 13 | start = time.time() 14 | try: 15 | yield 16 | finally: 17 | end = time.time() 18 | print('{}: {}'.format(label, end - start)) 19 | 20 | # Example use 21 | with timethis('counting'): 22 | n = 10000000 23 | while n > 0: 24 | n -= 1 25 | 26 | @contextmanager 27 | def list_transaction(orig_list): 28 | working = list(orig_list) 29 | yield working 30 | orig_list[:] = working 31 | 32 | import time 33 | 34 | class timethis: 35 | def __init__(self, label): 36 | self.label = label 37 | 38 | def __enter__(self): 39 | self.start = time.time() 40 | 41 | def __exit__(self, exc_ty, exc_val, exc_tb): 42 | end = time.time() 43 | print('{}: {}'.format(self.label, end - self.start)) 44 | -------------------------------------------------------------------------------- /cookbook/c09/p23_local_side.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 在局部变量域中执行代码 5 | Desc : 6 | """ 7 | 8 | def test3(): 9 | x = 0 10 | loc = locals() 11 | print(loc) 12 | exec('x += 1') 13 | print(loc) 14 | locals() 15 | print(loc) 16 | 17 | 18 | def test4(): 19 | a = 13 20 | loc = {'a': a} 21 | glb = {} 22 | exec('b = a + 1', glb, loc) 23 | b = loc['b'] 24 | print(b) 25 | -------------------------------------------------------------------------------- /cookbook/c09/p25_disassemble_bytecode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 拆解Python字节码 5 | Desc : 6 | """ 7 | 8 | import opcode 9 | 10 | 11 | def generate_opcodes(codebytes): 12 | extended_arg = 0 13 | i = 0 14 | n = len(codebytes) 15 | while i < n: 16 | op = codebytes[i] 17 | i += 1 18 | if op >= opcode.HAVE_ARGUMENT: 19 | oparg = codebytes[i] + codebytes[i + 1] * 256 + extended_arg 20 | extended_arg = 0 21 | i += 2 22 | if op == opcode.EXTENDED_ARG: 23 | extended_arg = oparg * 65536 24 | continue 25 | else: 26 | oparg = None 27 | yield (op, oparg) 28 | 29 | 30 | -------------------------------------------------------------------------------- /cookbook/c10/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: sample 5 | Desc : 6 | """ 7 | 8 | -------------------------------------------------------------------------------- /cookbook/c10/p02_control_import.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 控制导入内容 5 | Desc : 6 | """ 7 | 8 | # somemodule.py 9 | def spam(): 10 | pass 11 | 12 | 13 | def grok(): 14 | pass 15 | 16 | 17 | blah = 42 18 | # Only export 'spam' and 'grok' 19 | __all__ = ['spam', 'grok'] 20 | 21 | -------------------------------------------------------------------------------- /cookbook/c11/p01_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p02_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p03_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p04_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p05_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p06_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p07_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p08_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p09_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p10_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p11_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p12_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c11/p13_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yidao620c/python3-cookbook/8c0b2ab251e0ac65b46e87dd511df41018f433bf/cookbook/c12/__init__.py -------------------------------------------------------------------------------- /cookbook/c12/p02_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p03_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p04_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p05_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p06_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p07_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p08_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p09_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p10_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p11_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p12_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p13_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c12/p14_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p01_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p02_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p03_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p04_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p05_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p06_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p07_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p08_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p09_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p10_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p11_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p12_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p13_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p14_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c13/p15_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p01_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p02_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p03_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p04_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p05_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p06_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p07_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p08_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p09_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p10_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p11_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p12_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p13_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c14/p14_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p01_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p02_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p03_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p04_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p05_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p06_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p07_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p08_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p09_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p10_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p11_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p12_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p13_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p14_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p15_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p16_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p17_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p18_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p19_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p20_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/c15/p21_.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ 4 | Topic: 5 | Desc : 6 | """ 7 | -------------------------------------------------------------------------------- /cookbook/somefile.txt: -------------------------------------------------------------------------------- 1 | Python is powerful... and fast; 2 | plays well with others; 3 | runs everywhere; 4 | is friendly & easy to learn; 5 | is Open. 6 | These are some of the reasons people who use Python would rather not use anything else. 7 | 8 | Python can be easy to pick up whether you're a first time programmer 9 | or you're experienced with other languages. 10 | The following pages are a useful first step to get on your way 11 | writing programs with Python! 12 | 13 | The community hosts conferences and meetups, collaborates on code, 14 | and much more. Python's documentation will help you along the way, 15 | and the mailing lists will keep you in touch. 16 | 17 | Conferences and Workshops 18 | Python Documentation 19 | Mailing Lists and IRC channels -------------------------------------------------------------------------------- /exts/chinese_search.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | def setup(app): 4 | import sphinx.search as search 5 | import zh 6 | search.languages["zh_CN"] = zh.SearchChinese -------------------------------------------------------------------------------- /exts/suffix.dic: -------------------------------------------------------------------------------- 1 | 和 2 | 是 3 | 了 4 | 中 5 | 有 6 | 都 7 | 的 8 | 来 9 | 在 10 | 次 11 | 还 12 | 但 13 | 为 14 | 里 15 | 用 16 | 外 17 | 上 18 | 下 19 | 就 20 | 以 21 | 去 22 | 即 23 | 丁 24 | 万 25 | 乔 26 | 余 27 | 候 28 | 傅 29 | 冯 30 | 刘 31 | 单 32 | 卢 33 | 史 34 | 叶 35 | 吕 36 | 吴 37 | 唐 38 | 夏 39 | 姚 40 | 姜 41 | 孔 42 | 孙 43 | 孟 44 | 宋 45 | 尹 46 | 崔 47 | 常 48 | 康 49 | 廖 50 | 张 51 | 彭 52 | 徐 53 | 戴 54 | 文 55 | 方 56 | 易 57 | 曹 58 | 曾 59 | 朱 60 | 李 61 | 杜 62 | 杨 63 | 林 64 | 梁 65 | 武 66 | 段 67 | 毛 68 | 江 69 | 汤 70 | 沈 71 | 潘 72 | 熊 73 | 王 74 | 田 75 | 白 76 | 石 77 | 秦 78 | 罗 79 | 肖 80 | 胡 81 | 苏 82 | 范 83 | 董 84 | 蒋 85 | 薛 86 | 袁 87 | 谢 88 | 谭 89 | 贾 90 | 赖 91 | 赵 92 | 邓 93 | 邱 94 | 邵 95 | 邹 96 | 郑 97 | 郝 98 | 郭 99 | 金 100 | 钟 101 | 钱 102 | 阎 103 | 陆 104 | 陈 105 | 雷 106 | 韩 107 | 顾 108 | 马 109 | 高 110 | 魏 111 | 黄 112 | 黎 113 | 龙 114 | 龚 -------------------------------------------------------------------------------- /exts/wuxiong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yidao620c/python3-cookbook/8c0b2ab251e0ac65b46e87dd511df41018f433bf/exts/wuxiong.jpg -------------------------------------------------------------------------------- /exts/zh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from sphinx.search import SearchLanguage 3 | from smallseg import SEG 4 | 5 | class SearchChinese(SearchLanguage): 6 | lang = 'zh' 7 | 8 | def init(self, options): 9 | print("reading Chiniese dictionary") 10 | self.seg = SEG() 11 | 12 | def split(self, input): 13 | return self.seg.cut(input.encode("utf8")) 14 | 15 | def word_filter(self, stemmed_word): 16 | return len(stemmed_word) > 1 17 | -------------------------------------------------------------------------------- /qcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yidao620c/python3-cookbook/8c0b2ab251e0ac65b46e87dd511df41018f433bf/qcode.jpg -------------------------------------------------------------------------------- /requirements_.txt: -------------------------------------------------------------------------------- 1 | PIL==1.1.7 2 | greenlet==0.4.5 3 | gunicorn==19.1.1 4 | oauthlib==0.7.2 5 | paho-mqtt==1.0 6 | paramiko==1.15.1 7 | psycopg2==2.5.4 8 | pycrypto==2.6.1 9 | pytz==2014.9 10 | tzlocal==1.1.2 11 | redis==2.10.3 12 | requests==2.4.3 13 | requests-oauthlib==0.4.2 14 | whitenoise==1.0.3 15 | openpyxl==2.1.5 -------------------------------------------------------------------------------- /source/aboutme.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | 关于译者 3 | ============== 4 | 5 | *关于译者* 6 | 7 | * 姓名: 熊能 8 | * 微信: yidao620 9 | * Email: yidao620@gmail.com 10 | * 博客: https://www.xncoding.com/ 11 | * GitHub: https://github.com/yidao620c 12 | 13 | -------------------------------------------- 14 | 15 | **欢迎关注我的个人公众号“飞污熊”,我会定期分享一些自己的Python学习笔记和心得。** 16 | 17 | .. image:: https://github.com/yidao620c/python3-cookbook/raw/master/exts/wuxiong.jpg 18 | 19 | 20 | -------------------------------------------------------------------------------- /source/c01/p07_keep_dict_in_order.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | 1.7 字典排序 3 | ================================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想创建一个字典,并且在迭代或序列化这个字典的时候能够控制元素的顺序。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 为了能控制一个字典中元素的顺序,你可以使用 ``collections`` 模块中的 ``OrderedDict`` 类。 14 | 在迭代操作的时候它会保持元素被插入时的顺序,示例如下: 15 | 16 | .. code-block:: python 17 | 18 | from collections import OrderedDict 19 | 20 | d = OrderedDict() 21 | d['foo'] = 1 22 | d['bar'] = 2 23 | d['spam'] = 3 24 | d['grok'] = 4 25 | # Outputs "foo 1", "bar 2", "spam 3", "grok 4" 26 | for key in d: 27 | print(key, d[key]) 28 | 29 | 当你想要构建一个将来需要序列化或编码成其他格式的映射的时候, ``OrderedDict`` 是非常有用的。 30 | 比如,你想精确控制以 JSON 编码后字段的顺序,你可以先使用 ``OrderedDict`` 来构建这样的数据: 31 | 32 | .. code-block:: python 33 | 34 | >>> import json 35 | >>> json.dumps(d) 36 | '{"foo": 1, "bar": 2, "spam": 3, "grok": 4}' 37 | >>> 38 | 39 | ---------- 40 | 讨论 41 | ---------- 42 | ``OrderedDict`` 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候, 43 | 它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会改变键的顺序。 44 | 45 | 需要注意的是,一个 ``OrderedDict`` 的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。 46 | 所以如果你要构建一个需要大量 ``OrderedDict`` 实例的数据结构的时候(比如读取 100,000 行 CSV 数据到一个 ``OrderedDict`` 列表中去), 47 | 那么你就得仔细权衡一下是否使用 ``OrderedDict`` 带来的好处要大过额外内存消耗的影响。 48 | -------------------------------------------------------------------------------- /source/c01/p09_find_commonalities_in_dicts.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 1.9 查找两字典的相同点 3 | ============================= 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 怎样在两个字典中寻找相同点(比如相同的键、相同的值等等)? 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 考虑下面两个字典: 14 | 15 | .. code-block:: python 16 | 17 | a = { 18 | 'x' : 1, 19 | 'y' : 2, 20 | 'z' : 3 21 | } 22 | 23 | b = { 24 | 'w' : 10, 25 | 'x' : 11, 26 | 'y' : 2 27 | } 28 | 29 | 为了寻找两个字典的相同点,可以简单的在两字典的 ``keys()`` 或者 ``items()`` 方法返回结果上执行集合操作。比如: 30 | 31 | .. code-block:: python 32 | 33 | # Find keys in common 34 | a.keys() & b.keys() # { 'x', 'y' } 35 | # Find keys in a that are not in b 36 | a.keys() - b.keys() # { 'z' } 37 | # Find (key,value) pairs in common 38 | a.items() & b.items() # { ('y', 2) } 39 | 40 | 这些操作也可以用于修改或者过滤字典元素。 41 | 比如,假如你想以现有字典构造一个排除几个指定键的新字典。 42 | 下面利用字典推导来实现这样的需求: 43 | 44 | .. code-block:: python 45 | 46 | # Make a new dictionary with certain keys removed 47 | c = {key:a[key] for key in a.keys() - {'z', 'w'}} 48 | # c is {'x': 1, 'y': 2} 49 | 50 | ---------- 51 | 讨论 52 | ---------- 53 | 一个字典就是一个键集合与值集合的映射关系。 54 | 字典的 ``keys()`` 方法返回一个展现键集合的键视图对象。 55 | 键视图的一个很少被了解的特性就是它们也支持集合操作,比如集合并、交、差运算。 56 | 所以,如果你想对集合的键执行一些普通的集合操作,可以直接使用键视图对象而不用先将它们转换成一个 set。 57 | 58 | 字典的 ``items()`` 方法返回一个包含 (键,值) 对的元素视图对象。 59 | 这个对象同样也支持集合操作,并且可以被用来查找两个字典有哪些相同的键值对。 60 | 61 | 尽管字典的 ``values()`` 方法也是类似,但是它并不支持这里介绍的集合操作。 62 | 某种程度上是因为值视图并不能保证所有的值互不相同,这样会导致某些集合操作出现问题。 63 | 不过,如果你硬要在值上面执行这些集合操作的话,可以先将值集合转换成 set,然后再执行集合运算。 64 | -------------------------------------------------------------------------------- /source/c01/p17_extract_subset_of_dict.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | 1.17 从字典中提取子集 3 | ================================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想构造一个字典,它是另外一个字典的子集。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 最简单的方式是使用字典推导。比如: 14 | 15 | .. code-block:: python 16 | 17 | prices = { 18 | 'ACME': 45.23, 19 | 'AAPL': 612.78, 20 | 'IBM': 205.55, 21 | 'HPQ': 37.20, 22 | 'FB': 10.75 23 | } 24 | # Make a dictionary of all prices over 200 25 | p1 = {key: value for key, value in prices.items() if value > 200} 26 | # Make a dictionary of tech stocks 27 | tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'} 28 | p2 = {key: value for key, value in prices.items() if key in tech_names} 29 | 30 | ---------- 31 | 讨论 32 | ---------- 33 | 大多数情况下字典推导能做到的,通过创建一个元组序列然后把它传给 ``dict()`` 函数也能实现。比如: 34 | 35 | .. code-block:: python 36 | 37 | p1 = dict((key, value) for key, value in prices.items() if value > 200) 38 | 39 | 但是,字典推导方式表意更清晰,并且实际上也会运行的更快些 40 | (在这个例子中,实际测试几乎比 ``dict()`` 函数方式快了一倍多)。 41 | 42 | 有时候完成同一件事会有多种方式。比如,第二个例子程序也可以像这样重写: 43 | 44 | .. code-block:: python 45 | 46 | # Make a dictionary of tech stocks 47 | tech_names = { 'AAPL', 'IBM', 'HPQ', 'MSFT' } 48 | p2 = { key:prices[key] for key in prices.keys() & tech_names } 49 | 50 | 但是,运行时间测试结果显示这种方案大概比第一种方案慢 1.6 倍。 51 | 如果对程序运行性能要求比较高的话,需要花点时间去做计时测试。 52 | 关于更多计时和性能测试,可以参考 14.13 小节。 53 | -------------------------------------------------------------------------------- /source/c02/p07_specify_regexp_for_shortest_match.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | 2.7 最短匹配模式 3 | ======================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你正在试着用正则表达式匹配某个文本模式,但是它找到的是模式的最长可能匹配。 9 | 而你想修改它变成查找最短的可能匹配。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | 这个问题一般出现在需要匹配一对分隔符之间的文本的时候(比如引号包含的字符串)。 15 | 为了说明清楚,考虑如下的例子: 16 | 17 | .. code-block:: python 18 | 19 | >>> str_pat = re.compile(r'"(.*)"') 20 | >>> text1 = 'Computer says "no."' 21 | >>> str_pat.findall(text1) 22 | ['no.'] 23 | >>> text2 = 'Computer says "no." Phone says "yes."' 24 | >>> str_pat.findall(text2) 25 | ['no." Phone says "yes.'] 26 | >>> 27 | 28 | 在这个例子中,模式 ``r'\"(.*)\"'`` 的意图是匹配被双引号包含的文本。 29 | 但是在正则表达式中*操作符是贪婪的,因此匹配操作会查找最长的可能匹配。 30 | 于是在第二个例子中搜索 ``text2`` 的时候返回结果并不是我们想要的。 31 | 32 | 为了修正这个问题,可以在模式中的*操作符后面加上?修饰符,就像这样: 33 | 34 | .. code-block:: python 35 | 36 | >>> str_pat = re.compile(r'"(.*?)"') 37 | >>> str_pat.findall(text2) 38 | ['no.', 'yes.'] 39 | >>> 40 | 41 | 这样就使得匹配变成非贪婪模式,从而得到最短的匹配,也就是我们想要的结果。 42 | 43 | ---------- 44 | 讨论 45 | ---------- 46 | 这一节展示了在写包含点(.)字符的正则表达式的时候遇到的一些常见问题。 47 | 在一个模式字符串中,点(.)匹配除了换行外的任何字符。 48 | 然而,如果你将点(.)号放在开始与结束符(比如引号)之间的时候,那么匹配操作会查找符合模式的最长可能匹配。 49 | 这样通常会导致很多中间的被开始与结束符包含的文本被忽略掉,并最终被包含在匹配结果字符串中返回。 50 | 通过在 ``*`` 或者 ``+`` 这样的操作符后面添加一个 ``?`` 可以强制匹配算法改成寻找最短的可能匹配。 51 | 52 | -------------------------------------------------------------------------------- /source/c02/p08_regexp_for_multiline_partterns.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | 2.8 多行匹配模式 3 | ======================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你正在试着使用正则表达式去匹配一大块的文本,而你需要跨越多行去匹配。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 这个问题很典型的出现在当你用点(.)去匹配任意字符的时候,忘记了点(.)不能匹配换行符的事实。 14 | 比如,假设你想试着去匹配C语言分割的注释: 15 | 16 | .. code-block:: python 17 | 18 | >>> comment = re.compile(r'/\*(.*?)\*/') 19 | >>> text1 = '/* this is a comment */' 20 | >>> text2 = '''/* this is a 21 | ... multiline comment */ 22 | ... ''' 23 | >>> 24 | >>> comment.findall(text1) 25 | [' this is a comment '] 26 | >>> comment.findall(text2) 27 | [] 28 | >>> 29 | 30 | 为了修正这个问题,你可以修改模式字符串,增加对换行的支持。比如: 31 | 32 | .. code-block:: python 33 | 34 | >>> comment = re.compile(r'/\*((?:.|\n)*?)\*/') 35 | >>> comment.findall(text2) 36 | [' this is a\n multiline comment '] 37 | >>> 38 | 39 | 在这个模式中, ``(?:.|\n)`` 指定了一个非捕获组 40 | (也就是它定义了一个仅仅用来做匹配,而不能通过单独捕获或者编号的组)。 41 | 42 | ---------- 43 | 讨论 44 | ---------- 45 | ``re.compile()`` 函数接受一个标志参数叫 ``re.DOTALL`` ,在这里非常有用。 46 | 它可以让正则表达式中的点(.)匹配包括换行符在内的任意字符。比如: 47 | 48 | .. code-block:: python 49 | 50 | >>> comment = re.compile(r'/\*(.*?)\*/', re.DOTALL) 51 | >>> comment.findall(text2) 52 | [' this is a\n multiline comment '] 53 | 54 | 对于简单的情况使用 ``re.DOTALL`` 标记参数工作的很好, 55 | 但是如果模式非常复杂或者是为了构造字符串令牌而将多个模式合并起来(2.18节有详细描述), 56 | 这时候使用这个标记参数就可能出现一些问题。 57 | 如果让你选择的话,最好还是定义自己的正则表达式模式,这样它可以在不需要额外的标记参数下也能工作的很好。 58 | 59 | -------------------------------------------------------------------------------- /source/c02/p10_work_with_unicode_in_regexp.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2.10 在正则式中使用Unicode 3 | =========================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你正在使用正则表达式处理文本,但是关注的是Unicode字符处理。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 默认情况下 ``re`` 模块已经对一些Unicode字符类有了基本的支持。 14 | 比如, ``\\d`` 已经匹配任意的unicode数字字符了: 15 | 16 | .. code-block:: python 17 | 18 | >>> import re 19 | >>> num = re.compile('\d+') 20 | >>> # ASCII digits 21 | >>> num.match('123') 22 | <_sre.SRE_Match object at 0x1007d9ed0> 23 | >>> # Arabic digits 24 | >>> num.match('\u0661\u0662\u0663') 25 | <_sre.SRE_Match object at 0x101234030> 26 | >>> 27 | 28 | 如果你想在模式中包含指定的Unicode字符,你可以使用Unicode字符对应的转义序列(比如 ``\uFFF`` 或者 ``\UFFFFFFF`` )。 29 | 比如,下面是一个匹配几个不同阿拉伯编码页面中所有字符的正则表达式: 30 | 31 | .. code-block:: python 32 | 33 | >>> arabic = re.compile('[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff]+') 34 | >>> 35 | 36 | 当执行匹配和搜索操作的时候,最好是先标准化并且清理所有文本为标准化格式(参考2.9小节)。 37 | 但是同样也应该注意一些特殊情况,比如在忽略大小写匹配和大小写转换时的行为。 38 | 39 | .. code-block:: python 40 | 41 | >>> pat = re.compile('stra\u00dfe', re.IGNORECASE) 42 | >>> s = 'straße' 43 | >>> pat.match(s) # Matches 44 | <_sre.SRE_Match object at 0x10069d370> 45 | >>> pat.match(s.upper()) # Doesn't match 46 | >>> s.upper() # Case folds 47 | 'STRASSE' 48 | >>> 49 | 50 | ---------- 51 | 讨论 52 | ---------- 53 | 混合使用Unicode和正则表达式通常会让你抓狂。 54 | 如果你真的打算这样做的话,最好考虑下安装第三方正则式库, 55 | 它们会为Unicode的大小写转换和其他大量有趣特性提供全面的支持,包括模糊匹配。 56 | 57 | -------------------------------------------------------------------------------- /source/c03/p08_calculating_with_fractions.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 3.8 分数运算 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你进入时间机器,突然发现你正在做小学家庭作业,并涉及到分数计算问题。 9 | 或者你可能需要写代码去计算在你的木工工厂中的测量值。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | ``fractions`` 模块可以被用来执行包含分数的数学运算。比如: 15 | 16 | .. code-block:: python 17 | 18 | >>> from fractions import Fraction 19 | >>> a = Fraction(5, 4) 20 | >>> b = Fraction(7, 16) 21 | >>> print(a + b) 22 | 27/16 23 | >>> print(a * b) 24 | 35/64 25 | 26 | >>> # Getting numerator/denominator 27 | >>> c = a * b 28 | >>> c.numerator 29 | 35 30 | >>> c.denominator 31 | 64 32 | 33 | >>> # Converting to a float 34 | >>> float(c) 35 | 0.546875 36 | 37 | >>> # Limiting the denominator of a value 38 | >>> print(c.limit_denominator(8)) 39 | 4/7 40 | 41 | >>> # Converting a float to a fraction 42 | >>> x = 3.75 43 | >>> y = Fraction(*x.as_integer_ratio()) 44 | >>> y 45 | Fraction(15, 4) 46 | >>> 47 | 48 | ---------- 49 | 讨论 50 | ---------- 51 | 在大多数程序中一般不会出现分数的计算问题,但是有时候还是需要用到的。 52 | 比如,在一个允许接受分数形式的测试单位并以分数形式执行运算的程序中, 53 | 直接使用分数可以减少手动转换为小数或浮点数的工作。 54 | 55 | -------------------------------------------------------------------------------- /source/c03/p15_convert_strings_into_datetimes.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 3.15 字符串转换为日期 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你的应用程序接受字符串格式的输入,但是你想将它们转换为 ``datetime`` 对象以便在上面执行非字符串操作。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 使用Python的标准模块 ``datetime`` 可以很容易的解决这个问题。比如: 14 | 15 | .. code-block:: python 16 | 17 | >>> from datetime import datetime 18 | >>> text = '2012-09-20' 19 | >>> y = datetime.strptime(text, '%Y-%m-%d') 20 | >>> z = datetime.now() 21 | >>> diff = z - y 22 | >>> diff 23 | datetime.timedelta(3, 77824, 177393) 24 | >>> 25 | 26 | ---------- 27 | 讨论 28 | ---------- 29 | ``datetime.strptime()`` 方法支持很多的格式化代码, 30 | 比如 ``%Y`` 代表4位数年份, ``%m`` 代表两位数月份。 31 | 还有一点值得注意的是这些格式化占位符也可以反过来使用,将日期输出为指定的格式字符串形式。 32 | 33 | 比如,假设你的代码中生成了一个 ``datetime`` 对象, 34 | 你想将它格式化为漂亮易读形式后放在自动生成的信件或者报告的顶部: 35 | 36 | .. code-block:: python 37 | 38 | >>> z 39 | datetime.datetime(2012, 9, 23, 21, 37, 4, 177393) 40 | >>> nice_z = datetime.strftime(z, '%A %B %d, %Y') 41 | >>> nice_z 42 | 'Sunday September 23, 2012' 43 | >>> 44 | 45 | 还有一点需要注意的是, ``strptime()`` 的性能要比你想象中的差很多, 46 | 因为它是使用纯Python实现,并且必须处理所有的系统本地设置。 47 | 如果你要在代码中需要解析大量的日期并且已经知道了日期字符串的确切格式,可以自己实现一套解析方案来获取更好的性能。 48 | 比如,如果你已经知道所以日期格式是 ``YYYY-MM-DD`` ,你可以像下面这样实现一个解析函数: 49 | 50 | .. code-block:: python 51 | 52 | from datetime import datetime 53 | def parse_ymd(s): 54 | year_s, mon_s, day_s = s.split('-') 55 | return datetime(int(year_s), int(mon_s), int(day_s)) 56 | 57 | 实际测试中,这个函数比 ``datetime.strptime()`` 快7倍多。 58 | 如果你要处理大量的涉及到日期的数据的话,那么最好考虑下这个方案! 59 | -------------------------------------------------------------------------------- /source/c04/p02_delegating_iteration.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 4.2 代理迭代 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你构建了一个自定义容器对象,里面包含有列表、元组或其他可迭代对象。 9 | 你想直接在你的这个新容器对象上执行迭代操作。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | 实际上你只需要定义一个 ``__iter__()`` 方法,将迭代操作代理到容器内部的对象上去。比如: 15 | 16 | .. code-block:: python 17 | 18 | class Node: 19 | def __init__(self, value): 20 | self._value = value 21 | self._children = [] 22 | 23 | def __repr__(self): 24 | return 'Node({!r})'.format(self._value) 25 | 26 | def add_child(self, node): 27 | self._children.append(node) 28 | 29 | def __iter__(self): 30 | return iter(self._children) 31 | 32 | # Example 33 | if __name__ == '__main__': 34 | root = Node(0) 35 | child1 = Node(1) 36 | child2 = Node(2) 37 | root.add_child(child1) 38 | root.add_child(child2) 39 | # Outputs Node(1), Node(2) 40 | for ch in root: 41 | print(ch) 42 | 43 | 在上面代码中, ``__iter__()`` 方法只是简单的将迭代请求传递给内部的 ``_children`` 属性。 44 | 45 | ---------- 46 | 讨论 47 | ---------- 48 | Python的迭代器协议需要 ``__iter__()`` 方法返回一个实现了 ``__next__()`` 方法的迭代器对象。 49 | 如果你只是迭代遍历其他容器的内容,你无须担心底层是怎样实现的。你所要做的只是传递迭代请求既可。 50 | 51 | 这里的 ``iter()`` 函数使用了简化的代码, 52 | ``iter(s)`` 只是简单的通过调用 ``s.__iter__()`` 方法来返回对应的迭代器对象, 53 | 就跟 ``len(s)`` 会调用 ``s.__len__()`` 原理是一样的。 54 | 55 | -------------------------------------------------------------------------------- /source/c04/p05_iterating_in_reverse.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 4.5 反向迭代 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想反方向迭代一个序列 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 使用内置的 ``reversed()`` 函数,比如: 14 | 15 | .. code-block:: python 16 | 17 | >>> a = [1, 2, 3, 4] 18 | >>> for x in reversed(a): 19 | ... print(x) 20 | ... 21 | 4 22 | 3 23 | 2 24 | 1 25 | 26 | 反向迭代仅仅当对象的大小可预先确定或者对象实现了 ``__reversed__()`` 的特殊方法时才能生效。 27 | 如果两者都不符合,那你必须先将对象转换为一个列表才行,比如: 28 | 29 | .. code-block:: python 30 | 31 | # Print a file backwards 32 | f = open('somefile') 33 | for line in reversed(list(f)): 34 | print(line, end='') 35 | 36 | 要注意的是如果可迭代对象元素很多的话,将其预先转换为一个列表要消耗大量的内存。 37 | 38 | ---------- 39 | 讨论 40 | ---------- 41 | 很多程序员并不知道可以通过在自定义类上实现 ``__reversed__()`` 方法来实现反向迭代。比如: 42 | 43 | .. code-block:: python 44 | 45 | class Countdown: 46 | def __init__(self, start): 47 | self.start = start 48 | 49 | # Forward iterator 50 | def __iter__(self): 51 | n = self.start 52 | while n > 0: 53 | yield n 54 | n -= 1 55 | 56 | # Reverse iterator 57 | def __reversed__(self): 58 | n = 1 59 | while n <= self.start: 60 | yield n 61 | n += 1 62 | 63 | for rr in reversed(Countdown(30)): 64 | print(rr) 65 | for rr in Countdown(30): 66 | print(rr) 67 | 68 | 定义一个反向迭代器可以使得代码非常的高效, 69 | 因为它不再需要将数据填充到一个列表中然后再去反向迭代这个列表。 70 | -------------------------------------------------------------------------------- /source/c04/p07_taking_slice_of_iterator.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 4.7 迭代器切片 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想得到一个由迭代器生成的切片对象,但是标准切片操作并不能做到。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 函数 ``itertools.islice()`` 正好适用于在迭代器和生成器上做切片操作。比如: 14 | 15 | .. code-block:: python 16 | 17 | >>> def count(n): 18 | ... while True: 19 | ... yield n 20 | ... n += 1 21 | ... 22 | >>> c = count(0) 23 | >>> c[10:20] 24 | Traceback (most recent call last): 25 | File "", line 1, in 26 | TypeError: 'generator' object is not subscriptable 27 | 28 | >>> # Now using islice() 29 | >>> import itertools 30 | >>> for x in itertools.islice(c, 10, 20): 31 | ... print(x) 32 | ... 33 | 10 34 | 11 35 | 12 36 | 13 37 | 14 38 | 15 39 | 16 40 | 17 41 | 18 42 | 19 43 | >>> 44 | 45 | ---------- 46 | 讨论 47 | ---------- 48 | 迭代器和生成器不能使用标准的切片操作,因为它们的长度事先我们并不知道(并且也没有实现索引)。 49 | 函数 ``islice()`` 返回一个可以生成指定元素的迭代器,它通过遍历并丢弃直到切片开始索引位置的所有元素。 50 | 然后才开始一个个的返回元素,并直到切片结束索引位置。 51 | 52 | 这里要着重强调的一点是 ``islice()`` 会消耗掉传入的迭代器中的数据。 53 | 必须考虑到迭代器是不可逆的这个事实。 54 | 所以如果你需要之后再次访问这个迭代器的话,那你就得先将它里面的数据放入一个列表中。 55 | -------------------------------------------------------------------------------- /source/c04/p15_iterate_in_sorted_order_over_merged_sorted_iterables.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 4.15 顺序迭代合并后的排序迭代对象 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你有一系列排序序列,想将它们合并后得到一个排序序列并在上面迭代遍历。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | ``heapq.merge()`` 函数可以帮你解决这个问题。比如: 14 | 15 | .. code-block:: python 16 | 17 | >>> import heapq 18 | >>> a = [1, 4, 7, 10] 19 | >>> b = [2, 5, 6, 11] 20 | >>> for c in heapq.merge(a, b): 21 | ... print(c) 22 | ... 23 | 1 24 | 2 25 | 4 26 | 5 27 | 6 28 | 7 29 | 10 30 | 11 31 | 32 | 33 | ---------- 34 | 讨论 35 | ---------- 36 | ``heapq.merge`` 可迭代特性意味着它不会立马读取所有序列。 37 | 这就意味着你可以在非常长的序列中使用它,而不会有太大的开销。 38 | 比如,下面是一个例子来演示如何合并两个排序文件: 39 | 40 | .. code-block:: python 41 | 42 | with open('sorted_file_1', 'rt') as file1, \ 43 | open('sorted_file_2', 'rt') as file2, \ 44 | open('merged_file', 'wt') as outf: 45 | 46 | for line in heapq.merge(file1, file2): 47 | outf.write(line) 48 | 49 | 有一点要强调的是 ``heapq.merge()`` 需要所有输入序列必须是排过序的。 50 | 特别的,它并不会预先读取所有数据到堆栈中或者预先排序,也不会对输入做任何的排序检测。 51 | 它仅仅是检查所有序列的开始部分并返回最小的那个,这个过程一直会持续直到所有输入序列中的元素都被遍历完。 52 | -------------------------------------------------------------------------------- /source/c05/p02_printing_to_file.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 5.2 打印输出至文件中 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想将 ``print()`` 函数的输出重定向到一个文件中去。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 在 ``print()`` 函数中指定 ``file`` 关键字参数,像下面这样: 14 | 15 | .. code-block:: python 16 | 17 | with open('d:/work/test.txt', 'wt') as f: 18 | print('Hello World!', file=f) 19 | 20 | ---------- 21 | 讨论 22 | ---------- 23 | 关于输出重定向到文件中就这些了。但是有一点要注意的就是文件必须是以文本模式打开。 24 | 如果文件是二进制模式的话,打印就会出错。 25 | 26 | -------------------------------------------------------------------------------- /source/c05/p05_write_to_file_not_exist.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | 5.5 文件不存在才能写入 3 | ========================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想向一个文件中写入数据,但是前提必须是这个文件在文件系统上不存在。 9 | 也就是不允许覆盖已存在的文件内容。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | 可以在 ``open()`` 函数中使用 ``x`` 模式来代替 ``w`` 模式的方法来解决这个问题。比如: 15 | 16 | .. code-block:: python 17 | 18 | >>> with open('somefile', 'wt') as f: 19 | ... f.write('Hello\n') 20 | ... 21 | >>> with open('somefile', 'xt') as f: 22 | ... f.write('Hello\n') 23 | ... 24 | Traceback (most recent call last): 25 | File "", line 1, in 26 | FileExistsError: [Errno 17] File exists: 'somefile' 27 | >>> 28 | 29 | 如果文件是二进制的,使用 ``xb`` 来代替 ``xt`` 30 | 31 | ---------- 32 | 讨论 33 | ---------- 34 | 这一小节演示了在写文件时通常会遇到的一个问题的完美解决方案(不小心覆盖一个已存在的文件)。 35 | 一个替代方案是先测试这个文件是否存在,像下面这样: 36 | 37 | .. code-block:: python 38 | 39 | >>> import os 40 | >>> if not os.path.exists('somefile'): 41 | ... with open('somefile', 'wt') as f: 42 | ... f.write('Hello\n') 43 | ... else: 44 | ... print('File already exists!') 45 | ... 46 | File already exists! 47 | >>> 48 | 49 | 显而易见,使用x文件模式更加简单。要注意的是x模式是一个Python3对 ``open()`` 函数特有的扩展。 50 | 在Python的旧版本或者是Python实现的底层C函数库中都是没有这个模式的。 51 | -------------------------------------------------------------------------------- /source/c05/p06_io_operations_on_string.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 5.6 字符串的I/O操作 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想使用操作类文件对象的程序来操作文本或二进制字符串。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 使用 ``io.StringIO()`` 和 ``io.BytesIO()`` 类来创建类文件对象操作字符串数据。比如: 14 | 15 | .. code-block:: python 16 | 17 | >>> s = io.StringIO() 18 | >>> s.write('Hello World\n') 19 | 12 20 | >>> print('This is a test', file=s) 21 | 15 22 | >>> # Get all of the data written so far 23 | >>> s.getvalue() 24 | 'Hello World\nThis is a test\n' 25 | >>> 26 | 27 | >>> # Wrap a file interface around an existing string 28 | >>> s = io.StringIO('Hello\nWorld\n') 29 | >>> s.read(4) 30 | 'Hell' 31 | >>> s.read() 32 | 'o\nWorld\n' 33 | >>> 34 | 35 | ``io.StringIO`` 只能用于文本。如果你要操作二进制数据,要使用 ``io.BytesIO`` 类来代替。比如: 36 | 37 | .. code-block:: python 38 | 39 | >>> s = io.BytesIO() 40 | >>> s.write(b'binary data') 41 | >>> s.getvalue() 42 | b'binary data' 43 | >>> 44 | 45 | ---------- 46 | 讨论 47 | ---------- 48 | 当你想模拟一个普通的文件的时候 ``StringIO`` 和 ``BytesIO`` 类是很有用的。 49 | 比如,在单元测试中,你可以使用 ``StringIO`` 来创建一个包含测试数据的类文件对象, 50 | 这个对象可以被传给某个参数为普通文件对象的函数。 51 | 52 | 需要注意的是, ``StringIO`` 和 ``BytesIO`` 实例并没有正确的整数类型的文件描述符。 53 | 因此,它们不能在那些需要使用真实的系统级文件如文件,管道或者是套接字的程序中使用。 54 | 55 | -------------------------------------------------------------------------------- /source/c05/p08_iterate_over_fixed_sized_records.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 5.8 固定大小记录的文件迭代 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想在一个固定长度记录或者数据块的集合上迭代,而不是在一个文件中一行一行的迭代。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 通过下面这个小技巧使用 ``iter`` 和 ``functools.partial()`` 函数: 14 | 15 | .. code-block:: python 16 | 17 | from functools import partial 18 | 19 | RECORD_SIZE = 32 20 | 21 | with open('somefile.data', 'rb') as f: 22 | records = iter(partial(f.read, RECORD_SIZE), b'') 23 | for r in records: 24 | ... 25 | 26 | 这个例子中的 ``records`` 对象是一个可迭代对象,它会不断的产生固定大小的数据块,直到文件末尾。 27 | 要注意的是如果总记录大小不是块大小的整数倍的话,最后一个返回元素的字节数会比期望值少。 28 | 29 | ---------- 30 | 讨论 31 | ---------- 32 | ``iter()`` 函数有一个鲜为人知的特性就是,如果你给它传递一个可调用对象和一个标记值,它会创建一个迭代器。 33 | 这个迭代器会一直调用传入的可调用对象直到它返回标记值为止,这时候迭代终止。 34 | 35 | 在例子中, ``functools.partial`` 用来创建一个每次被调用时从文件中读取固定数目字节的可调用对象。 36 | 标记值 ``b''`` 就是当到达文件结尾时的返回值。 37 | 38 | 最后再提一点,上面的例子中的文件时以二进制模式打开的。 39 | 如果是读取固定大小的记录,这通常是最普遍的情况。 40 | 而对于文本文件,一行一行的读取(默认的迭代行为)更普遍点。 41 | 42 | -------------------------------------------------------------------------------- /source/c05/p11_manipulating_pathnames.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 5.11 文件路径名的操作 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你需要使用路径名来获取文件名,目录名,绝对路径等等。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 使用 ``os.path`` 模块中的函数来操作路径名。 14 | 下面是一个交互式例子来演示一些关键的特性: 15 | 16 | .. code-block:: python 17 | 18 | >>> import os 19 | >>> path = '/Users/beazley/Data/data.csv' 20 | 21 | >>> # Get the last component of the path 22 | >>> os.path.basename(path) 23 | 'data.csv' 24 | 25 | >>> # Get the directory name 26 | >>> os.path.dirname(path) 27 | '/Users/beazley/Data' 28 | 29 | >>> # Join path components together 30 | >>> os.path.join('tmp', 'data', os.path.basename(path)) 31 | 'tmp/data/data.csv' 32 | 33 | >>> # Expand the user's home directory 34 | >>> path = '~/Data/data.csv' 35 | >>> os.path.expanduser(path) 36 | '/Users/beazley/Data/data.csv' 37 | 38 | >>> # Split the file extension 39 | >>> os.path.splitext(path) 40 | ('~/Data/data', '.csv') 41 | >>> 42 | 43 | ---------- 44 | 讨论 45 | ---------- 46 | 对于任何的文件名的操作,你都应该使用 ``os.path`` 模块,而不是使用标准字符串操作来构造自己的代码。 47 | 特别是为了可移植性考虑的时候更应如此, 48 | 因为 ``os.path`` 模块知道Unix和Windows系统之间的差异并且能够可靠地处理类似 ``Data/data.csv`` 49 | 和 ``Data\data.csv`` 这样的文件名。 50 | 其次,你真的不应该浪费时间去重复造轮子。通常最好是直接使用已经为你准备好的功能。 51 | 52 | 要注意的是 ``os.path`` 还有更多的功能在这里并没有列举出来。 53 | 可以查阅官方文档来获取更多与文件测试,符号链接等相关的函数说明。 54 | 55 | -------------------------------------------------------------------------------- /source/c05/p14_bypassing_filename_encoding.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 5.14 忽略文件名编码 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想使用原始文件名执行文件的I/O操作,也就是说文件名并没有经过系统默认编码去解码或编码过。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 默认情况下,所有的文件名都会根据 ``sys.getfilesystemencoding()`` 返回的文本编码来编码或解码。比如: 14 | 15 | .. code-block:: python 16 | 17 | >>> sys.getfilesystemencoding() 18 | 'utf-8' 19 | >>> 20 | 21 | 如果因为某种原因你想忽略这种编码,可以使用一个原始字节字符串来指定一个文件名即可。比如: 22 | 23 | .. code-block:: python 24 | 25 | >>> # Wrte a file using a unicode filename 26 | >>> with open('jalape\xf1o.txt', 'w') as f: 27 | ... f.write('Spicy!') 28 | ... 29 | 6 30 | >>> # Directory listing (decoded) 31 | >>> import os 32 | >>> os.listdir('.') 33 | ['jalapeño.txt'] 34 | 35 | >>> # Directory listing (raw) 36 | >>> os.listdir(b'.') # Note: byte string 37 | [b'jalapen\xcc\x83o.txt'] 38 | 39 | >>> # Open file with raw filename 40 | >>> with open(b'jalapen\xcc\x83o.txt') as f: 41 | ... print(f.read()) 42 | ... 43 | Spicy! 44 | >>> 45 | 46 | 正如你所见,在最后两个操作中,当你给文件相关函数如 ``open()`` 和 ``os.listdir()`` 47 | 传递字节字符串时,文件名的处理方式会稍有不同。 48 | 49 | ---------- 50 | 讨论 51 | ---------- 52 | 通常来讲,你不需要担心文件名的编码和解码,普通的文件名操作应该就没问题了。 53 | 但是,有些操作系统允许用户通过偶然或恶意方式去创建名字不符合默认编码的文件。 54 | 这些文件名可能会神秘地中断那些需要处理大量文件的Python程序。 55 | 56 | 读取目录并通过原始未解码方式处理文件名可以有效的避免这样的问题, 57 | 尽管这样会带来一定的编程难度。 58 | 59 | 关于打印不可解码的文件名,请参考5.15小节。 60 | -------------------------------------------------------------------------------- /source/c05/p17_write_bytes_to_text_file.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 5.17 将字节写入文本文件 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想在文本模式打开的文件中写入原始的字节数据。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 将字节数据直接写入文件的缓冲区即可,例如: 14 | 15 | .. code-block:: python 16 | 17 | >>> import sys 18 | >>> sys.stdout.write(b'Hello\n') 19 | Traceback (most recent call last): 20 | File "", line 1, in 21 | TypeError: must be str, not bytes 22 | >>> sys.stdout.buffer.write(b'Hello\n') 23 | Hello 24 | 5 25 | >>> 26 | 27 | 类似的,能够通过读取文本文件的 ``buffer`` 属性来读取二进制数据。 28 | 29 | ---------- 30 | 讨论 31 | ---------- 32 | I/O系统以层级结构的形式构建而成。 33 | 文本文件是通过在一个拥有缓冲的二进制模式文件上增加一个Unicode编码/解码层来创建。 34 | ``buffer`` 属性指向对应的底层文件。如果你直接访问它的话就会绕过文本编码/解码层。 35 | 36 | 本小节例子展示的 ``sys.stdout`` 可能看起来有点特殊。 37 | 默认情况下,``sys.stdout`` 总是以文本模式打开的。 38 | 但是如果你在写一个需要打印二进制数据到标准输出的脚本的话,你可以使用上面演示的技术来绕过文本编码层。 39 | 40 | -------------------------------------------------------------------------------- /source/c05/p20_communicating_with_serial_ports.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 5.20 与串行端口的数据通信 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想通过串行端口读写数据,典型场景就是和一些硬件设备打交道(比如一个机器人或传感器)。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 尽管你可以通过使用Python内置的I/O模块来完成这个任务,但对于串行通信最好的选择是使用 14 | `pySerial包 `_ 。 15 | 这个包的使用非常简单,先安装pySerial,使用类似下面这样的代码就能很容易的打开一个串行端口: 16 | 17 | .. code-block:: python 18 | 19 | import serial 20 | ser = serial.Serial('/dev/tty.usbmodem641', # Device name varies 21 | baudrate=9600, 22 | bytesize=8, 23 | parity='N', 24 | stopbits=1) 25 | 26 | 设备名对于不同的设备和操作系统是不一样的。 27 | 比如,在Windows系统上,你可以使用0, 1等表示的一个设备来打开通信端口"COM0"和"COM1"。 28 | 一旦端口打开,那就可以使用 ``read()``,``readline()`` 和 ``write()`` 函数读写数据了。例如: 29 | 30 | .. code-block:: python 31 | 32 | ser.write(b'G1 X50 Y50\r\n') 33 | resp = ser.readline() 34 | 35 | 大多数情况下,简单的串口通信从此变得十分简单。 36 | 37 | ---------- 38 | 讨论 39 | ---------- 40 | 尽管表面上看起来很简单,其实串口通信有时候也是挺麻烦的。 41 | 推荐你使用第三方包如 ``pySerial`` 的一个原因是它提供了对高级特性的支持 42 | (比如超时,控制流,缓冲区刷新,握手协议等等)。举个例子,如果你想启用 ``RTS-CTS`` 握手协议, 43 | 你只需要给 ``Serial()`` 传递一个 ``rtscts=True`` 的参数即可。 44 | 其官方文档非常完善,因此我在这里极力推荐这个包。 45 | 46 | 时刻记住所有涉及到串口的I/O都是二进制模式的。因此,确保你的代码使用的是字节而不是文本 47 | (或有时候执行文本的编码/解码操作)。 48 | 另外当你需要创建二进制编码的指令或数据包的时候,``struct`` 模块也是非常有用的。 49 | 50 | -------------------------------------------------------------------------------- /source/c06/p09_decode_encode_hexadecimal_digits.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 6.9 编码和解码十六进制数 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想将一个十六进制字符串解码成一个字节字符串或者将一个字节字符串编码成一个十六进制字符串。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 如果你只是简单的解码或编码一个十六进制的原始字符串,可以使用 ``binascii`` 模块。例如: 14 | 15 | .. code-block:: python 16 | 17 | >>> # Initial byte string 18 | >>> s = b'hello' 19 | >>> # Encode as hex 20 | >>> import binascii 21 | >>> h = binascii.b2a_hex(s) 22 | >>> h 23 | b'68656c6c6f' 24 | >>> # Decode back to bytes 25 | >>> binascii.a2b_hex(h) 26 | b'hello' 27 | >>> 28 | 29 | 类似的功能同样可以在 ``base64`` 模块中找到。例如: 30 | 31 | .. code-block:: python 32 | 33 | >>> import base64 34 | >>> h = base64.b16encode(s) 35 | >>> h 36 | b'68656C6C6F' 37 | >>> base64.b16decode(h) 38 | b'hello' 39 | >>> 40 | 41 | ---------- 42 | 讨论 43 | ---------- 44 | 大部分情况下,通过使用上述的函数来转换十六进制是很简单的。 45 | 上面两种技术的主要不同在于大小写的处理。 46 | 函数 ``base64.b16decode()`` 和 ``base64.b16encode()`` 只能操作大写形式的十六进制字母, 47 | 而 ``binascii`` 模块中的函数大小写都能处理。 48 | 49 | 还有一点需要注意的是编码函数所产生的输出总是一个字节字符串。 50 | 如果想强制以Unicode形式输出,你需要增加一个额外的解码步骤。例如: 51 | 52 | .. code-block:: python 53 | 54 | >>> h = base64.b16encode(s) 55 | >>> print(h) 56 | b'68656C6C6F' 57 | >>> print(h.decode('ascii')) 58 | 68656C6C6F 59 | >>> 60 | 61 | 在解码十六进制数时,函数 ``b16decode()`` 和 ``a2b_hex()`` 可以接受字节或unicode字符串。 62 | 但是,unicode字符串必须仅仅只包含ASCII编码的十六进制数。 63 | -------------------------------------------------------------------------------- /source/c06/p10_decode_encode_base64.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 6.10 编码解码Base64数据 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你需要使用Base64格式解码或编码二进制数据。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | ``base64`` 模块中有两个函数 ``b64encode()`` and ``b64decode()`` 可以帮你解决这个问题。例如; 14 | 15 | .. code-block:: python 16 | 17 | >>> # Some byte data 18 | >>> s = b'hello' 19 | >>> import base64 20 | 21 | >>> # Encode as Base64 22 | >>> a = base64.b64encode(s) 23 | >>> a 24 | b'aGVsbG8=' 25 | 26 | >>> # Decode from Base64 27 | >>> base64.b64decode(a) 28 | b'hello' 29 | >>> 30 | 31 | ---------- 32 | 讨论 33 | ---------- 34 | Base64编码仅仅用于面向字节的数据比如字节字符串和字节数组。 35 | 此外,编码处理的输出结果总是一个字节字符串。 36 | 如果你想混合使用Base64编码的数据和Unicode文本,你必须添加一个额外的解码步骤。例如: 37 | 38 | .. code-block:: python 39 | 40 | >>> a = base64.b64encode(s).decode('ascii') 41 | >>> a 42 | 'aGVsbG8=' 43 | >>> 44 | 45 | 当解码Base64的时候,字节字符串和Unicode文本都可以作为参数。 46 | 但是,Unicode字符串只能包含ASCII字符。 47 | -------------------------------------------------------------------------------- /source/c07/p02_functions_that_only_accept_keyword_arguments.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 7.2 只接受关键字参数的函数 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你希望函数的某些参数强制使用关键字参数传递 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 将强制关键字参数放到某个*参数或者单个*后面就能达到这种效果。比如: 14 | 15 | .. code-block:: python 16 | 17 | def recv(maxsize, *, block): 18 | 'Receives a message' 19 | pass 20 | 21 | recv(1024, True) # TypeError 22 | recv(1024, block=True) # Ok 23 | 24 | 利用这种技术,我们还能在接受任意多个位置参数的函数中指定关键字参数。比如: 25 | 26 | .. code-block:: python 27 | 28 | def minimum(*values, clip=None): 29 | m = min(values) 30 | if clip is not None: 31 | m = clip if clip > m else m 32 | return m 33 | 34 | minimum(1, 5, 2, -5, 10) # Returns -5 35 | minimum(1, 5, 2, -5, 10, clip=0) # Returns 0 36 | 37 | ---------- 38 | 讨论 39 | ---------- 40 | 很多情况下,使用强制关键字参数会比使用位置参数表意更加清晰,程序也更加具有可读性。 41 | 例如,考虑下如下一个函数调用: 42 | 43 | .. code-block:: python 44 | 45 | msg = recv(1024, False) 46 | 47 | 如果调用者对recv函数并不是很熟悉,那他肯定不明白那个False参数到底来干嘛用的。 48 | 但是,如果代码变成下面这样子的话就清楚多了: 49 | 50 | .. code-block:: python 51 | 52 | msg = recv(1024, block=False) 53 | 54 | 另外,使用强制关键字参数也会比使用**kwargs参数更好,因为在使用函数help的时候输出也会更容易理解: 55 | 56 | .. code-block:: python 57 | 58 | >>> help(recv) 59 | Help on function recv in module __main__: 60 | recv(maxsize, *, block) 61 | Receives a message 62 | 63 | 强制关键字参数在一些更高级场合同样也很有用。 64 | 例如,它们可以被用来在使用*args和**kwargs参数作为输入的函数中插入参数,9.11小节有一个这样的例子。 65 | -------------------------------------------------------------------------------- /source/c07/p03_attach_informatinal_matadata_to_function_arguments.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 7.3 给函数参数增加元信息 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你写好了一个函数,然后想为这个函数的参数增加一些额外的信息,这样的话其他使用者就能清楚的知道这个函数应该怎么使用。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 使用函数参数注解是一个很好的办法,它能提示程序员应该怎样正确使用这个函数。 14 | 例如,下面有一个被注解了的函数: 15 | 16 | .. code-block:: python 17 | 18 | def add(x:int, y:int) -> int: 19 | return x + y 20 | 21 | python解释器不会对这些注解添加任何的语义。它们不会被类型检查,运行时跟没有加注解之前的效果也没有任何差距。 22 | 然而,对于那些阅读源码的人来讲就很有帮助啦。第三方工具和框架可能会对这些注解添加语义。同时它们也会出现在文档中。 23 | 24 | .. code-block:: python 25 | 26 | >>> help(add) 27 | Help on function add in module __main__: 28 | add(x: int, y: int) -> int 29 | >>> 30 | 31 | 尽管你可以使用任意类型的对象给函数添加注解(例如数字,字符串,对象实例等等),不过通常来讲使用类或者字符串会比较好点。 32 | 33 | ---------- 34 | 讨论 35 | ---------- 36 | 函数注解只存储在函数的 ``__annotations__`` 属性中。例如: 37 | 38 | .. code-block:: python 39 | 40 | >>> add.__annotations__ 41 | {'y': , 'return': , 'x': } 42 | 43 | 尽管注解的使用方法可能有很多种,但是它们的主要用途还是文档。 44 | 因为python并没有类型声明,通常来讲仅仅通过阅读源码很难知道应该传递什么样的参数给这个函数。 45 | 这时候使用注解就能给程序员更多的提示,让他们可以正确的使用函数。 46 | 47 | 参考9.20小节的一个更加高级的例子,演示了如何利用注解来实现多分派(比如重载函数)。 48 | -------------------------------------------------------------------------------- /source/c07/p04_return_multiple_values_from_function.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 7.4 返回多个值的函数 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你希望构造一个可以返回多个值的函数 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 为了能返回多个值,函数直接return一个元组就行了。例如: 14 | 15 | .. code-block:: python 16 | 17 | >>> def myfun(): 18 | ... return 1, 2, 3 19 | ... 20 | >>> a, b, c = myfun() 21 | >>> a 22 | 1 23 | >>> b 24 | 2 25 | >>> c 26 | 3 27 | 28 | ---------- 29 | 讨论 30 | ---------- 31 | 尽管myfun()看上去返回了多个值,实际上是先创建了一个元组然后返回的。 32 | 这个语法看上去比较奇怪,实际上我们使用的是逗号来生成一个元组,而不是用括号。比如下面的: 33 | 34 | .. code-block:: python 35 | 36 | >>> a = (1, 2) # With parentheses 37 | >>> a 38 | (1, 2) 39 | >>> b = 1, 2 # Without parentheses 40 | >>> b 41 | (1, 2) 42 | >>> 43 | 44 | 当我们调用返回一个元组的函数的时候 ,通常我们会将结果赋值给多个变量,就像上面的那样。 45 | 其实这就是1.1小节中我们所说的元组解包。返回结果也可以赋值给单个变量, 46 | 这时候这个变量值就是函数返回的那个元组本身了: 47 | 48 | .. code-block:: python 49 | 50 | >>> x = myfun() 51 | >>> x 52 | (1, 2, 3) 53 | >>> 54 | -------------------------------------------------------------------------------- /source/c07/p06_define_anonymous_or_inline_functions.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 7.6 定义匿名或内联函数 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想为 ``sort()`` 操作创建一个很短的回调函数,但又不想用 ``def`` 去写一个单行函数, 9 | 而是希望通过某个快捷方式以内联方式来创建这个函数。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | 当一些函数很简单,仅仅只是计算一个表达式的值的时候,就可以使用lambda表达式来代替了。比如: 15 | 16 | .. code-block:: python 17 | 18 | >>> add = lambda x, y: x + y 19 | >>> add(2,3) 20 | 5 21 | >>> add('hello', 'world') 22 | 'helloworld' 23 | >>> 24 | 25 | 这里使用的lambda表达式跟下面的效果是一样的: 26 | 27 | .. code-block:: python 28 | 29 | >>> def add(x, y): 30 | ... return x + y 31 | ... 32 | >>> add(2,3) 33 | 5 34 | >>> 35 | lambda表达式典型的使用场景是排序或数据reduce等: 36 | 37 | .. code-block:: python 38 | 39 | >>> names = ['David Beazley', 'Brian Jones', 40 | ... 'Raymond Hettinger', 'Ned Batchelder'] 41 | >>> sorted(names, key=lambda name: name.split()[-1].lower()) 42 | ['Ned Batchelder', 'David Beazley', 'Raymond Hettinger', 'Brian Jones'] 43 | >>> 44 | 45 | ---------- 46 | 讨论 47 | ---------- 48 | 尽管lambda表达式允许你定义简单函数,但是它的使用是有限制的。 49 | 你只能指定单个表达式,它的值就是最后的返回值。也就是说不能包含其他的语言特性了, 50 | 包括多个语句、条件表达式、迭代以及异常处理等等。 51 | 52 | 你可以不使用lambda表达式就能编写大部分python代码。 53 | 但是,当有人编写大量计算表达式值的短小函数或者需要用户提供回调函数的程序的时候, 54 | 你就会看到lambda表达式的身影了。 55 | -------------------------------------------------------------------------------- /source/c08/p04_save_memory_when_create_large_number_instances.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 8.4 创建大量对象时节省内存方法 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你的程序要创建大量(可能上百万)的对象,导致占用很大的内存。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 对于主要是用来当成简单的数据结构的类而言,你可以通过给类添加 ``__slots__`` 属性来极大的减少实例所占的内存。比如: 14 | 15 | .. code-block:: python 16 | 17 | class Date: 18 | __slots__ = ['year', 'month', 'day'] 19 | def __init__(self, year, month, day): 20 | self.year = year 21 | self.month = month 22 | self.day = day 23 | 24 | 当你定义 ``__slots__`` 后,Python就会为实例使用一种更加紧凑的内部表示。 25 | 实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。 26 | 在 ``__slots__`` 中列出的属性名在内部被映射到这个数组的指定下标上。 27 | 使用slots一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在 ``__slots__`` 中定义的那些属性名。 28 | 29 | ---------- 30 | 讨论 31 | ---------- 32 | 使用slots后节省的内存会跟存储属性的数量和类型有关。 33 | 不过,一般来讲,使用到的内存总量和将数据存储在一个元组中差不多。 34 | 为了给你一个直观认识,假设你不使用slots直接存储一个Date实例, 35 | 在64位的Python上面要占用428字节,而如果使用了slots,内存占用下降到156字节。 36 | 如果程序中需要同时创建大量的日期实例,那么这个就能极大的减小内存使用量了。 37 | 38 | 尽管slots看上去是一个很有用的特性,很多时候你还是得减少对它的使用冲动。 39 | Python的很多特性都依赖于普通的基于字典的实现。 40 | 另外,定义了slots后的类不再支持一些普通类特性了,比如多继承。 41 | 大多数情况下,你应该只在那些经常被使用到的用作数据结构的类上定义slots 42 | (比如在程序中需要创建某个类的几百万个实例对象)。 43 | 44 | 关于 ``__slots__`` 的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。 45 | 尽管使用slots可以达到这样的目的,但是这个并不是它的初衷。 46 | ``__slots__`` 更多的是用来作为一个内存优化工具。 47 | 48 | -------------------------------------------------------------------------------- /source/c08/p16_define_more_than_one_constructor_in_class.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 8.16 在类中定义多个构造器 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想实现一个类,除了使用 ``__init__()`` 方法外,还有其他方式可以初始化它。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 为了实现多个构造器,你需要使用到类方法。例如: 14 | 15 | .. code-block:: python 16 | 17 | import time 18 | 19 | class Date: 20 | """方法一:使用类方法""" 21 | # Primary constructor 22 | def __init__(self, year, month, day): 23 | self.year = year 24 | self.month = month 25 | self.day = day 26 | 27 | # Alternate constructor 28 | @classmethod 29 | def today(cls): 30 | t = time.localtime() 31 | return cls(t.tm_year, t.tm_mon, t.tm_mday) 32 | 33 | 直接调用类方法即可,下面是使用示例: 34 | 35 | .. code-block:: python 36 | 37 | a = Date(2012, 12, 21) # Primary 38 | b = Date.today() # Alternate 39 | 40 | ---------- 41 | 讨论 42 | ---------- 43 | 类方法的一个主要用途就是定义多个构造器。它接受一个 ``class`` 作为第一个参数(cls)。 44 | 你应该注意到了这个类被用来创建并返回最终的实例。在继承时也能工作的很好: 45 | 46 | .. code-block:: python 47 | 48 | class NewDate(Date): 49 | pass 50 | 51 | c = Date.today() # Creates an instance of Date (cls=Date) 52 | d = NewDate.today() # Creates an instance of NewDate (cls=NewDate) 53 | 54 | -------------------------------------------------------------------------------- /source/c10/p02_control_the_import_of_everything.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | 10.2 控制模块被全部导入的内容 3 | ============================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 当使用'from module import *' 语句时,希望对从模块或包导出的符号进行精确控制。 9 | 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | 在你的模块中定义一个变量 __all__ 来明确地列出需要导出的内容。 15 | 16 | 举个例子: 17 | 18 | .. code-block:: python 19 | 20 | # somemodule.py 21 | def spam(): 22 | pass 23 | 24 | def grok(): 25 | pass 26 | 27 | blah = 42 28 | # Only export 'spam' and 'grok' 29 | __all__ = ['spam', 'grok'] 30 | 31 | ---------- 32 | 讨论 33 | ---------- 34 | 尽管强烈反对使用 'from module import *', 但是在定义了大量变量名的模块中频繁使用。 35 | 如果你不做任何事, 这样的导入将会导入所有不以下划线开头的。 36 | 另一方面,如果定义了 __all__ , 那么只有被列举出的东西会被导出。 37 | 38 | 39 | 40 | 如果你将 __all__ 定义成一个空列表, 没有东西将被导入。 41 | 如果 __all__ 包含未定义的名字, 在导入时引起AttributeError。 42 | 43 | -------------------------------------------------------------------------------- /source/c10/p07_make_directory_or_zip_runnable_as_main_script.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 10.7 运行目录或压缩文件 3 | =========================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 您有一个已成长为包含多个文件的应用,它已远不再是一个简单的脚本,你想向用户提供一些简单的方法运行这个程序。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 如果你的应用程序已经有多个文件,你可以把你的应用程序放进它自己的目录并添加一个__main__.py文件。 举个例子,你可以像这样创建目录: 14 | 15 | .. code-block:: python 16 | 17 | myapplication/ 18 | spam.py 19 | bar.py 20 | grok.py 21 | __main__.py 22 | 23 | 如果__main__.py存在,你可以简单地在顶级目录运行Python解释器: 24 | 25 | .. code-block:: python 26 | 27 | bash % python3 myapplication 28 | 29 | 解释器将执行__main__.py文件作为主程序。 30 | 31 | 如果你将你的代码打包成zip文件,这种技术同样也适用,举个例子: 32 | 33 | .. code-block:: python 34 | 35 | bash % ls 36 | spam.py bar.py grok.py __main__.py 37 | bash % zip -r myapp.zip *.py 38 | bash % python3 myapp.zip 39 | ... output from __main__.py ... 40 | 41 | ---------- 42 | 讨论 43 | ---------- 44 | 创建一个目录或zip文件并添加__main__.py文件来将一个更大的Python应用打包是可行的。这和作为标准库被安装到Python库的代码包是有一点区别的。相反,这只是让别人执行的代码包。 45 | 46 | 47 | 由于目录和zip文件与正常文件有一点不同,你可能还需要增加一个shell脚本,使执行更加容易。例如,如果代码文件名为myapp.zip,你可以创建这样一个顶级脚本: 48 | 49 | 50 | .. code-block:: bash 51 | 52 | #!/usr/bin/env python3 /usr/local/bin/myapp.zip 53 | 54 | -------------------------------------------------------------------------------- /source/c10/p08_read_datafile_within_package.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | 10.8 读取位于包中的数据文件 3 | ================================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你的包中包含代码需要去读取的数据文件。你需要尽可能地用最便捷的方式来做这件事。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 假设你的包中的文件组织成如下: 14 | 15 | .. code-block:: python 16 | 17 | mypackage/ 18 | __init__.py 19 | somedata.dat 20 | spam.py 21 | 22 | 现在假设spam.py文件需要读取somedata.dat文件中的内容。你可以用以下代码来完成: 23 | 24 | .. code-block:: python 25 | 26 | # spam.py 27 | import pkgutil 28 | data = pkgutil.get_data(__package__, 'somedata.dat') 29 | 30 | 由此产生的变量是包含该文件的原始内容的字节字符串。 31 | 32 | ---------- 33 | 讨论 34 | ---------- 35 | 要读取数据文件,你可能会倾向于编写使用内置的I/ O功能的代码,如open()。但是这种方法也有一些问题。 36 | 37 | 38 | 首先,一个包对解释器的当前工作目录几乎没有控制权。因此,编程时任何I/O操作都必须使用绝对文件名。由于每个模块包含有完整路径的__file__变量,这弄清楚它的路径不是不可能,但它很凌乱。 39 | 40 | 41 | 第二,包通常安装作为.zip或.egg文件,这些文件并不像在文件系统上的一个普通目录里那样被保存。因此,你试图用open()对一个包含数据文件的归档文件进行操作,它根本不会工作。 42 | 43 | 44 | pkgutil.get_data()函数是一个读取数据文件的高级工具,不用管包是如何安装以及安装在哪。它只是工作并将文件内容以字节字符串返回给你 45 | 46 | 47 | get_data()的第一个参数是包含包名的字符串。你可以直接使用包名,也可以使用特殊的变量,比如__package__。第二个参数是包内文件的相对名称。如果有必要,可以使用标准的Unix命名规范到不同的目录,只要最后的目录仍然位于包中。 48 | -------------------------------------------------------------------------------- /source/c10/p10_import_modules_using_name_given_in_string.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | 10.10 通过字符串名导入模块 3 | ================================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想导入一个模块,但是模块的名字在字符串里。你想对字符串调用导入命令。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 使用importlib.import_module()函数来手动导入名字为字符串给出的一个模块或者包的一部分。举个例子: 14 | 15 | .. code-block:: python 16 | 17 | >>> import importlib 18 | >>> math = importlib.import_module('math') 19 | >>> math.sin(2) 20 | 0.9092974268256817 21 | >>> mod = importlib.import_module('urllib.request') 22 | >>> u = mod.urlopen('http://www.python.org') 23 | >>> 24 | 25 | import_module只是简单地执行和import相同的步骤,但是返回生成的模块对象。你只需要将其存储在一个变量,然后像正常的模块一样使用。 26 | 27 | 28 | 如果你正在使用的包,import_module()也可用于相对导入。但是,你需要给它一个额外的参数。例如: 29 | 30 | .. code-block:: python 31 | 32 | import importlib 33 | # Same as 'from . import b' 34 | b = importlib.import_module('.b', __package__) 35 | 36 | ---------- 37 | 讨论 38 | ---------- 39 | 使用import_module()手动导入模块的问题通常出现在以某种方式编写修改或覆盖模块的代码时候。例如,也许你正在执行某种自定义导入机制,需要通过名称来加载一个模块,通过补丁加载代码。 40 | 41 | 42 | 在旧的代码,有时你会看到用于导入的内建函数__import__()。尽管它能工作,但是importlib.import_module() 通常更容易使用。 43 | 44 | 自定义导入过程的高级实例见10.11小节 45 | 46 | -------------------------------------------------------------------------------- /source/c10/p13_installing_packages_just_for_yourself.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | 10.13 安装私有的包 3 | ================================ 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想要安装一个第三方包,但是没有权限将它安装到系统Python库中去。 9 | 或者,你可能想要安装一个供自己使用的包,而不是系统上面所有用户。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | Python有一个用户安装目录,通常类似"~/.local/lib/python3.3/site-packages"。 15 | 要强制在这个目录中安装包,可使用安装选项“--user”。例如: 16 | 17 | .. code-block:: python 18 | 19 | python3 setup.py install --user 20 | 21 | 或者 22 | 23 | .. code-block:: python 24 | 25 | pip install --user packagename 26 | 27 | 在sys.path中用户的“site-packages”目录位于系统的“site-packages”目录之前。 28 | 因此,你安装在里面的包就比系统已安装的包优先级高 29 | (尽管并不总是这样,要取决于第三方包管理器,比如distribute或pip)。 30 | 31 | 32 | ---------- 33 | 讨论 34 | ---------- 35 | 通常包会被安装到系统的site-packages目录中去,路径类似“/usr/local/lib/python3.3/site-packages”。 36 | 不过,这样做需要有管理员权限并且使用sudo命令。 37 | 就算你有这样的权限去执行命令,使用sudo去安装一个新的,可能没有被验证过的包有时候也不安全。 38 | 39 | 安装包到用户目录中通常是一个有效的方案,它允许你创建一个自定义安装。 40 | 41 | 另外,你还可以创建一个虚拟环境,这个我们在下一节会讲到。 42 | -------------------------------------------------------------------------------- /source/c13/p01_accept_input_via_redirect_pips_or_input_files.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 13.1 通过重定向/管道/文件接受输入 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你希望你的脚本接受任何用户认为最简单的输入方式。包括将命令行的输出通过管道传递给该脚本、 9 | 重定向文件到该脚本,或在命令行中传递一个文件名或文件名列表给该脚本。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | Python内置的 ``fileinput`` 模块让这个变得简单。如果你有一个下面这样的脚本: 15 | 16 | .. code-block:: python 17 | 18 | #!/usr/bin/env python3 19 | import fileinput 20 | 21 | with fileinput.input() as f_input: 22 | for line in f_input: 23 | print(line, end='') 24 | 25 | 那么你就能以前面提到的所有方式来为此脚本提供输入。假设你将此脚本保存为 ``filein.py`` 并将其变为可执行文件, 26 | 那么你可以像下面这样调用它,得到期望的输出: 27 | 28 | .. code-block:: bash 29 | 30 | $ ls | ./filein.py # Prints a directory listing to stdout. 31 | $ ./filein.py /etc/passwd # Reads /etc/passwd to stdout. 32 | $ ./filein.py < /etc/passwd # Reads /etc/passwd to stdout. 33 | 34 | ---------- 35 | 讨论 36 | ---------- 37 | ``fileinput.input()`` 创建并返回一个 ``FileInput`` 类的实例。 38 | 该实例除了拥有一些有用的帮助方法外,它还可被当做一个上下文管理器使用。 39 | 因此,整合起来,如果我们要写一个打印多个文件输出的脚本,那么我们需要在输出中包含文件名和行号,如下所示: 40 | 41 | .. code-block:: python 42 | 43 | >>> import fileinput 44 | >>> with fileinput.input('/etc/passwd') as f: 45 | >>> for line in f: 46 | ... print(f.filename(), f.lineno(), line, end='') 47 | ... 48 | /etc/passwd 1 ## 49 | /etc/passwd 2 # User Database 50 | /etc/passwd 3 # 51 | 52 | 53 | 54 | 通过将它作为一个上下文管理器使用,可以确保它不再使用时文件能自动关闭, 55 | 而且我们在之后还演示了 ``FileInput`` 的一些有用的帮助方法来获取输出中的一些其他信息。 56 | -------------------------------------------------------------------------------- /source/c13/p02_terminate_program_with_an_error_message.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 13.2 终止程序并给出错误信息 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想向标准错误打印一条消息并返回某个非零状态码来终止程序运行 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 你有一个程序像下面这样终止,抛出一个 ``SystemExit`` 异常,使用错误消息作为参数。例如: 14 | 15 | .. code-block:: python 16 | 17 | raise SystemExit('It failed!') 18 | 19 | 它会将消息在 ``sys.stderr`` 中打印,然后程序以状态码1退出。 20 | 21 | ---------- 22 | 讨论 23 | ---------- 24 | 本节虽然很短小,但是它能解决在写脚本时的一个常见问题。 25 | 也就是说,当你想要终止某个程序时,你可能会像下面这样写: 26 | 27 | .. code-block:: python 28 | 29 | import sys 30 | sys.stderr.write('It failed!\n') 31 | raise SystemExit(1) 32 | 33 | 如果你直接将消息作为参数传给 ``SystemExit()`` ,那么你可以省略其他步骤, 34 | 比如import语句或将错误消息写入 ``sys.stderr`` 35 | -------------------------------------------------------------------------------- /source/c13/p04_prompt_for_password_at_runtime.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 13.4 运行时弹出密码输入提示 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你写了个脚本,运行时需要一个密码。此脚本是交互式的,因此不能将密码在脚本中硬编码, 9 | 而是需要弹出一个密码输入提示,让用户自己输入。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | 这时候Python的 ``getpass`` 模块正是你所需要的。你可以让你很轻松的弹出密码输入提示, 15 | 并且不会在用户终端回显密码。下面是具体代码: 16 | 17 | .. code-block:: python 18 | 19 | import getpass 20 | 21 | user = getpass.getuser() 22 | passwd = getpass.getpass() 23 | 24 | if svc_login(user, passwd): # You must write svc_login() 25 | print('Yay!') 26 | else: 27 | print('Boo!') 28 | 29 | 在此代码中,``svc_login()`` 是你要实现的处理密码的函数,具体的处理过程你自己决定。 30 | 31 | ---------- 32 | 讨论 33 | ---------- 34 | 注意在前面代码中 ``getpass.getuser()`` 不会弹出用户名的输入提示。 35 | 它会根据该用户的shell环境或者会依据本地系统的密码库(支持 `pwd` 模块的平台)来使用当前用户的登录名, 36 | 37 | 如果你想显示的弹出用户名输入提示,使用内置的 ``input`` 函数: 38 | 39 | .. code-block:: python 40 | 41 | user = input('Enter your username: ') 42 | 43 | 还有一点很重要,有些系统可能不支持 ``getpass()`` 方法隐藏输入密码。 44 | 这种情况下,Python会提前警告你这些问题(例如它会警告你说密码会以明文形式显示) 45 | -------------------------------------------------------------------------------- /source/c13/p05_getting_terminal_size.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 13.5 获取终端的大小 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你需要知道当前终端的大小以便正确的格式化输出。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 使用 ``os.get_terminal_size()`` 函数来做到这一点。 14 | 15 | 代码示例: 16 | 17 | .. code-block:: python 18 | 19 | >>> import os 20 | >>> sz = os.get_terminal_size() 21 | >>> sz 22 | os.terminal_size(columns=80, lines=24) 23 | >>> sz.columns 24 | 80 25 | >>> sz.lines 26 | 24 27 | >>> 28 | 29 | ---------- 30 | 讨论 31 | ---------- 32 | 有太多方式来得知终端大小了,从读取环境变量到执行底层的 ``ioctl()`` 函数等等。 33 | 不过,为什么要去研究这些复杂的办法而不是仅仅调用一个简单的函数呢? 34 | -------------------------------------------------------------------------------- /source/c13/p08_creating_and_unpacking_archives.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 13.8 创建和解压归档文件 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你需要创建或解压常见格式的归档文件(比如.tar, .tgz或.zip) 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | ``shutil`` 模块拥有两个函数—— ``make_archive()`` 和 ``unpack_archive()`` 可派上用场。 14 | 例如: 15 | 16 | .. code-block:: python 17 | 18 | >>> import shutil 19 | >>> shutil.unpack_archive('Python-3.3.0.tgz') 20 | 21 | >>> shutil.make_archive('py33','zip','Python-3.3.0') 22 | '/Users/beazley/Downloads/py33.zip' 23 | >>> 24 | 25 | ``make_archive()`` 的第二个参数是期望的输出格式。 26 | 可以使用 ``get_archive_formats()`` 获取所有支持的归档格式列表。例如: 27 | 28 | .. code-block:: python 29 | 30 | >>> shutil.get_archive_formats() 31 | [('bztar', "bzip2'ed tar-file"), ('gztar', "gzip'ed tar-file"), 32 | ('tar', 'uncompressed tar file'), ('zip', 'ZIP file')] 33 | >>> 34 | 35 | ---------- 36 | 讨论 37 | ---------- 38 | Python还有其他的模块可用来处理多种归档格式(比如tarfile, zipfile, gzip, bz2)的底层细节。 39 | 不过,如果你仅仅只是要创建或提取某个归档,就没有必要使用底层库了。 40 | 可以直接使用 ``shutil`` 中的这些高层函数。 41 | 42 | 这些函数还有很多其他选项,用于日志打印、预检、文件权限等等。 43 | 参考 `shutil文档 `_ -------------------------------------------------------------------------------- /source/c13/p15_luanch_a_web_browser.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 13.15 启动一个WEB浏览器 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想通过脚本启动浏览器并打开指定的URL网页 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | ``webbrowser`` 模块能被用来启动一个浏览器,并且与平台无关。例如: 14 | 15 | .. code-block:: python 16 | 17 | >>> import webbrowser 18 | >>> webbrowser.open('http://www.python.org') 19 | True 20 | >>> 21 | 22 | 它会使用默认浏览器打开指定网页。如果你还想对网页打开方式做更多控制,还可以使用下面这些函数: 23 | 24 | .. code-block:: python 25 | 26 | >>> # Open the page in a new browser window 27 | >>> webbrowser.open_new('http://www.python.org') 28 | True 29 | >>> 30 | 31 | >>> # Open the page in a new browser tab 32 | >>> webbrowser.open_new_tab('http://www.python.org') 33 | True 34 | >>> 35 | 36 | 这样就可以打开一个新的浏览器窗口或者标签,只要浏览器支持就行。 37 | 38 | 如果你想指定浏览器类型,可以使用 ``webbrowser.get()`` 函数来指定某个特定浏览器。例如: 39 | 40 | .. code-block:: python 41 | 42 | >>> c = webbrowser.get('firefox') 43 | >>> c.open('http://www.python.org') 44 | True 45 | >>> c.open_new_tab('http://docs.python.org') 46 | True 47 | >>> 48 | 49 | 对于支持的浏览器名称列表可查阅`Python文档 `_ 50 | 51 | ---------- 52 | 讨论 53 | ---------- 54 | 在脚本中打开浏览器有时候会很有用。例如,某个脚本执行某个服务器发布任务, 55 | 你想快速打开一个浏览器来确保它已经正常运行了。 56 | 或者是某个程序以HTML网页格式输出数据,你想打开浏览器查看结果。 57 | 不管是上面哪种情况,使用 ``webbrowser`` 模块都是一个简单实用的解决方案。 58 | 59 | -------------------------------------------------------------------------------- /source/c14/p10_reraising_the_last_exception.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 14.10 重新抛出被捕获的异常 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你在一个 ``except`` 块中捕获了一个异常,现在想重新抛出它。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 简单的使用一个单独的 ``rasie`` 语句即可,例如: 14 | 15 | :: 16 | 17 | >>> def example(): 18 | ... try: 19 | ... int('N/A') 20 | ... except ValueError: 21 | ... print("Didn't work") 22 | ... raise 23 | ... 24 | 25 | >>> example() 26 | Didn't work 27 | Traceback (most recent call last): 28 | File "", line 1, in 29 | File "", line 3, in example 30 | ValueError: invalid literal for int() with base 10: 'N/A' 31 | >>> 32 | 33 | ---------- 34 | 讨论 35 | ---------- 36 | 这个问题通常是当你需要在捕获异常后执行某个操作(比如记录日志、清理等),但是之后想将异常传播下去。 37 | 一个很常见的用法是在捕获所有异常的处理器中: 38 | 39 | .. code-block:: python 40 | 41 | try: 42 | ... 43 | except Exception as e: 44 | # Process exception information in some way 45 | ... 46 | 47 | # Propagate the exception 48 | raise 49 | 50 | -------------------------------------------------------------------------------- /source/c15/p07_release_the_gil_in_c_extensions.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 15.7 从C扩展中释放全局锁 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想让C扩展代码和Python解释器中的其他进程一起正确的执行, 9 | 那么你就需要去释放并重新获取全局解释器锁(GIL)。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | 在C扩展代码中,GIL可以通过在代码中插入下面这样的宏来释放和重新获取: 15 | 16 | :: 17 | 18 | #include "Python.h" 19 | ... 20 | 21 | PyObject *pyfunc(PyObject *self, PyObject *args) { 22 | ... 23 | Py_BEGIN_ALLOW_THREADS 24 | // Threaded C code. Must not use Python API functions 25 | ... 26 | Py_END_ALLOW_THREADS 27 | ... 28 | return result; 29 | } 30 | 31 | ---------- 32 | 讨论 33 | ---------- 34 | 只有当你确保没有Python C API函数在C中执行的时候你才能安全的释放GIL。 35 | GIL需要被释放的常见的场景是在计算密集型代码中需要在C数组上执行计算(比如在numpy中) 36 | 或者是要执行阻塞的I/O操作时(比如在一个文件描述符上读取或写入时)。 37 | 38 | 当GIL被释放后,其他Python线程才被允许在解释器中执行。 39 | ``Py_END_ALLOW_THREADS`` 宏会阻塞执行直到调用线程重新获取了GIL。 40 | 41 | -------------------------------------------------------------------------------- /source/c15/p08_mix_threads_from_c_and_python.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 15.8 C和Python中的线程混用 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你有一个程序需要混合使用C、Python和线程, 9 | 有些线程是在C中创建的,超出了Python解释器的控制范围。 10 | 并且一些线程还使用了Python C API中的函数。 11 | 12 | ---------- 13 | 解决方案 14 | ---------- 15 | 如果你想将C、Python和线程混合在一起,你需要确保正确的初始化和管理Python的全局解释器锁(GIL)。 16 | 要想这样做,可以将下列代码放到你的C代码中并确保它在任何线程被创建之前被调用。 17 | 18 | :: 19 | 20 | #include 21 | ... 22 | if (!PyEval_ThreadsInitialized()) { 23 | PyEval_InitThreads(); 24 | } 25 | ... 26 | 27 | 对于任何调用Python对象或Python C API的C代码,确保你首先已经正确地获取和释放了GIL。 28 | 这可以用 ``PyGILState_Ensure()`` 和 ``PyGILState_Release()`` 来做到,如下所示: 29 | 30 | :: 31 | 32 | ... 33 | /* Make sure we own the GIL */ 34 | PyGILState_STATE state = PyGILState_Ensure(); 35 | 36 | /* Use functions in the interpreter */ 37 | ... 38 | /* Restore previous GIL state and return */ 39 | PyGILState_Release(state); 40 | ... 41 | 42 | 每次调用 ``PyGILState_Ensure()`` 都要相应的调用 ``PyGILState_Release()`` . 43 | 44 | ---------- 45 | 讨论 46 | ---------- 47 | 在涉及到C和Python的高级程序中,很多事情一起做是很常见的—— 48 | 可能是对C、Python、C线程、Python线程的混合使用。 49 | 只要你确保解释器被正确的初始化,并且涉及到解释器的C代码执行了正确的GIL管理,应该没什么问题。 50 | 51 | 要注意的是调用 ``PyGILState_Ensure()`` 并不会立刻抢占或中断解释器。 52 | 如果有其他代码正在执行,这个函数被中断知道那个执行代码释放掉GIL。 53 | 在内部,解释器会执行周期性的线程切换,因此如果其他线程在执行, 54 | 调用者最终还是可以运行的(尽管可能要先等一会)。 55 | -------------------------------------------------------------------------------- /source/c15/p18_pass_open_files_to_c_extensions.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 15.18 传递已打开的文件给C扩展 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你在Python中有一个打开的文件对象,但是需要将它传给要使用这个文件的C扩展。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 要将一个文件转换为一个整型的文件描述符,使用 ``PyFile_FromFd()`` ,如下: 14 | 15 | :: 16 | 17 | PyObject *fobj; /* File object (already obtained somehow) */ 18 | int fd = PyObject_AsFileDescriptor(fobj); 19 | if (fd < 0) { 20 | return NULL; 21 | } 22 | 23 | 结果文件描述符是通过调用 ``fobj`` 中的 ``fileno()`` 方法获得的。 24 | 因此,任何以这种方式暴露给一个描述器的对象都适用(比如文件、套接字等)。 25 | 一旦你有了这个描述器,它就能被传递给多个低级的可处理文件的C函数。 26 | 27 | 如果你需要转换一个整型文件描述符为一个Python对象,适用下面的 ``PyFile_FromFd()`` : 28 | 29 | :: 30 | 31 | int fd; /* Existing file descriptor (already open) */ 32 | PyObject *fobj = PyFile_FromFd(fd, "filename","r",-1,NULL,NULL,NULL,1); 33 | 34 | ``PyFile_FromFd()`` 的参数对应内置的 ``open()`` 函数。 35 | NULL表示编码、错误和换行参数使用默认值。 36 | 37 | ---------- 38 | 讨论 39 | ---------- 40 | 如果将Python中的文件对象传给C,有一些注意事项。 41 | 首先,Python通过 ``io`` 模块执行自己的I/O缓冲。 42 | 在传递任何类型的文件描述符给C之前,你都要首先在相应文件对象上刷新I/O缓冲。 43 | 不然的话,你会打乱文件系统上面的数据。 44 | 45 | 其次,你需要特别注意文件的归属者以及关闭文件的职责。 46 | 如果一个文件描述符被传给C,但是在Python中还在被使用着,你需要确保C没有意外的关闭它。 47 | 类似的,如果一个文件描述符被转换为一个Python文件对象,你需要清楚谁应该去关闭它。 48 | ``PyFile_FromFd()`` 的最后一个参数被设置成1,用来指出Python应该关闭这个文件。 49 | 50 | 如果你需要从C标准I/O库中使用如 ``fdopen()`` 函数来创建不同类型的文件对象比如 ``FILE *`` 对象, 51 | 你需要特别小心了。这样做会在I/O堆栈中产生两个完全不同的I/O缓冲层 52 | (一个是来自Python的 ``io`` 模块,另一个来自C的 ``stdio`` )。 53 | 像C中的 ``fclose()`` 会关闭Python要使用的文件。 54 | 如果让你选的话,你应该会选择去构建一个扩展代码来处理底层的整型文件描述符, 55 | 而不是使用来自的高层抽象功能。 56 | -------------------------------------------------------------------------------- /source/c15/p20_consuming_an_iterable_from_c.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 15.20 处理C语言中的可迭代对象 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 你想写C扩展代码处理来自任何可迭代对象如列表、元组、文件或生成器中的元素。 9 | 10 | ---------- 11 | 解决方案 12 | ---------- 13 | 下面是一个C扩展函数例子,演示了怎样处理可迭代对象中的元素: 14 | 15 | :: 16 | 17 | static PyObject *py_consume_iterable(PyObject *self, PyObject *args) { 18 | PyObject *obj; 19 | PyObject *iter; 20 | PyObject *item; 21 | 22 | if (!PyArg_ParseTuple(args, "O", &obj)) { 23 | return NULL; 24 | } 25 | if ((iter = PyObject_GetIter(obj)) == NULL) { 26 | return NULL; 27 | } 28 | while ((item = PyIter_Next(iter)) != NULL) { 29 | /* Use item */ 30 | ... 31 | Py_DECREF(item); 32 | } 33 | 34 | Py_DECREF(iter); 35 | return Py_BuildValue(""); 36 | } 37 | 38 | ---------- 39 | 讨论 40 | ---------- 41 | 本节中的代码和Python中对应代码类似。 42 | ``PyObject_GetIter()`` 的调用和调用 ``iter()`` 一样可获得一个迭代器。 43 | ``PyIter_Next()`` 函数调用 ``next`` 方法返回下一个元素或NULL(如果没有元素了)。 44 | 要注意正确的内存管理—— ``Py_DECREF()`` 需要同时在产生的元素和迭代器对象本身上同时被调用, 45 | 以避免出现内存泄露。 46 | -------------------------------------------------------------------------------- /source/c15/p21_diagnosing_segmentation_faults.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | 15.21 诊断分段错误 3 | ============================== 4 | 5 | ---------- 6 | 问题 7 | ---------- 8 | 解释器因为某个分段错误、总线错误、访问越界或其他致命错误而突然间奔溃。 9 | 你想获得Python堆栈信息,从而找出在发生错误的时候你的程序运行点。 10 | 11 | ---------- 12 | 解决方案 13 | ---------- 14 | ``faulthandler`` 模块能被用来帮你解决这个问题。 15 | 在你的程序中引入下列代码: 16 | 17 | .. code-block:: python 18 | 19 | import faulthandler 20 | faulthandler.enable() 21 | 22 | 另外还可以像下面这样使用 ``-Xfaulthandler`` 来运行Python: 23 | 24 | :: 25 | 26 | bash % python3 -Xfaulthandler program.py 27 | 28 | 最后,你可以设置 ``PYTHONFAULTHANDLER`` 环境变量。 29 | 开启faulthandler后,在C扩展中的致命错误会导致一个Python错误堆栈被打印出来。例如: 30 | 31 | :: 32 | 33 | Fatal Python error: Segmentation fault 34 | 35 | Current thread 0x00007fff71106cc0: 36 | File "example.py", line 6 in foo 37 | File "example.py", line 10 in bar 38 | File "example.py", line 14 in spam 39 | File "example.py", line 19 in 40 | Segmentation fault 41 | 42 | 尽管这个并不能告诉你C代码中哪里出错了,但是至少能告诉你Python里面哪里有错。 43 | 44 | ---------- 45 | 讨论 46 | ---------- 47 | faulthandler会在Python代码执行出错的时候向你展示跟踪信息。 48 | 至少,它会告诉你出错时被调用的最顶级扩展函数是哪个。 49 | 在pdb和其他Python调试器的帮助下,你就能追根溯源找到错误所在的位置了。 50 | 51 | faulthandler不会告诉你任何C语言中的错误信息。 52 | 因此,你需要使用传统的C调试器,比如gdb。 53 | 不过,在faulthandler追踪信息可以让你去判断从哪里着手。 54 | 还要注意的是在C中某些类型的错误可能不太容易恢复。 55 | 例如,如果一个C扩展丢弃了程序堆栈信息,它会让faulthandler不可用, 56 | 那么你也得不到任何输出(除了程序奔溃外)。 57 | 58 | -------------------------------------------------------------------------------- /source/chapters/p01_data_structures_algorithms.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第一章:数据结构和算法 3 | ============================= 4 | 5 | Python 提供了大量的内置数据结构,包括列表,集合以及字典。大多数情况下使用这些数据结构是很简单的。 6 | 但是,我们也会经常碰到到诸如查询,排序和过滤等等这些普遍存在的问题。 7 | 因此,这一章的目的就是讨论这些比较常见的问题和算法。 8 | 另外,我们也会给出在集合模块 ``collections`` 当中操作这些数据结构的方法。 9 | 10 | 11 | 12 | 13 | .. toctree:: 14 | :maxdepth: 1 15 | :glob: 16 | 17 | ../c01/* 18 | -------------------------------------------------------------------------------- /source/chapters/p02_strings_and_text.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第二章:字符串和文本 3 | ============================= 4 | 5 | 几乎所有有用的程序都会涉及到某些文本处理,不管是解析数据还是产生输出。 6 | 这一章将重点关注文本的操作处理,比如提取字符串,搜索,替换以及解析等。 7 | 大部分的问题都能简单的调用字符串的内建方法完成。 8 | 但是,一些更为复杂的操作可能需要正则表达式或者强大的解析器,所有这些主题我们都会详细讲解。 9 | 并且在操作Unicode时候碰到的一些棘手的问题在这里也会被提及到。 10 | 11 | 12 | Contents: 13 | 14 | .. toctree:: 15 | :maxdepth: 1 16 | :glob: 17 | 18 | ../c02/* 19 | -------------------------------------------------------------------------------- /source/chapters/p03_numbers_dates_times.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第三章:数字日期和时间 3 | ============================= 4 | 5 | 在Python中执行整数和浮点数的数学运算时很简单的。 6 | 尽管如此,如果你需要执行分数、数组或者是日期和时间的运算的话,就得做更多的工作了。 7 | 本章集中讨论的就是这些主题。 8 | 9 | 10 | Contents: 11 | 12 | .. toctree:: 13 | :maxdepth: 1 14 | :glob: 15 | 16 | ../c03/* 17 | -------------------------------------------------------------------------------- /source/chapters/p04_iterators_and_generators.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第四章:迭代器与生成器 3 | ============================= 4 | 5 | 迭代是Python最强大的功能之一。初看起来,你可能会简单的认为迭代只不过是处理序列中元素的一种方法。 6 | 然而,绝非仅仅就是如此,还有很多你可能不知道的, 7 | 比如创建你自己的迭代器对象,在itertools模块中使用有用的迭代模式,构造生成器函数等等。 8 | 这一章目的就是向你展示跟迭代有关的各种常见问题。 9 | 10 | 11 | Contents: 12 | 13 | .. toctree:: 14 | :maxdepth: 1 15 | :glob: 16 | 17 | ../c04/* 18 | -------------------------------------------------------------------------------- /source/chapters/p05_files_and_io.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第五章:文件与IO 3 | ============================= 4 | 5 | 所有程序都要处理输入和输出。 6 | 这一章将涵盖处理不同类型的文件,包括文本和二进制文件,文件编码和其他相关的内容。 7 | 对文件名和目录的操作也会涉及到。 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | :glob: 14 | 15 | ../c05/* 16 | -------------------------------------------------------------------------------- /source/chapters/p06_data_encoding_and_process.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第六章:数据编码和处理 3 | ============================= 4 | 5 | 这一章主要讨论使用Python处理各种不同方式编码的数据,比如CSV文件,JSON,XML和二进制包装记录。 6 | 和数据结构那一章不同的是,这章不会讨论特殊的算法问题,而是关注于怎样获取和存储这些格式的数据。 7 | 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | :glob: 14 | 15 | ../c06/* 16 | -------------------------------------------------------------------------------- /source/chapters/p07_functions.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第七章:函数 3 | ============================= 4 | 5 | 使用 ``def`` 语句定义函数是所有程序的基础。 6 | 本章的目标是讲解一些更加高级和不常见的函数定义与使用模式。 7 | 涉及到的内容包括默认参数、任意数量参数、强制关键字参数、注解和闭包。 8 | 另外,一些高级的控制流和利用回调函数传递数据的技术在这里也会讲解到。 9 | 10 | 11 | Contents: 12 | 13 | .. toctree:: 14 | :maxdepth: 1 15 | :glob: 16 | 17 | ../c07/* 18 | -------------------------------------------------------------------------------- /source/chapters/p08_classes_and_objects.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第八章:类与对象 3 | ============================= 4 | 5 | 本章主要关注点的是和类定义有关的常见编程模型。包括让对象支持常见的Python特性、特殊方法的使用、 6 | 类封装技术、继承、内存管理以及有用的设计模式。 7 | 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | :glob: 14 | 15 | ../c08/* 16 | -------------------------------------------------------------------------------- /source/chapters/p09_meta_programming.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第九章:元编程 3 | ============================= 4 | 5 | 软件开发领域中最经典的口头禅就是“don’t repeat yourself”。 6 | 也就是说,任何时候当你的程序中存在高度重复(或者是通过剪切复制)的代码时,都应该想想是否有更好的解决方案。 7 | 在Python当中,通常都可以通过元编程来解决这类问题。 8 | 简而言之,元编程就是关于创建操作源代码(比如修改、生成或包装原来的代码)的函数和类。 9 | 主要技术是使用装饰器、类装饰器和元类。不过还有一些其他技术, 10 | 包括签名对象、使用 ``exec()`` 执行代码以及对内部函数和类的反射技术等。 11 | 本章的主要目的是向大家介绍这些元编程技术,并且给出实例来演示它们是怎样定制化你的源代码行为的。 12 | 13 | 14 | Contents: 15 | 16 | .. toctree:: 17 | :maxdepth: 1 18 | :glob: 19 | 20 | ../c09/* 21 | -------------------------------------------------------------------------------- /source/chapters/p10_modules_and_packages.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第十章:模块与包 3 | ============================= 4 | 5 | 模块与包是任何大型程序的核心,就连Python安装程序本身也是一个包。本章重点涉及有关模块和包的常用编程技术,例如如何组织包、把大型模块分割成多个文件、创建命名空间包。同时,也给出了让你自定义导入语句的秘籍。 6 | 7 | 8 | Contents: 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | :glob: 13 | 14 | ../c10/* 15 | -------------------------------------------------------------------------------- /source/chapters/p11_network_and_web_program.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第十一章:网络与Web编程 3 | ============================= 4 | 5 | 本章是关于在网络应用和分布式应用中使用的各种主题。主题划分为使用Python编写客户端程序来访问已有的服务,以及使用Python实现网络服务端程序。也给出了一些常见的技术,用于编写涉及协同或通信的的代码。 6 | 7 | Contents: 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | :glob: 12 | 13 | ../c11/* 14 | -------------------------------------------------------------------------------- /source/chapters/p12_concurrency.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第十二章:并发编程 3 | ============================= 4 | 5 | 对于并发编程, Python有多种长期支持的方法, 包括多线程, 调用子进程, 以及各种各样的关于生成器函数的技巧. 6 | 这一章将会给出并发编程各种方面的技巧, 包括通用的多线程技术以及并行计算的实现方法. 7 | 8 | 像经验丰富的程序员所知道的那样, 大家担心并发的程序有潜在的危险. 9 | 因此, 本章的主要目标之一是给出更加可信赖和易调试的代码. 10 | 11 | Contents: 12 | 13 | .. toctree:: 14 | :maxdepth: 1 15 | :glob: 16 | 17 | ../c12/* 18 | -------------------------------------------------------------------------------- /source/chapters/p13_utility_script_and_system_manage.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第十三章:脚本编程与系统管理 3 | ============================= 4 | 5 | 许多人使用Python作为一个shell脚本的替代,用来实现常用系统任务的自动化,如文件的操作,系统的配置等。本章的主要目标是描述关于编写脚本时候经常遇到的一些功能。例如,解析命令行选项、获取有用的系统配置数据等等。第5章也包含了与文件和目录相关的一般信息。 6 | 7 | Contents: 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | :glob: 12 | 13 | ../c13/* 14 | -------------------------------------------------------------------------------- /source/chapters/p14_test_debug_and_exceptions.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | 第十四章:测试、调试和异常 3 | ============================= 4 | 5 | 试验还是很棒的,但是调试?就没那么有趣了。事实是,在Python测试代码之前没有编译器来分析你的代码,因此使得测试成为开发的一个重要部分。本章的目标是讨论一些关于测试、调试和异常处理的常见问题。但是并不是为测试驱动开发或者单元测试模块做一个简要的介绍。因此,笔者假定读者熟悉测试概念。 6 | 7 | 8 | Contents: 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | :glob: 13 | 14 | ../c14/* 15 | -------------------------------------------------------------------------------- /source/copyright.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Copyright 3 | ==================== 4 | 5 | | 书名: 《Python Cookbook》3rd Edition 6 | | 作者: David Beazley, Brian K. Jones 7 | | 译者: 熊能 8 | | 版本: 第3版 9 | | 出版社: O’Reilly Media, Inc. 10 | | 出版日期: 2013年5月08日 11 | | Copyright © 2013 David Beazley and Brian Jones. All rights reserved. 12 | 13 | | 14 | 15 | | 更多发布信息请参考 http://oreilly.com/catalog/errata.csp?isbn=9781449340377 16 | -------------------------------------------------------------------------------- /source/index.rst: -------------------------------------------------------------------------------- 1 | .. python3-cookbook documentation master file, created by 2 | sphinx-quickstart on Tue Aug 19 03:21:45 2014. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | ================================================ 7 | Python Cookbook 3rd Edition Documentation 8 | ================================================ 9 | 10 | Contents: 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | :glob: 15 | 16 | copyright 17 | preface 18 | chapters/* 19 | aboutme 20 | roadmap 21 | -------------------------------------------------------------------------------- /source/roadmap.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Roadmap 3 | =========== 4 | 5 | 2014/08/10 - 2014/08/31: 6 | 7 | :: 8 | 9 | | github项目搭建,readthedocs文档生成。 10 | | 整个项目的框架完成 11 | 12 | 2014/09/01 - 2014/10/31: 13 | 14 | :: 15 | 16 | | 前4章翻译完成 17 | 18 | 19 | 2014/11/01 - 2015/01/31: 20 | 21 | :: 22 | 23 | | 前8章翻译完成 24 | 25 | 26 | 2015/02/01 - 2015/03/31: 27 | 28 | :: 29 | 30 | | 前9章翻译完成 31 | 32 | 2015/04/01 - 2015/05/31: 33 | 34 | :: 35 | 36 | | 10章翻译完成 37 | 38 | 2015/06/01 - 2015/06/30: 39 | 40 | :: 41 | 42 | | 11章翻译完成 43 | 44 | 45 | 2015/07/01 - 2015/07/31: 46 | 47 | :: 48 | 49 | | 12章翻译完成 50 | 51 | 52 | 2015/08/01 - 2015/08/31: 53 | 54 | :: 55 | 56 | | 13章翻译完成 57 | 58 | 59 | 2015/09/01 - 2015/11/30: 60 | 61 | :: 62 | 63 | | 14章翻译完成 64 | 65 | 66 | 2015/12/01 - 2015/12/20: 67 | 68 | :: 69 | 70 | | 15章翻译完成 71 | 72 | 73 | 2015/12/21 - 2015/12/31: 74 | 75 | :: 76 | 77 | | 对全部翻译进行校对一次 78 | 79 | 80 | 2016/01/01 - 2016/01/10: 81 | 82 | :: 83 | 84 | | 对外公开发布完整版1.0,包括转换后的PDF文件 85 | 86 | --------------------------------------------------------------------------------