os.mkdir(MyClass()),TypeError:强制为Unicode,魔术方法



我想写一个类,它的实例应该可以用作os.mkdir()的参数。有没有一个神奇的方法,我可以添加到我的类中,这样就可以工作了?以下使用__unicode__()的实现:

main.py:

import os
class MyClass(object):
    def __init__(self, string):
        self.__string = string
    def __unicode__(self):
        return unicode(self.__string)
obj = MyClass("/tmp/dir")
print unicode(obj)
os.mkdir(obj)

导致以下错误:

/tmp/dir
Traceback (most recent call last):
  File "main.py", line 11, in <module>
    os.mkdir(obj)
TypeError: coercing to Unicode: need string or buffer, MyClass found

我想在需要str或unicode的上下文中使用MyClass的实例。例如,为了使"abc"+MyClass("def")工作,我可以在MyClass中实现__radd__()魔术方法。

编辑:解释我意图的新代码示例(上面的MyClass对应下面的StringRef):

import os
class StringRef(object):
    def __init__(self, string):
        self.__string = string
    def set_value(self, value):
        self.__string = value
    def __str__(self):
        return str(self.__string)
    def __repr__(self):
        return repr(self.__string)
    def __unicode__(self):
        return unicode(self.__string)
    def __add__(self, other):
        return self.__string + other
    def __radd__(self, other):
        return other + self.__string
class SomeClass(object):
    def __init__(self, directory):
        self.__directory = directory
    def use_dir1(self):
        print "directory: %s" % self.__directory
    def use_dir2(self):
        print "subdirectory:", self.__directory + "/subdir"
    def use_dir3(self):
        os.mkdir(self.__directory)
        os.rmdir(self.__directory)
print "* old *"
directory = "/tmp/dir1"
obj = SomeClass(directory)  # more objects can be created like this
obj.use_dir1()
directory = "/tmp/dir2"  # has no effect on the created objects
obj.use_dir1()
directory = "/tmp/dir1"
obj = SomeClass(directory)
obj.use_dir2()
directory = "/tmp/dir2"
obj.use_dir2()
directory = "/tmp/dir1"
obj = SomeClass(directory)
obj.use_dir3()
directory = "/tmp/dir2"
obj.use_dir3()

print "* new *"
directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)  # more objects can be created like this
obj.use_dir1()
directory.set_value("/tmp/dir2")  # has effect on all created objects
obj.use_dir1()
directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)
obj.use_dir2()
directory.set_value("/tmp/dir2")
obj.use_dir2()
directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)
obj.use_dir3()
directory.set_value("/tmp/dir2")
obj.use_dir3()

输出:

* old *
directory: /tmp/dir1
directory: /tmp/dir1
subdirectory: /tmp/dir1/subdir
subdirectory: /tmp/dir1/subdir
* new *
directory: /tmp/dir1
directory: /tmp/dir2
subdirectory: /tmp/dir1/subdir
subdirectory: /tmp/dir2/subdir
Traceback (most recent call last):
  File "main.py", line 65, in <module>
    obj.use_dir3()
  File "main.py", line 27, in use_dir3
    os.mkdir(self.__directory)
TypeError: coercing to Unicode: need string or buffer, StringRef found

第二次编辑:StringRef(unicode)避免TypeError,但不创建/tmp/dir2:

import os
class StringRef(unicode):
    def __init__(self, string):
        self.__string = string
    def set_value(self, value):
        self.__string = value
    def __str__(self):
        return str(self.__string)
    def __repr__(self):
        return repr(self.__string)
    def __unicode__(self):
        return unicode(self.__string)
    def __add__(self, other):
        return self.__string + other
    def __radd__(self, other):
        return other + self.__string
class SomeClass(object):
    def __init__(self, directory):
        self.__directory = directory
    def use_directory(self):
        os.mkdir(self.__directory)
directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)
obj.use_directory()
directory.set_value("/tmp/dir2")
obj.use_directory()

输出:

Traceback (most recent call last):
  File "main.py", line 29, in <module>
    obj.use_directory()
  File "main.py", line 23, in use_directory
    os.mkdir(self.__directory)
OSError: [Errno 17] File exists: '/tmp/dir1'

因为你想让这个小狗表现得像一个字符串,对不起,unicode,只需要从unicode(内置的unicode类)而不是对象中派生它。

#as per Padraic's remark that string <> unicode
#class MyClass(str):
class MyClass(unicode):
    pass

obj = MyClass("/tmp/dir")
print unicode(obj)
os.mkdir(obj)
#surprised that assigning a new attribute here works
#I woulda thought MyClass
#would be using __slots__.  oh well, better for you.
obj.foo = 1
print "obj.foo:%s" % (obj.foo)

这个怎么样?

(文件为testmkdir2.py)导入os

class MonkeyPatch(object):
    def __init__(self):
        self.func = os.mkdir
    def __call__(self, sortastring):
        if hasattr(sortastring,"value"):
            self.func(sortastring.value)
        else:
            self.func(sortastring)
mk = MonkeyPatch()
os.mkdir = mk
os.mkdir("/tmp/foo")
class Dummy(object):
    pass
sneakystring = Dummy()
sneakystring.value = "/tmp/foo2"
os.mkdir(sneakystring)
sneakystring.value = "/tmp/foo3"
os.mkdir(sneakystring)

$ls-l/tmp/|grep-foo$

$python testmkdir2.py

$ls/tmp/|grep-foo

drwxr-xr-x 2 jluc车轮68 2月26日20:19 foo

drwxr-xr-x 2 jluc车轮68 2月26日20:19 foo2

drwxr-xr-x 2 jluc车轮68 2月26日20:19 foo3

我认为,让一个字符串引用在传递给各种对象后可以更改其值的最干净的方法是使用一个包含字符串值的对象,并将字符串引用的执行上下文更改为不同于它的样子,如果使用字符串而不是字符串引用:新的执行上下文将是os.mkdir(s.value)、"string"+s.value、s.value+"string"而不是os.mkddir(s)、"字符串"+s、s+"字符串"):

class StringRef(object):
    def __init__(self, value):
        self.__value = value
    @property
    def value(self):
        return self.__value
    @value.setter
    def value(self, val):
        self.__value = val
class SomeClass(object):
    def __init__(self, s):
        self.__s = s
    def meth(self):
        print self.__s.value  # new execution context here
directory = StringRef("/tmp")
obj = SomeClass(directory)
obj.meth()
directory.value = "/var"
obj.meth()

最新更新