Skip to content

Instantly share code, notes, and snippets.

@domodomodomo
Created September 9, 2018 07:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save domodomodomo/b5b477316298316e47d304568f7ed2d1 to your computer and use it in GitHub Desktop.
Save domodomodomo/b5b477316298316e47d304568f7ed2d1 to your computer and use it in GitHub Desktop.
"""Check the obj is immutable or not by adding new attribute or sequence.
USAGE:
isimmutable(var)
WARNING:
This code cannot precisely check immutability,
because Python has the mechanisms to cutomize attribute access,
such as property and descriptor.
> 3.3.2. Customizing attribute access
> The following methods can be defined to customize
> the meaning of attribute access
> (use of, assignment to, or deletion of x.name) for class instances.
> docs.python.org/3/reference/datamodel.html#customizing-attribute-access
"""
import string
import random
def usage():
# int
print(isimmutable(1)) # True
# str
print(isimmutable('Hello, world!')) # True
# user defined class
class C:
pass
print(isimmutable(C())) # False
# dict
print(isimmutable({'a': 1})) # False
# set
print(isimmutable({'a'})) # False
# list
print(isimmutable([])) # False
# tuple
print(isimmutable(())) # True
def isimmutable(obj):
#
# attribute
# obj[attr]
#
#
while True:
attr_name = random_str()
if not hasattr(obj, attr_name):
break
try:
setattr(obj, attr_name, None)
except (AttributeError, TypeError):
pass
else:
delattr(obj, attr_name)
return False
#
# sequence
# obj[key]
#
if not hasattr(obj, '__iter__'):
return True
# dict
while True:
key_name = random_str()
if key_name not in obj:
break
try:
obj[key_name] = None
except (AttributeError, TypeError):
pass
else:
del obj[key_name]
return False
# set
while True:
element = random_str()
if element not in obj:
break
try:
# to avoid overriding add method.
# x obj.set(element)
set.add(obj, element)
except (AttributeError, TypeError):
pass
else:
set.remove(obj, element)
return False
# list
try:
# to avoid overriding append method.
# x obj.append(element)
list.append(obj, None)
except (AttributeError, TypeError):
pass
else:
list.pop(obj)
return False
return True
def random_str():
N = 5
return ''.join([random.choice(string.ascii_letters) for i in range(N)])
if __name__ == '__main__':
usage()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment