পাইথনের কোনও বস্তু বাইটস জাতীয় বস্তু কিনা তা নির্ধারণের সঠিক উপায় কী?


93

আমার কাছে এমন কোড রয়েছে যা প্রত্যাশা করে strতবে bytesনিম্নলিখিত পদ্ধতিতে পাস হওয়ার ক্ষেত্রে এটি পরিচালনা করবে :

if isinstance(data, bytes):
    data = data.decode()

দুর্ভাগ্যক্রমে, এটি ক্ষেত্রে কাজ করে না bytearray। সেখানে কিনা একটি বস্তু হয় পরীক্ষা করার জন্য আর জেনেরিক উপায় আছে কি bytesবা bytearray, অথবা আমি শুধু উভয়ের জন্য পরীক্ষা করা উচিত? আমার hasattr('decode')যেমন মনে হবে তত খারাপ?


6
ব্যক্তিগতভাবে আমি পরের লোকের মতো পাইথনের হাঁসের টাইপিং পছন্দ করি। তবে যদি আপনাকে নিজের ইনপুট আর্গুমেন্টগুলি পরীক্ষা করার এবং বিভিন্ন ধরণের কাছে জোর করা দরকার হয়, তবে আপনি আর টাইপ করতে পছন্দ করবেন না - আপনি কেবল নিজের কোডটি বজায় রাখা আরও কঠিন করে তুলছেন। আমার পরামর্শ এখানে (এবং অন্যরা একমত হতে পারে) হতে হবে একাধিক ফাংশন করা (যা ধরণের জবরদস্তি পরিচালনা করে এবং একটি বেস প্রয়োগের জন্য প্রতিনিধি)।
মিগিলসন

(1) লিগ্যাসি পাইথন 2 কোডের সাথে সামঞ্জস্যের জন্য আপনার প্রয়োজন না হলে; একসাথে পাঠ্য এবং বাইনারি উভয় ডেটা গ্রহণ করা এড়িয়ে চলুন। যদি আপনার ফাংশন পাঠ্যের সাথে কাজ করে তবে তা কেবল গ্রহণযোগ্য হওয়া উচিত str। কিছু অন্যান্য কোড যত তাড়াতাড়ি সম্ভব ইনপুটটিতে বাইটস থেকে ইউনিকোডে রূপান্তর করা উচিত। (২) পাইথনে "বাইটস-লাইক" এর একটি বিশেষ অর্থ রয়েছে (বস্তুগুলি যা বাফার প্রোটোকলকে সমর্থন করে (কেবলমাত্র সি))
jfs

মূল সমস্যাটি হ'ল পাইথন 2 এ এই ফাংশনটি কাজ করে না, যেখানে একটি সাধারণ ASCII স্ট্রিং <বাইটস> পরীক্ষায় উত্তীর্ণ হয়!
অ্যাপোস্টোলোস

উত্তর:


75

আপনি এখানে ব্যবহার করতে পারেন কয়েকটি পন্থা রয়েছে।

হাঁসের টাইপিং

পাইথন যেহেতু হাঁসের টাইপড টাইপ করা হয়েছে , আপনি কেবল নীচের মতগুলি করতে পারেন (যা সাধারণত প্রস্তাবিত উপায় বলে মনে হয়):

try:
    data = data.decode()
except (UnicodeDecodeError, AttributeError):
    pass

আপনি hasattrবর্ণনা হিসাবে আপনি ব্যবহার করতে পারেন , এবং সম্ভবত এটি ঠিক আছে। এটি অবশ্যই, ধরে নেওয়া হচ্ছে যে .decode()প্রদত্ত বস্তুর জন্য পদ্ধতিটি একটি স্ট্রিং প্রদান করে এবং এর কোনও বাজে পার্শ্ব প্রতিক্রিয়া নেই।

আমি ব্যক্তিগতভাবে ব্যতিক্রম বা hasattrপদ্ধতিটি সুপারিশ করি তবে আপনি যা ব্যবহার করেন তা আপনার উপর নির্ভর করে।

