পাইথন ডিরেক্টরি ডিরেক্টরি গাছ কাঠামো?
আমরা সাধারণত GNU ট্রি ব্যবহার করতে পছন্দ করি তবে আমাদের সর্বদা tree
প্রতিটি সিস্টেমে থাকে না এবং কখনও কখনও পাইথন 3 পাওয়া যায়। এখানে একটি ভাল উত্তর সহজেই অনুলিপি-পেস্ট করা এবং GNU tree
প্রয়োজন হিসাবে তৈরি করা যেতে পারে ।
tree
এর আউটপুট এর মত দেখাচ্ছে:
$ tree
.
├── package
│ ├── __init__.py
│ ├── __main__.py
│ ├── subpackage
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ └── module.py
│ └── subpackage2
│ ├── __init__.py
│ ├── __main__.py
│ └── module2.py
└── package2
└── __init__.py
4 directories, 9 files
আমি যে ডিরেক্টরিটি কল করি তার অধীনে আমি আমার ডিরেক্টরি ডিরেক্টরিতে উপরের ডিরেক্টরি কাঠামোটি তৈরি করেছি pyscratch
।
আমি এখানে অন্যান্য উত্তরগুলিও দেখতে পাই যা এই ধরণের আউটপুটটিতে পৌঁছায় তবে আমি মনে করি সহজ, আরও আধুনিক কোড এবং অলসতার সাথে পদ্ধতির মূল্যায়নের সাথে আমরা আরও ভাল করতে পারি।
পাইথনে গাছ
শুরু করার জন্য, এর একটি উদাহরণ ব্যবহার করুন
- পাইথন 3
Path
অবজেক্ট ব্যবহার করে
- ব্যবহার করে
yield
এবংyield from
এক্সপ্রেশন (যে জেনারেটরের ফাংশন তৈরি করুন)
- মার্জিত সরলতার জন্য পুনরাবৃত্তি ব্যবহার করে
- অতিরিক্ত স্পষ্টতার জন্য মন্তব্য এবং কিছু ধরণের টিকা ব্যবহার করে
from pathlib import Path
# prefix components:
space = ' '
branch = '│ '
# pointers:
tee = '├── '
last = '└── '
def tree(dir_path: Path, prefix: str=''):
"""A recursive generator, given a directory Path object
will yield a visual tree structure line by line
with each line prefixed by the same characters
"""
contents = list(dir_path.iterdir())
# contents each get pointers that are ├── with a final └── :
pointers = [tee] * (len(contents) - 1) + [last]
for pointer, path in zip(pointers, contents):
yield prefix + pointer + path.name
if path.is_dir(): # extend the prefix and recurse:
extension = branch if pointer == tee else space
# i.e. space because last, └── , above so no more |
yield from tree(path, prefix=prefix+extension)
এবং এখন:
for line in tree(Path.home() / 'pyscratch'):
print(line)
কপি করে প্রিন্ট:
├── package
│ ├── __init__.py
│ ├── __main__.py
│ ├── subpackage
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ └── module.py
│ └── subpackage2
│ ├── __init__.py
│ ├── __main__.py
│ └── module2.py
└── package2
└── __init__.py
আমাদের প্রতিটি ডিরেক্টরি একটি তালিকাতে রূপায়িত করতে হবে কারণ এটি কতটা দীর্ঘ তা আমাদের জানতে হবে, তবে পরে আমরা তালিকাটি ফেলে দিই। গভীর এবং বিস্তৃত পুনরাবৃত্তির জন্য এটি যথেষ্ট অলস হওয়া উচিত।
উপরোক্ত কোডগুলি, মন্তব্য সহ, আমরা এখানে কী করছি তা সম্পূর্ণরূপে বোঝার জন্য যথেষ্ট হওয়া উচিত তবে আপনার যদি প্রয়োজন হয় তবে এটি আরও ভালভাবে গ্রাক করতে কোনও ডিবাগার দিয়ে এটিকে পদক্ষেপে নির্দ্বিধায় অনুভব করতে পারেন।
আরো বৈশিষ্ট্য
এখন জিএনইউ tree
আমাদের কয়েকটি কার্যকর বৈশিষ্ট্য দেয় যা আমি এই ফাংশনটির সাথে রাখতে চাই:
- প্রথমে সাবজেক্ট ডিরেক্টরি নাম মুদ্রণ করে (স্বয়ংক্রিয়ভাবে এটি করা হয়, আমাদের হয় না)
- প্রিন্ট গণনা
n directories, m files
- পুনরাবৃত্তি সীমাবদ্ধ করার বিকল্প,
-L level
- কেবল ডিরেক্টরিতে সীমাবদ্ধ করার বিকল্প,
-d
এছাড়াও, যখন বিশাল গাছ থাকে তখন islice
পাঠ্যটি দিয়ে আপনার দোভাষীকে লক করা এড়ানোর জন্য পুনরাবৃত্তিকে সীমাবদ্ধ করা কার্যকর হয় (যেমন: আউটপুটটি কার্যকর হওয়ার জন্য খুব ভার্জবস হয়ে যায়)। আমরা এটিকে নির্বিচারে উচ্চতর করতে পারি ডিফল্ট - বলে 1000
।
সুতরাং আসুন পূর্ববর্তী মন্তব্যগুলি মুছে ফেলা এবং এই কার্যকারিতাটি পূরণ করুন:
from pathlib import Path
from itertools import islice
space = ' '
branch = '│ '
tee = '├── '
last = '└── '
def tree(dir_path: Path, level: int=-1, limit_to_directories: bool=False,
length_limit: int=1000):
"""Given a directory Path object print a visual tree structure"""
dir_path = Path(dir_path) # accept string coerceable to Path
files = 0
directories = 0
def inner(dir_path: Path, prefix: str='', level=-1):
nonlocal files, directories
if not level:
return # 0, stop iterating
if limit_to_directories:
contents = [d for d in dir_path.iterdir() if d.is_dir()]
else:
contents = list(dir_path.iterdir())
pointers = [tee] * (len(contents) - 1) + [last]
for pointer, path in zip(pointers, contents):
if path.is_dir():
yield prefix + pointer + path.name
directories += 1
extension = branch if pointer == tee else space
yield from inner(path, prefix=prefix+extension, level=level-1)
elif not limit_to_directories:
yield prefix + pointer + path.name
files += 1
print(dir_path.name)
iterator = inner(dir_path, level=level)
for line in islice(iterator, length_limit):
print(line)
if next(iterator, None):
print(f'... length_limit, {length_limit}, reached, counted:')
print(f'\n{directories} directories' + (f', {files} files' if files else ''))
এবং এখন আমরা একই ধরণের আউটপুট পেতে পারি tree
:
tree(Path.home() / 'pyscratch')
কপি করে প্রিন্ট:
pyscratch
├── package
│ ├── __init__.py
│ ├── __main__.py
│ ├── subpackage
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ └── module.py
│ └── subpackage2
│ ├── __init__.py
│ ├── __main__.py
│ └── module2.py
└── package2
└── __init__.py
4 directories, 9 files
এবং আমরা স্তরগুলিতে সীমাবদ্ধ করতে পারি:
tree(Path.home() / 'pyscratch', level=2)
কপি করে প্রিন্ট:
pyscratch
├── package
│ ├── __init__.py
│ ├── __main__.py
│ ├── subpackage
│ └── subpackage2
└── package2
└── __init__.py
4 directories, 3 files
এবং আমরা আউটপুট ডিরেক্টরিগুলিতে সীমাবদ্ধ করতে পারি:
tree(Path.home() / 'pyscratch', level=2, limit_to_directories=True)
কপি করে প্রিন্ট:
pyscratch
├── package
│ ├── subpackage
│ └── subpackage2
└── package2
4 directories
ভূতাপেক্ষ
পূর্ববর্তী ক্ষেত্রে, আমরা path.glob
মিলের জন্য ব্যবহার করতে পারতাম । আমরা সম্ভবত path.rglob
পুনরাবৃত্ত গ্লোববিংয়ের জন্যও ব্যবহার করতে পারি, তবে এর জন্য পুনর্লিখনের প্রয়োজন হবে। আমরা ব্যবহার করতে পারেitertools.tee
ডিরেক্টরি সামগ্রীর তালিকা তৈরির পরিবর্তেও , তবে এটিতে নেতিবাচক ট্রেডঅফস থাকতে পারে এবং সম্ভবত কোডটিকে আরও জটিল করে তুলবে।
মন্তব্য স্বাগত!