5

I want

class MyClass(object):
    _my_unique = ????      # if this were lisp, I would have written (cons nil nil) here

    def myFunc (self, arg):
        assert arg != _my_unique    # this must never fail
        ...

What do use instead of ??? to ensure that the assert never fails?

(With Lisp, I could create _my_unique with (cons nil nil) and used eq in assert).

PS. Use case: I will put _my_unique in a dict, so I want it to be equal to itself, but I do not want it to be equal (in the dict collision sense) to anything passed in from the outside.

sds
  • 58,617
  • 29
  • 161
  • 278
  • Do you want to set an attribute of your object? – tjati Mar 25 '14 at 18:03
  • I think there must be some extra condition you haven't specified, otherwise anything which is never equal to itself -- `float(nan)`, for example -- would suffice. – DSM Mar 25 '14 at 18:05
  • I'm confused as to the use case. Why would you include an assert that can NEVER FAIL? Wouldn't that be a literally pointless line of code? Just remove the `assert` and it won't fail, promise! :) – Adam Smith Mar 25 '14 at 18:08
  • @AdamSmith: most people only put in asserts that "should never fail". After all, if you expect it to fail then you can write code to handle the failure. The assert will let you know if it does fail, before code that depends on the value runs. – Bryan Oakley Mar 25 '14 at 19:45
  • @BryanOakley Right but the way the question is phrased makes it sound like he wants an option that will never fail because the laws of the universe guarantee it, like `assert 1 < 2`. If that assert fails, you're right that I'd want to know sooner rather than later! :) – Adam Smith Mar 25 '14 at 19:48

4 Answers4

6

You can use object(), but this won't make the assert "never fail". It will still fail if you call myFunc and pass MyClass.my_unique as the object. Also, if you want to test whether it's the same object, use arg is not my_unique rather than !=.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • how do I ensure that the outside world cannot see `MyClass.my_unique`? – sds Mar 25 '14 at 19:18
  • my test in `assert` must be the same test which `dict` uses, see *PS* – sds Mar 25 '14 at 19:19
  • 2
    @sds you can not. You can politely ask not to by putting a underscore in front but you can not make anything private. – joojaa Mar 25 '14 at 19:36
  • @sds this is [python philosophy](https://python-guide-chinese.readthedocs.io/zh_CN/latest/writing/style.html#we-are-all-consenting-adults): it works out for what python is, namely NOT a security proven language. And that's perfectly fine. – Mayou36 Oct 20 '18 at 14:15
2

You can use object().

Return a new featureless object. object is a base for all new style classes. It has the methods that are common to all instances of new style classes.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
0

If what you're asking is "how do I make _my_unique unique for each instance of MyClass", you could simply create a new, empty object in the constructor.

For example:

>>> class MyClass(object):
...     def __init__(self):
...         self._my_unique = object()
... 
>>> foo=MyClass()
>>> bar=MyClass()
>>> foo._my_unique
<object object at 0x100ce70c0>
>>> bar._my_unique
<object object at 0x100ce7090>

If you want to hide _my_unique, give it two underscores. This way, nobody can accidentally get at the value. It's not impossible, but they would need to work a little harder to get at the value. This is called name mangling, and you can read more about it here: http://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

>>> class MyClass(object):
...     def __init__(self):
...         self.__my_unique = object()
... 
>>> foo=MyClass()
>>> foo.__my_unique
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute '__my_unique'
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
-2

This is a mildly confusing question, as it seems to mix a bunch of concepts without purpose. For one thing, most any object in Python is unique, but there may be multiple ways to reach them. The operator to check identities is not != (inequality) but is not. Unlike Java, Python does not require you to put things in a class, and does not implicitly look in self (which they know as implicit this). cons from Lisp is used to construct pairs which frequently form singly linked lists, a structure that's unusual in Python because we use dynamic reference arrays known as lists. Lists are mutable, and thus constructing one using list() or [] will produce a unique object.

So, while it is rather pointless, one way to write a function producing functions that perform the useless assert might be:

def createfunc():
  mylist=[]
  def subfunc(x):
    assert x is not mylist
  return subfunc

Each call to createfunc() returns a new function with its own mylist. However, the object being unique doesn't make it impossible to reach:

f=createfunc()
f(f.func_closure[0].cell_contents)   # raises AssertionError

Regarding the PS, to be relevant to dict collissions, your object must also be hashable, which makes object() a better choice than list() for the unique object.

Yann Vernier
  • 15,414
  • 2
  • 28
  • 26