Str () ব্যবহার করুন

এই পদ্ধতির অসাধারণ, তবে এটি সম্ভব:

data = str(data, "utf-8")

বাফার প্রোটোকলের মতোই অন্যান্য এনকোডিংগুলিও অনুমোদিত .decode()। ত্রুটি পরিচালনা পরিচালনা নির্দিষ্ট করতে আপনি একটি তৃতীয় প্যারামিটারও পাস করতে পারেন।

একক প্রেরণ জেনেরিক ফাংশন (পাইথন 3.4+)

পাইথন ৩.৪ এবং তারপরের মধ্যে ফান্টটুলস.সেলিংডিসপ্যাচের মাধ্যমে সিঙ্গেল-প্রেরণ জেনেরিক ফাংশন নামে একটি নিফটি বৈশিষ্ট্য রয়েছে । এটি কিছুটা ভারবজ, তবে এটি আরও স্পষ্ট:

def func(data):
    # This is the generic implementation
    data = data.decode()
    ...

@func.register(str)
def _(data):
    # data will already be a string
    ...

আপনি যদি পছন্দ করেন তবে আপনি বিশেষ হ্যান্ডলারগুলি bytearrayএবং bytesঅবজেক্টগুলিও তৈরি করতে পারেন।

সাবধান : একক-প্রেরণ ফাংশন কেবল প্রথম যুক্তিতে কাজ করে! এটি একটি ইচ্ছাকৃত বৈশিষ্ট্য, পিইপি 433 দেখুন


একক-প্রেরণ জেনেরিকের উল্লেখের জন্য +1, যা আমি সরবরাহিত মানক লাইব্রেরিটিকে পুরোপুরি ভুলে গিয়েছি।
উ। উইলকক্স

যেহেতু স্ট্রিংকে আরআরএনটি কল করা কিছুই করে না এবং আমার কাছে সবচেয়ে স্পষ্ট মনে হয়েছিল, তাই আমি সে সাথে চলেছি।
উ। উইলকক্স

সামগ্রিকভাবে আমি চেষ্টাটি hasattrচেয়ে বেশি পছন্দ করি / ডিকোড ফাংশনটিতে দুর্ঘটনাক্রমে কিছু বাগ গিলে যাওয়া থেকে রোধ করা ছাড়া, তবে +1।
কেরডসন

39

তুমি ব্যবহার করতে পার:

isinstance(data, (bytes, bytearray))

বিভিন্ন বেস শ্রেণীর কারণে এখানে ব্যবহৃত হয়।

>>> bytes.__base__
<type 'basestring'>
>>> bytearray.__base__
<type 'object'>

যাচাই করা bytes

>>> by = bytes()
>>> isinstance(by, basestring)
True

যাহোক,

>>> buf = bytearray()
>>> isinstance(buf, basestring)
False

উপরের কোডগুলি পাইথন ২.7 এর অধীনে পরীক্ষা করা হয়

দুর্ভাগ্যক্রমে, অজগর 3.4 এর অধীনে, তারা একই ....

>>> bytes.__base__
<class 'object'>
>>> bytearray.__base__
<class 'object'>

4
ছয়টি স্ট্রিং_ টাইপগুলি 2/3 সামঞ্জস্যপূর্ণ হওয়া উচিত।
জোশুয়া ওলসন

পাইথন 2 তে এই ধরণের চেকিং কাজ করে না, যেখানে একটি সাধারণ ASCII স্ট্রিং <বাইটস> এর পরীক্ষায় পাস করে!
অ্যাপস্টোলোস

13
>>> content = b"hello"
>>> text = "hello"
>>> type(content)
<class 'bytes'>
>>> type(text)
<class 'str'>
>>> type(text) is str
True
>>> type(content) is bytes
True

দ্রষ্টব্য যে এটি পাইথন 2-তে একটি নির্ভরযোগ্য পরীক্ষা নয় , যেখানে স্ট্রিং অবজেক্টটি বাইট হিসাবেও পাস করে! যে, উপরের কোডের উপর ভিত্তি করে, type(text) is bytesসত্য হবে!
Apostolos

11

এই কোডটি সঠিক নয় যতক্ষণ না আপনি কিছু জানেন যা আমরা করি না:

if isinstance(data, bytes):
    data = data.decode()

আপনি এর এনকোডিং জানেন না (প্রদর্শিত হবে) data। আপনি ধরে নিচ্ছেন এটি ইউটিএফ -8 , তবে এটি খুব ভাল হতে পারে। যেহেতু আপনি এনকোডিং জানেন না, তাই আপনার পাঠ্য নেই । আপনার বাইট রয়েছে, যা সূর্যের নিচে কোনও অর্থ হতে পারে।

সুসংবাদটি হ'ল বাইটগুলির সর্বাধিক এলোমেলো ক্রমগুলি বৈধ ইউটিএফ -8 বৈধ নয়, সুতরাং যখন এই বিরতি ঘটে তখন এটি errors='strict'নিঃশব্দে ভুল কাজটি করার পরিবর্তে উচ্চস্বরে ( ডিফল্ট হয়) ভেঙে যায় । আরও ভাল খবরটি হ'ল যে সমস্ত র্যান্ডম সিকোয়েন্সগুলি বৈধ ইউটিএফ -8 হিসাবে দেখা যায় সেগুলি বেশিরভাগই বৈধ এএসসিআইআই, যা ( প্রায় ) প্রত্যেকেই যেভাবে যেভাবে পার্স করতে পারে তাতে সম্মত হয়।

খারাপ খবরটি হ'ল এটি ঠিক করার কোনও যুক্তিসঙ্গত উপায় নেই। এনকোডিং তথ্য সরবরাহের একটি মানক উপায় রয়েছে: strপরিবর্তে ব্যবহার করুন bytes। যদি কিছু তৃতীয় পক্ষের কোড আপনাকে কোনও প্রসঙ্গ বা তথ্য ছাড়াই কোনও জিনিস bytesবা bytearrayবস্তু হস্তান্তর করে তবে কেবলমাত্র সঠিক পদক্ষেপ ব্যর্থ হওয়া।


এখন ধরে নেওয়া, আপনি এনকোডিং জানেন কিনা, আপনি functools.singledispatchএখানে ব্যবহার করতে পারেন :

@functools.singledispatch
def foo(data, other_arguments, ...):
    raise TypeError('Unknown type: '+repr(type(data)))

@foo.register(str)
def _(data, other_arguments, ...):
    # data is a str

@foo.register(bytes)
@foo.register(bytearray)
def _(data, other_arguments, ...):
    data = data.decode('encoding')
    # explicit is better than implicit; don't leave the encoding out for UTF-8
    return foo(data, other_arguments, ...)

এটি পদ্ধতিতে কাজ করে না এবং dataএটি প্রথম যুক্তি হতে হবে। যদি এই বিধিনিষেধগুলি আপনার পক্ষে কাজ করে না, তবে পরিবর্তে অন্য যে কোনও একটি উত্তর ব্যবহার করুন।


আমি যে লাইব্রেরিতে লিখছি, এই নির্দিষ্ট পদ্ধতির জন্য, আমি অবশ্যই জানি যে আমি যে বাইটগুলি এবং / বা বাইটারি পাচ্ছি তা ইউটিএফ -8 এনকোডযুক্ত।
উ। উইলকক্স

4
@ অ্যান্ড্রুউইলকক্স: যথেষ্ট ভাল, তবে আমি ভবিষ্যতের গুগল ট্র্যাফিকের জন্য এই তথ্যটি রেখে দিচ্ছি।
কেভিন

4

এটি নির্ভর করে আপনি কী সমাধান করতে চান। আপনি যদি একই কোডটি চান যা উভয় কেসকে স্ট্রিংয়ে রূপান্তর করে, আপনি কেবল প্রকারটি bytesপ্রথমে রূপান্তর করতে পারেন এবং তারপরে ডিকোড করতে পারেন। এইভাবে, এটি এক-লাইনার:

#!python3

b1 = b'123456'
b2 = bytearray(b'123456')

print(type(b1))
print(type(b2))

s1 = bytes(b1).decode('utf-8')
s2 = bytes(b2).decode('utf-8')

print(s1)
print(s2)

এইভাবে, আপনার জন্য উত্তর হতে পারে:

data = bytes(data).decode()

যাইহোক, আমি ডিকোডে 'utf-8'স্পষ্টভাবে লিখতে পরামর্শ দিই , যদি আপনি কয়েকটি বাইট বাদ দেওয়া না করেন। কারণটি হ'ল পরের বার আপনি বা অন্য কেউ উত্স কোডটি পড়বেন, পরিস্থিতি আরও স্পষ্ট হবে।


3

এখানে দুটি প্রশ্ন রয়েছে এবং সেগুলির উত্তর আলাদা।

প্রথম প্রশ্ন, এই পোস্টের শিরোনাম, পাইথনের কোনও বস্তু বাইটের মতো বস্তু কিনা তা নির্ধারণের সঠিক উপায় কী? এই ধরনের বিল্ট ইন একটি নম্বর থাকে ( bytes, bytearray, array.array, memoryview, অন্যদের?) এবং সম্ভবত এছাড়াও ব্যবহারকারী-সংজ্ঞায়িত ধরনের। এগুলির জন্য যাচাই করার সবচেয়ে ভাল উপায় হ'ল এগুলির মধ্যে একটি তৈরি করার চেষ্টা করা memoryview:

>>> memoryview(b"foo")
<memory at 0x7f7c43a70888>
>>> memoryview(u"foo")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: memoryview: a bytes-like object is required, not 'str'

মূল পোস্টের মুখ্য অংশে, যদিও এটির শব্দের বদলে মনে হচ্ছে যে কোনও বস্তু ডিকোড () সমর্থন করে কিনা তা আমি কীভাবে পরীক্ষা করব? @ এলিজাবেথ-মায়ার্স এই প্রশ্নের উত্তরের উত্তর দুর্দান্ত। নোট করুন যে সমস্ত বাইটের মতো বস্তু ডিকোড () সমর্থন করে না।


4
নোট করুন যে আপনি যদি এটি করেন তবে আপনার অবশ্যই কল করতে হবে .release()বা প্রসঙ্গ পরিচালক ব্যবহার করতে হবে ।
o11c

আমি মনে করি সিপথনে অস্থায়ীটি memoryviewতাত্ক্ষণিকভাবে মুক্তি দেওয়া হবে এবং .release()তাকে স্পষ্টভাবে বলা হবে। তবে আমি একমত যে সমস্ত পাইথন বাস্তবায়ন রেফারেন্স-গণনা করা না হওয়ায় এটির উপর নির্ভর করা ভাল নয়।
জ্যাক ও'কনোর

0

পাইথন 2 এ পরীক্ষা if isinstance(data, bytes)বা অন্যান্য if type(data) == bytesকাজ করে না, যেখানে একটি সাধারণ ASCII স্ট্রিং পরীক্ষায় উত্তীর্ণ হয়! যেহেতু আমি পাইথন 2 এবং পাইথন 3 উভয়ই ব্যবহার করি, এটি থেকে উত্তরণের জন্য আমি নিম্নলিখিত চেকটি করি:

if str(type(data)).find("bytes") != -1: print("It's <bytes>")

এটি কিছুটা কুরুচিপূর্ণ, তবে এটি প্রশ্নটি জিজ্ঞাসা করে এমন কাজটি করে এবং এটি সর্বদা সহজ উপায়ে কাজ করে।


Python2 strবস্তু হয় bytes : যদিও str is bytes> - TruePython2 মধ্যে
snakecharmerb

স্পষ্টতই, তাই সনাক্তকরণ সমস্যা! :)
অ্যাপোস্টোলোস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.